diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts index 2a0e819..a103a25 100644 --- a/e2e/smoke.spec.ts +++ b/e2e/smoke.spec.ts @@ -7,7 +7,8 @@ interface PlanetDto { id: number; name: string; type: string; hazard: boolean; e interface InventoryItemDto { kind: string; name: string; qty: number } interface SystemState { systemId: number; systemName: string; planets: PlanetDto[]; inventory: InventoryItemDto[]; turn: number } interface FoundItem { kind: string; name: string; qty: number } -interface ExploreResult extends SystemState { outcome: FoundItem[] } +interface ExploreResult extends SystemState { outcome: FoundItem[]; crewFound: unknown } +interface CrewDto { id: number; name: string; role: string; traitGood: string; traitBad: string; origin: string } test('landing page loads with the SpaceWanderer title', async ({ page }) => { await page.goto('/'); @@ -119,6 +120,25 @@ test('exploration yields finds that accumulate in the inventory', async ({ page } }); +test('CREW tab renders real roster cards, each showing both traits and an origin', async ({ page }) => { + const roster = (await (await page.request.get('/api/crew')).json()) as CrewDto[]; + expect(roster.length).toBeGreaterThanOrEqual(2); // starting crew is always seeded + + await page.goto('/'); + await page.getByRole('tab', { name: 'CREW' }).click(); + + for (const member of roster) { + const heading = page.getByRole('heading', { name: member.name }); + await expect(heading).toBeVisible(); + // The card is the third div ancestor of the title (flex row → CardHeader → Card). + const card = heading.locator('xpath=ancestor::div[3]'); + await expect(card.getByText(member.role)).toBeVisible(); + await expect(card.getByText(member.traitGood)).toBeVisible(); + await expect(card.getByText(member.traitBad)).toBeVisible(); + await expect(card.getByText(`ORIGIN // ${member.origin.toUpperCase()}`)).toBeVisible(); + } +}); + test('GET /api/version reports the app version as JSON', async ({ page }) => { const res = await page.request.get('/api/version'); expect(res.status()).toBe(200); diff --git a/e2e/state.spec.ts b/e2e/state.spec.ts index 4958300..f0d2a75 100644 --- a/e2e/state.spec.ts +++ b/e2e/state.spec.ts @@ -13,6 +13,7 @@ interface WorldSystemDto { id: number; name: string; x: number; y: number; disco interface WorldState { systems: WorldSystemDto[]; edges: [number, number][]; turn: number } interface PlanetDto { id: number; name: string; type: string; hazard: boolean; explored: boolean; parent: number | null } interface SystemState { systemId: number; systemName: string; planets: PlanetDto[]; inventory: { kind: string; name: string; qty: number }[]; turn: number } +interface CrewDto { id: number; name: string; role: string; traitGood: string; traitBad: string; origin: string } test('app survives a container restart (stack + volume persistence)', async ({ page }) => { test.setTimeout(180_000); @@ -47,6 +48,10 @@ test('app survives a container restart (stack + volume persistence)', async ({ p expect(exploreRes.status()).toBe(200); const sysExplored = (await exploreRes.json()) as SystemState; + // Crew baseline: the roster (starting crew + any finds so far) must survive too. + const crewBefore = (await (await page.request.get('/api/crew')).json()) as CrewDto[]; + expect(crewBefore.length).toBeGreaterThanOrEqual(2); // starting crew is always seeded + // Restart the app container mid-run — the named DB volume must survive it. execSync(`docker compose ${composeArgs} restart space-wanderer`, { cwd: repoRoot, stdio: 'pipe' }); @@ -77,6 +82,10 @@ test('app survives a container restart (stack + volume persistence)', async ({ p expect(sysAfter.turn).toBe(sysExplored.turn); expect(sysAfter.planets.find((p) => p.id === targetPlanet.id)?.explored).toBe(true); + // Crew roster survived too: same members, traits and origins (no re-seed on restart). + const crewAfter = (await (await page.request.get('/api/crew')).json()) as CrewDto[]; + expect(crewAfter).toEqual(crewBefore); + // The page itself serves again with the landing title. await page.goto('/'); await expect(page.getByRole('heading', { name: 'SpaceWanderer' })).toBeVisible();