Files
Portfolio/e2e/terminal.e2e.ts
Antonio Ledebuhr bb9912daef Keep the default-open terminal inside the viewport and the map labels inside their shapes.
The dock prompt and placeholder now meet contrast on the raised surface, and service nodes use the same rect geometry as the cases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 00:43:56 +02:00

159 lines
5.7 KiB
TypeScript

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('defaults open, keeps one session scrollport and runs the grammar', async ({
page,
}, testInfo) => {
const copy = SIGNATURE_COPY.de.terminal;
await page.goto('/');
const trigger = page.locator('.terminal-dock-trigger');
const panel = page.locator('.terminal-dock-panel');
const input = page.locator('#terminal-dock-input');
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(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') {
const box = await panel.boundingBox();
expect(box, 'bottom-sheet panel').toBeTruthy();
expect(box!.width).toBeGreaterThan(300);
} 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');
}
await input.fill('navigate pitch');
await input.press('Enter');
await page.waitForURL('**/pitch');
await expect(page).toHaveURL(/\/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(session).toContainText(copy.historyIntro);
await expect(session).toContainText('navigate pitch');
await input.fill('clear');
await input.press('Enter');
await expect(session).toContainText(copy.clearedMessage);
await expect(session.locator('p')).toHaveCount(1);
await input.fill('navigate p');
await input.press('Tab');
await expect(session).toContainText('pitch');
await expect(session).toContainText('projects');
await input.fill('navigate nowhere');
await input.press('Enter');
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('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 expect(panel).toBeVisible();
await expect(trigger).toBeHidden();
const collapse = page.getByRole('button', { name: copy.collapseLabel });
await collapse.click();
await expect(panel).toHaveCount(0);
await expect(trigger).toBeVisible();
await expect(trigger).toBeFocused();
await expect(trigger).toHaveAttribute('aria-expanded', 'false');
});
test('keeps the prompt in the session scrollport after overflow', async ({ page }) => {
const copy = SIGNATURE_COPY.de.terminal;
await page.goto('/');
const input = page.locator('#terminal-dock-input');
const session = page.locator('.terminal-dock-session');
await expect(session).toBeVisible();
for (let index = 0; index < 8; index += 1) {
await input.fill('help');
await input.press('Enter');
}
await expect(session.locator('p.echo').last()).toHaveText(`${copy.prompt} help`);
await expect
.poll(async () =>
session.evaluate((element) => {
return element.scrollTop + element.clientHeight >= element.scrollHeight - 2;
}),
)
.toBe(true);
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 ({
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 expect(panel).toBeVisible();
const collapse = page.getByRole('button', { name: copy.collapseLabel });
await collapse.focus();
await expect(collapse).toBeFocused();
await page.keyboard.press('Escape');
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);
}
});
});