import { APIRequestContext, expect } from '@playwright/test'; export interface SeededLore { id: string; name: string; rootFolderId: string; rootFolderName: string; } /** * Seed un Lore + un dossier racine via l'API backend. * Les noms sont uniques (timestamp + random) pour éviter les collisions en parallèle. */ export async function seedLoreWithFolder(request: APIRequestContext): Promise { const suffix = `${Date.now()}-${Math.floor(Math.random() * 10000)}`; const loreName = `E2E Lore ${suffix}`; const folderName = `E2E Folder ${suffix}`; const loreRes = await request.post('/api/lores', { data: { name: loreName, description: 'Seeded by Playwright' }, }); expect(loreRes.ok(), `POST /api/lores -> ${loreRes.status()}`).toBeTruthy(); const lore = await loreRes.json(); const folderRes = await request.post('/api/lore-nodes', { data: { loreId: lore.id, name: folderName, icon: 'folder', description: '' }, }); expect(folderRes.ok(), `POST /api/lore-nodes -> ${folderRes.status()}`).toBeTruthy(); const folder = await folderRes.json(); return { id: lore.id, name: loreName, rootFolderId: folder.id, rootFolderName: folderName }; } /** Cleanup best-effort — n'échoue pas si déjà supprimé. */ export async function deleteLore(request: APIRequestContext, loreId: string): Promise { await request.delete(`/api/lores/${loreId}`).catch(() => undefined); } export async function getLoreById( request: APIRequestContext, loreId: string, ): Promise<{ id: string; name: string; description: string }> { const res = await request.get(`/api/lores/${loreId}`); expect(res.ok(), `GET /api/lores/${loreId} -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getArcsForCampaign( request: APIRequestContext, campaignId: string, ): Promise> { const res = await request.get(`/api/arcs?campaignId=${campaignId}`); expect(res.ok(), `GET /api/arcs -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getChaptersForArc( request: APIRequestContext, arcId: string, ): Promise> { const res = await request.get(`/api/chapters?arcId=${arcId}`); expect(res.ok(), `GET /api/chapters -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getScenesForChapter( request: APIRequestContext, chapterId: string, ): Promise> { const res = await request.get(`/api/scenes?chapterId=${chapterId}`); expect(res.ok(), `GET /api/scenes -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getTemplatesForLore( request: APIRequestContext, loreId: string, ): Promise> { const res = await request.get(`/api/templates?loreId=${loreId}`); expect(res.ok(), `GET /api/templates -> ${res.status()}`).toBeTruthy(); return res.json(); } export interface SeededTemplate { id: string; name: string; } export async function seedTemplate( request: APIRequestContext, opts: { loreId: string; defaultNodeId: string; name?: string; fieldNames?: string[] }, ): Promise { const templateName = opts.name ?? `E2E Template ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const fields = (opts.fieldNames ?? ['Nom', 'Description']).map((name) => ({ name, type: 'TEXT' })); const res = await request.post('/api/templates', { data: { loreId: opts.loreId, name: templateName, description: 'Seeded by Playwright', defaultNodeId: opts.defaultNodeId, fields, }, }); expect(res.ok(), `POST /api/templates -> ${res.status()}`).toBeTruthy(); const tpl = await res.json(); return { id: tpl.id, name: templateName }; } export async function deleteCampaign(request: APIRequestContext, campaignId: string): Promise { await request.delete(`/api/campaigns/${campaignId}`).catch(() => undefined); } export interface SeededCampaign { id: string; name: string; } export async function seedCampaign( request: APIRequestContext, opts: { name?: string; loreId?: string | null; playerCount?: number } = {}, ): Promise { const name = opts.name ?? `E2E Campaign ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/campaigns', { data: { name, description: 'Seeded by Playwright', playerCount: opts.playerCount ?? 4, loreId: opts.loreId ?? null, gameSystemId: null, }, }); expect(res.ok(), `POST /api/campaigns -> ${res.status()}`).toBeTruthy(); const c = await res.json(); return { id: c.id, name }; } export interface SeededArc { id: string; name: string; } export async function seedArc( request: APIRequestContext, opts: { campaignId: string; name?: string; order?: number }, ): Promise { const name = opts.name ?? `E2E Arc ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/arcs', { data: { campaignId: opts.campaignId, name, description: '', order: opts.order ?? 1, }, }); expect(res.ok(), `POST /api/arcs -> ${res.status()}`).toBeTruthy(); const a = await res.json(); return { id: a.id, name }; } export interface SeededChapter { id: string; name: string; } export async function seedChapter( request: APIRequestContext, opts: { arcId: string; name?: string; order?: number }, ): Promise { const name = opts.name ?? `E2E Chapter ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/chapters', { data: { arcId: opts.arcId, name, description: '', order: opts.order ?? 1 }, }); expect(res.ok(), `POST /api/chapters -> ${res.status()}`).toBeTruthy(); const c = await res.json(); return { id: c.id, name }; } export async function getChapterById( request: APIRequestContext, chapterId: string, ): Promise<{ id: string; name: string; description?: string; gmNotes?: string | null; playerObjectives?: string | null; narrativeStakes?: string | null; }> { const res = await request.get(`/api/chapters/${chapterId}`); expect(res.ok(), `GET /api/chapters/${chapterId} -> ${res.status()}`).toBeTruthy(); return res.json(); } export interface SeededScene { id: string; name: string; } export async function seedScene( request: APIRequestContext, opts: { chapterId: string; name?: string; order?: number }, ): Promise { const name = opts.name ?? `E2E Scene ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/scenes', { data: { chapterId: opts.chapterId, name, description: '', order: opts.order ?? 1 }, }); expect(res.ok(), `POST /api/scenes -> ${res.status()}`).toBeTruthy(); const s = await res.json(); return { id: s.id, name }; } export async function getSceneById( request: APIRequestContext, sceneId: string, ): Promise<{ id: string; name: string; description?: string; location?: string | null; timing?: string | null; atmosphere?: string | null; playerNarration?: string | null; gmSecretNotes?: string | null; choicesConsequences?: string | null; combatDifficulty?: string | null; enemies?: string | null; branches?: Array<{ label: string; targetSceneId: string; condition?: string }>; }> { const res = await request.get(`/api/scenes/${sceneId}`); expect(res.ok(), `GET /api/scenes/${sceneId} -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getArcById( request: APIRequestContext, arcId: string, ): Promise<{ id: string; name: string; description?: string; themes?: string | null; stakes?: string | null; gmNotes?: string | null; rewards?: string | null; resolution?: string | null; }> { const res = await request.get(`/api/arcs/${arcId}`); expect(res.ok(), `GET /api/arcs/${arcId} -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getCampaigns( request: APIRequestContext, ): Promise> { const res = await request.get('/api/campaigns'); expect(res.ok(), `GET /api/campaigns -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getPagesForLore( request: APIRequestContext, loreId: string, ): Promise> { const res = await request.get(`/api/pages?loreId=${loreId}`); expect(res.ok(), `GET /api/pages -> ${res.status()}`).toBeTruthy(); return res.json(); } export interface SeededPage { id: string; title: string; } export async function seedPage( request: APIRequestContext, opts: { loreId: string; nodeId: string; templateId: string; title?: string }, ): Promise { const title = opts.title ?? `E2E Page ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/pages', { data: { loreId: opts.loreId, nodeId: opts.nodeId, templateId: opts.templateId, title }, }); expect(res.ok(), `POST /api/pages -> ${res.status()}`).toBeTruthy(); const page = await res.json(); return { id: page.id, title }; } export async function getPageById( request: APIRequestContext, pageId: string, ): Promise<{ id: string; title: string; nodeId: string; values?: Record; tags?: string[]; notes?: string; }> { const res = await request.get(`/api/pages/${pageId}`); expect(res.ok(), `GET /api/pages/${pageId} -> ${res.status()}`).toBeTruthy(); return res.json(); } export interface SeededNpc { id: string; name: string; } export async function seedNpc( request: APIRequestContext, opts: { campaignId: string; name?: string; markdownContent?: string | null }, ): Promise { const name = opts.name ?? `E2E NPC ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/npcs', { data: { campaignId: opts.campaignId, name, markdownContent: opts.markdownContent ?? null, }, }); expect(res.ok(), `POST /api/npcs -> ${res.status()}`).toBeTruthy(); const n = await res.json(); return { id: n.id, name }; } export async function getNpcById( request: APIRequestContext, npcId: string, ): Promise<{ id: string; name: string; markdownContent: string | null; campaignId: string; order: number }> { const res = await request.get(`/api/npcs/${npcId}`); expect(res.ok(), `GET /api/npcs/${npcId} -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getNpcsByCampaign( request: APIRequestContext, campaignId: string, ): Promise> { const res = await request.get(`/api/npcs/campaign/${campaignId}`); expect(res.ok(), `GET /api/npcs/campaign -> ${res.status()}`).toBeTruthy(); return res.json(); } export async function getTemplateById( request: APIRequestContext, templateId: string, ): Promise<{ id: string; name: string; description?: string; defaultNodeId?: string | null; fields: Array<{ name: string; type: string }>; }> { const res = await request.get(`/api/templates/${templateId}`); expect(res.ok(), `GET /api/templates/${templateId} -> ${res.status()}`).toBeTruthy(); return res.json(); } // ─────────────── GameSystem ─────────────── export interface SeededGameSystem { id: string; name: string; } export async function seedGameSystem( request: APIRequestContext, opts: { name?: string; description?: string; author?: string; rulesMarkdown?: string } = {}, ): Promise { const name = opts.name ?? `E2E GameSystem ${Date.now()}-${Math.floor(Math.random() * 10000)}`; const res = await request.post('/api/game-systems', { data: { name, description: opts.description ?? null, author: opts.author ?? null, rulesMarkdown: opts.rulesMarkdown ?? null, characterTemplate: [], npcTemplate: [], isPublic: false, }, }); expect(res.ok(), `POST /api/game-systems -> ${res.status()}`).toBeTruthy(); const gs = await res.json(); return { id: gs.id, name }; } export async function deleteGameSystem( request: APIRequestContext, id: string, ): Promise { // Best-effort : ignore 404 si déjà supprimé par le test (ex: delete spec). await request.delete(`/api/game-systems/${id}`); } export async function getGameSystemById( request: APIRequestContext, id: string, ): Promise<{ id: string; name: string; description: string | null; author: string | null; rulesMarkdown: string | null; isPublic: boolean; }> { const res = await request.get(`/api/game-systems/${id}`); expect(res.ok(), `GET /api/game-systems/${id} -> ${res.status()}`).toBeTruthy(); return res.json(); }