148 lines
5.9 KiB
TypeScript
148 lines
5.9 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import {
|
|
seedCampaign,
|
|
seedArc,
|
|
seedChapter,
|
|
seedScene,
|
|
deleteCampaign,
|
|
getSceneById,
|
|
type SeededCampaign,
|
|
type SeededArc,
|
|
type SeededChapter,
|
|
type SeededScene,
|
|
} from '../../fixtures/api';
|
|
|
|
test.describe('Scene edit', () => {
|
|
let campaign: SeededCampaign;
|
|
let arc: SeededArc;
|
|
let chapter: SeededChapter;
|
|
let scene: SeededScene;
|
|
|
|
test.beforeEach(async ({ request }) => {
|
|
campaign = await seedCampaign(request);
|
|
arc = await seedArc(request, { campaignId: campaign.id });
|
|
chapter = await seedChapter(request, { arcId: arc.id });
|
|
scene = await seedScene(request, { chapterId: chapter.id });
|
|
});
|
|
|
|
test.afterEach(async ({ request }) => {
|
|
if (campaign?.id) await deleteCampaign(request, campaign.id);
|
|
});
|
|
|
|
test('edits all text fields across sections and persists them to API', async ({ page, request }) => {
|
|
const newName = `${scene.name} renamed`;
|
|
const values = {
|
|
description: "Les PJ arrivent au village à la nuit tombée.",
|
|
location: "Taverne du Dragon d'Or",
|
|
timing: 'Soir, pleine lune',
|
|
atmosphere: 'Silence pesant, regards fuyants des villageois.',
|
|
playerNarration: 'Vous poussez la porte de la taverne…',
|
|
gmSecretNotes: 'Le tavernier est complice des bandits.',
|
|
choicesConsequences: 'Accepter = piégés à l\'étage. Refuser = filature.',
|
|
combatDifficulty: 'Moyenne, 4 bandits niveau 3',
|
|
enemies: 'Bandit chef (feuille jointe) + 3 sbires.',
|
|
};
|
|
|
|
await page.goto(
|
|
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/${scene.id}/edit`,
|
|
);
|
|
|
|
await expect(page.getByLabel(/Titre de la scène/i)).toHaveValue(scene.name);
|
|
|
|
await page.getByLabel(/Titre de la scène/i).fill(newName);
|
|
await page.getByLabel(/Description courte/i).fill(values.description);
|
|
await page.getByLabel(/^Lieu$/i).fill(values.location);
|
|
await page.getByLabel(/^Moment$/i).fill(values.timing);
|
|
await page.getByLabel(/Ambiance et atmosphère/i).fill(values.atmosphere);
|
|
|
|
// Les sections suivantes sont fermées par défaut : on les ouvre avant de taper.
|
|
// Un clic sur le header de la section toggle son état.
|
|
await page.locator('app-expandable-section', { hasText: 'Narration pour les joueurs' }).click();
|
|
await page.getByPlaceholder(/Le texte que vous lirez aux joueurs/i).fill(values.playerNarration);
|
|
|
|
await page.locator('app-expandable-section', { hasText: 'Notes et secrets du MJ' }).click();
|
|
await page
|
|
.getByPlaceholder(/Informations cachées, indices, éléments secrets/i)
|
|
.fill(values.gmSecretNotes);
|
|
|
|
await page.locator('app-expandable-section', { hasText: 'Choix et conséquences' }).click();
|
|
await page
|
|
.getByPlaceholder(/Décrivez les différentes options/i)
|
|
.fill(values.choicesConsequences);
|
|
|
|
await page.locator('app-expandable-section', { hasText: 'Combat ou rencontre' }).click();
|
|
await page.getByLabel(/Difficulté estimée/i).fill(values.combatDifficulty);
|
|
await page.getByLabel(/Ennemis et créatures/i).fill(values.enemies);
|
|
|
|
await page.getByRole('button', { name: /^Sauvegarder$/i }).click();
|
|
|
|
await expect(page).toHaveURL(
|
|
new RegExp(
|
|
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/${scene.id}$`,
|
|
),
|
|
);
|
|
|
|
const persisted = await getSceneById(request, scene.id);
|
|
expect(persisted.name).toBe(newName);
|
|
expect(persisted.description).toBe(values.description);
|
|
expect(persisted.location).toBe(values.location);
|
|
expect(persisted.timing).toBe(values.timing);
|
|
expect(persisted.atmosphere).toBe(values.atmosphere);
|
|
expect(persisted.playerNarration).toBe(values.playerNarration);
|
|
expect(persisted.gmSecretNotes).toBe(values.gmSecretNotes);
|
|
expect(persisted.choicesConsequences).toBe(values.choicesConsequences);
|
|
expect(persisted.combatDifficulty).toBe(values.combatDifficulty);
|
|
expect(persisted.enemies).toBe(values.enemies);
|
|
});
|
|
|
|
test('adds a narrative branch to a sibling scene and persists it', async ({ page, request }) => {
|
|
const sibling = await seedScene(request, {
|
|
chapterId: chapter.id,
|
|
name: 'Scène alternative',
|
|
order: 2,
|
|
});
|
|
|
|
await page.goto(
|
|
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/${scene.id}/edit`,
|
|
);
|
|
|
|
const branchesSection = page.locator('app-expandable-section', { hasText: 'Branches narratives' });
|
|
await branchesSection.click();
|
|
|
|
await branchesSection.getByRole('button', { name: /Ajouter une branche/i }).click();
|
|
|
|
const branchItem = branchesSection.locator('.branch-item').first();
|
|
await branchItem.getByPlaceholder(/Ex: Si les joueurs attaquent/i).fill('Si les PJ fuient');
|
|
await branchItem.locator('select').selectOption({ label: sibling.name });
|
|
await branchItem.getByPlaceholder(/Jet de Persuasion/i).fill('Sur échec initiative');
|
|
|
|
await page.getByRole('button', { name: /^Sauvegarder$/i }).click();
|
|
|
|
await expect(page).toHaveURL(
|
|
new RegExp(
|
|
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/${scene.id}$`,
|
|
),
|
|
);
|
|
|
|
const persisted = await getSceneById(request, scene.id);
|
|
expect(persisted.branches).toHaveLength(1);
|
|
expect(persisted.branches![0].label).toBe('Si les PJ fuient');
|
|
expect(persisted.branches![0].targetSceneId).toBe(sibling.id);
|
|
expect(persisted.branches![0].condition).toBe('Sur échec initiative');
|
|
});
|
|
|
|
test('save button is disabled when name is empty', async ({ page }) => {
|
|
await page.goto(
|
|
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/${scene.id}/edit`,
|
|
);
|
|
const nameField = page.getByLabel(/Titre de la scène/i);
|
|
const saveBtn = page.getByRole('button', { name: /^Sauvegarder$/i });
|
|
|
|
await expect(saveBtn).toBeEnabled();
|
|
await nameField.fill('');
|
|
await expect(saveBtn).toBeDisabled();
|
|
await nameField.fill('OK');
|
|
await expect(saveBtn).toBeEnabled();
|
|
});
|
|
});
|