Rewrite the constraint specs and docs for the service-led information architecture.

Assertions now follow the eighteen prerenderable paths, the gist dialog, and the six-case evidence set.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-27 00:41:24 +02:00
parent 55d012cc10
commit a9ad7eb1a7
20 changed files with 467 additions and 165 deletions

View File

@@ -1,8 +1,11 @@
import { expect, test } from '@playwright/test';
import { SIGNATURE_COPY } from '../src/app/core/content/signature-copy';
import { expectNoOverflow } from './helpers';
const VIEWPORTS = [320, 390, 768, 1024, 1440] as const;
test.describe('terminal dock', () => {
test('walks collapsed, expanded and maximized and runs the grammar', async ({
test('defaults open, keeps one session scrollport and runs the grammar', async ({
page,
}, testInfo) => {
const copy = SIGNATURE_COPY.de.terminal;
@@ -11,14 +14,17 @@ test.describe('terminal dock', () => {
const trigger = page.locator('.terminal-dock-trigger');
const panel = page.locator('.terminal-dock-panel');
const input = page.locator('#terminal-dock-input');
const log = page.locator('.terminal-dock-log');
const session = page.locator('.terminal-dock-session');
const maximize = page.locator('.terminal-dock-control[aria-pressed]');
const collapse = page.getByRole('button', { name: copy.collapseLabel });
await expect(trigger).toBeVisible();
await expect(panel).toHaveCount(0);
await trigger.click();
await expect(panel).toBeVisible();
await expect(trigger).toBeHidden();
await expect(input).not.toBeFocused();
await expect(session).toBeVisible();
await expect(session.locator('form')).toHaveCount(1);
await expect(collapse).toHaveAttribute('title', copy.collapseTooltip);
await expect(maximize).toHaveAttribute('aria-label', copy.maximizeLabel);
await expect(page.locator('.terminal-dock-prompt')).toContainText(copy.prompt);
if (testInfo.project.name === 'mobile') {
@@ -28,6 +34,7 @@ test.describe('terminal dock', () => {
} else {
await maximize.click();
await expect(maximize).toHaveAttribute('aria-pressed', 'true');
await expect(maximize).toHaveAttribute('aria-label', copy.restoreLabel);
await maximize.click();
await expect(maximize).toHaveAttribute('aria-pressed', 'false');
}
@@ -36,90 +43,88 @@ test.describe('terminal dock', () => {
await input.press('Enter');
await page.waitForURL('**/pitch');
await expect(page).toHaveURL(/\/pitch$/);
await expect(log).toContainText(`${copy.prompt} navigate pitch`);
await expect(session).toContainText(`${copy.prompt} navigate pitch`);
await input.press('ArrowUp');
await expect(input).toHaveValue('navigate pitch');
await input.fill('history');
await input.press('Enter');
await expect(log).toContainText(copy.historyIntro);
await expect(log).toContainText('navigate pitch');
await expect(session).toContainText(copy.historyIntro);
await expect(session).toContainText('navigate pitch');
await input.fill('clear');
await input.press('Enter');
await expect(log).toHaveText(copy.clearedMessage);
await expect(session.locator('p')).toHaveText(copy.clearedMessage);
await input.fill('navigate p');
await input.press('Tab');
await expect(log).toContainText('pitch');
await expect(log).toContainText('projects');
await expect(session).toContainText('pitch');
await expect(session).toContainText('projects');
await input.fill('navigate nowhere');
await input.press('Enter');
await expect(log).toContainText(copy.validTargetsLabel);
await expect(log).toContainText('pitch');
await expect(session).toContainText(copy.validTargetsLabel);
await expect(session).toContainText('pitch');
await input.fill('nav');
await input.press('Tab');
await expect(input).toHaveValue('navigate');
await input.fill('navigate services sof');
await input.press('Tab');
await expect(input).toHaveValue('navigate services software');
});
test('clicking the visible desktop trigger while open collapses the panel', async ({
page,
}, testInfo) => {
test.skip(
testInfo.project.name === 'mobile',
'Below md the trigger is hidden while the panel is open.',
);
test('collapse control hides the panel and returns focus to the trigger', async ({ page }) => {
const copy = SIGNATURE_COPY.de.terminal;
await page.goto('/');
const trigger = page.locator('.terminal-dock-trigger');
const panel = page.locator('.terminal-dock-panel');
await trigger.click();
await expect(panel).toBeVisible();
await expect(trigger).toBeVisible();
await expect(trigger).toHaveAttribute('aria-expanded', 'true');
await expect(trigger).toBeHidden();
await trigger.click();
const collapse = page.getByRole('button', { name: copy.collapseLabel });
await collapse.click();
await expect(panel).toHaveCount(0);
await expect(trigger).toHaveAttribute('aria-expanded', 'false');
await expect(trigger).toBeVisible();
await expect(trigger).toBeFocused();
await expect(trigger).toHaveAttribute('aria-expanded', 'false');
});
test('keeps the newest echoed line in the log scrollport after overflow', async ({ page }) => {
test('keeps the prompt in the session scrollport after overflow', async ({ page }) => {
const copy = SIGNATURE_COPY.de.terminal;
await page.goto('/');
const trigger = page.locator('.terminal-dock-trigger');
const input = page.locator('#terminal-dock-input');
const log = page.locator('.terminal-dock-log');
const session = page.locator('.terminal-dock-session');
await trigger.click();
await expect(log).toBeVisible();
await expect(session).toBeVisible();
for (let index = 0; index < 8; index += 1) {
await input.fill('help');
await input.press('Enter');
}
await expect(log.locator('p.echo').last()).toHaveText(`${copy.prompt} help`);
await expect(session.locator('p.echo').last()).toHaveText(`${copy.prompt} help`);
await expect
.poll(async () =>
log.evaluate((element) => {
session.evaluate((element) => {
return element.scrollTop + element.clientHeight >= element.scrollHeight - 2;
}),
)
.toBe(true);
const last = log.locator('p').last();
const logBox = await log.boundingBox();
const lastBox = await last.boundingBox();
expect(logBox && lastBox).toBeTruthy();
expect(lastBox!.y).toBeGreaterThanOrEqual(logBox!.y - 1);
expect(lastBox!.y + lastBox!.height).toBeLessThanOrEqual(logBox!.y + logBox!.height + 1);
const form = session.locator('form');
const sessionBox = await session.boundingBox();
const formBox = await form.boundingBox();
expect(sessionBox && formBox).toBeTruthy();
expect(formBox!.y).toBeGreaterThanOrEqual(sessionBox!.y - 1);
expect(formBox!.y + formBox!.height).toBeLessThanOrEqual(
sessionBox!.y + sessionBox!.height + 1,
);
});
test('Escape from a panel control collapses the dock and returns focus to the trigger', async ({
@@ -130,8 +135,6 @@ test.describe('terminal dock', () => {
const trigger = page.locator('.terminal-dock-trigger');
const panel = page.locator('.terminal-dock-panel');
await trigger.click();
await expect(panel).toBeVisible();
const collapse = page.getByRole('button', { name: copy.collapseLabel });
@@ -142,4 +145,13 @@ test.describe('terminal dock', () => {
await expect(panel).toHaveCount(0);
await expect(trigger).toBeFocused();
});
test('stays usable and overflow-free at the required viewports', async ({ page }) => {
await page.goto('/');
for (const width of VIEWPORTS) {
await page.setViewportSize({ width, height: 900 });
await expect(page.locator('.terminal-dock-panel')).toBeVisible();
await expectNoOverflow(page, '/', width);
}
});
});