Assertions now follow the eighteen prerenderable paths, the gist dialog, and the six-case evidence set. Co-authored-by: Cursor <cursoragent@cursor.com>
158 lines
5.7 KiB
TypeScript
158 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.locator('p')).toHaveText(copy.clearedMessage);
|
|
|
|
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);
|
|
}
|
|
});
|
|
});
|