D6: AI Director polish + parity hardening
- pf2e parity: a unit test confirms the director carries the system through (systemConstraint + prompt say Pathfinder 2e, no cross-system leak) and still produces a grounded deterministic turn. (Degree-of-success/conditions already branch per system via the shared kernel.) - UX: the transcript pane is now a bounded, scrollable region (max-h-[60vh]) so long sessions don't blow the page layout; it still auto-scrolls to the newest line. - e2e: e2e/director.spec.ts exercises the full flow against a real browser — DM narrates a grounded scene with no API key (deterministic badge, empty-state clears, Continue appears), and the player persona seats a party character and takes a turn. 396 unit tests + 2 director e2e green; lint clean; build OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.evaluate(async () => {
|
||||
indexedDB.deleteDatabase('ttrpg-manager');
|
||||
localStorage.clear();
|
||||
});
|
||||
await page.reload();
|
||||
// Load the sample campaign (gives us a party + an active encounter).
|
||||
await page.getByLabel('Settings').click();
|
||||
await page.getByRole('button', { name: 'Load sample campaign' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Sample: Lost Mine' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('AI Director narrates a grounded scene with no API key (deterministic)', async ({ page }) => {
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'AI Director' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'AI Director' })).toBeVisible();
|
||||
await expect(page.getByText(/deterministic mode/)).toBeVisible();
|
||||
|
||||
// Empty until we start.
|
||||
await expect(page.getByText('The story begins when you start the scene.')).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Begin the scene' }).click();
|
||||
|
||||
// A narration entry appears; the empty-state is gone; source badge shows deterministic.
|
||||
await expect(page.getByText('The story begins when you start the scene.')).toBeHidden();
|
||||
await expect(page.getByText('deterministic', { exact: true })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Continue' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('the director can play a chosen party character (player persona)', async ({ page }) => {
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'AI Director' }).click();
|
||||
|
||||
await page.getByRole('button', { name: 'Player', exact: true }).click();
|
||||
// Subtitle reflects the mode.
|
||||
await expect(page.getByText(/· Player/)).toBeVisible();
|
||||
|
||||
// Seat the AI on the first party character.
|
||||
await page.getByLabel('Character the AI plays').selectOption({ index: 1 });
|
||||
|
||||
await page.getByRole('button', { name: /Take the first action|Take turn/ }).click();
|
||||
await expect(page.getByText('deterministic', { exact: true })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user