test(02-06): playwright e2e assertions for G1+G2 — phase-2 gap closure complete

Threads 3 new assertions into the existing PIPE-07 spec to verify the
G1 + G2 gap fixes hold end-to-end in a real Chromium browser:

- Assertion A (G1, after initial nav): document.body computed
  background-color is rgb(26, 26, 26) — proves src/index.css bundled
  cleanly into the entry chunk and applies before React mounts.
- Assertion B (G2, after Begin click): the FirstRunHint element
  (data-testid="first-run-hint") is visible with non-empty externalized
  text content from ui-strings.yaml.
- Assertion C (G2, after first plant): the FirstRunHint is gone —
  proves the component's tiles subscription dismisses on the first
  plant !== null transition.

The existing 16-step assertion chain continues to pass unchanged. Test
runtime grew from 1.6s → 1.7s (3 cheap evaluations + 1 visibility +
1 negation). All 4 first-impression UX gaps are now structurally closed.

npm run ci exits 0 (333/333 vitest green; ~21 new tests across G1+G2+G3+G4).
npm run test:e2e exits 0 (Playwright PIPE-07 + 3 new gap-closure assertions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 12:17:55 -04:00
parent 88adc4f623
commit 47b5b8d6b0
+20
View File
@@ -70,6 +70,13 @@ test.describe('PIPE-07 — Season 1 full loop', () => {
// Reload after clearing so the boot path sees a fresh DB. // Reload after clearing so the boot path sees a fresh DB.
await page.goto('/?devtime=fake'); await page.goto('/?devtime=fake');
// ASSERTION A (Plan 02-06 G1) — body background is #1a1a1a from frame
// one. The dark canvas no longer floats in a sea of white.
const bodyBg = await page.evaluate(() => {
return window.getComputedStyle(document.body).backgroundColor;
});
expect(bodyBg).toBe('rgb(26, 26, 26)'); // #1a1a1a in computed-style form
// 2) Begin screen visible (first run). // 2) Begin screen visible (first run).
const beginButton = page.getByRole('button', { name: 'Begin' }); const beginButton = page.getByRole('button', { name: 'Begin' });
await expect(beginButton).toBeVisible({ timeout: 15000 }); await expect(beginButton).toBeVisible({ timeout: 15000 });
@@ -78,6 +85,14 @@ test.describe('PIPE-07 — Season 1 full loop', () => {
await beginButton.click(); await beginButton.click();
await expect(beginButton).not.toBeVisible({ timeout: 5000 }); await expect(beginButton).not.toBeVisible({ timeout: 5000 });
// ASSERTION B (Plan 02-06 G2) — first-run hint is visible immediately
// after Begin dismisses (the A-Dark-Room first-prompt). Player sees
// the externalized line from ui-strings.yaml.
await expect(page.getByTestId('first-run-hint')).toBeVisible({ timeout: 5000 });
const hintText = await page.getByTestId('first-run-hint').textContent();
expect(hintText).toBeTruthy();
expect(hintText!.length).toBeGreaterThan(0);
// 4) Wait for the test-exposed store + fake clock. // 4) Wait for the test-exposed store + fake clock.
await page.waitForFunction(() => { await page.waitForFunction(() => {
const w = window as unknown as DevTimeWindow; const w = window as unknown as DevTimeWindow;
@@ -112,6 +127,11 @@ test.describe('PIPE-07 — Season 1 full loop', () => {
{ timeout: 5000 }, { timeout: 5000 },
); );
// ASSERTION C (Plan 02-06 G2) — first-run hint auto-dismisses on the
// first plant. The component subscribes to the tiles slice and
// dismisses when any tile transitions to plant !== null.
await expect(page.getByTestId('first-run-hint')).not.toBeVisible({ timeout: 5000 });
// 7) Fast-forward growth past 600 ticks (5Hz * 600 = 120s = 2min). // 7) Fast-forward growth past 600 ticks (5Hz * 600 = 120s = 2min).
// Advance 3 minutes wall-clock so the rosemary plant is solidly // Advance 3 minutes wall-clock so the rosemary plant is solidly
// in the 'ready' stage. // in the 'ready' stage.