Assertions now follow the eighteen prerenderable paths, the gist dialog, and the six-case evidence set. Co-authored-by: Cursor <cursoragent@cursor.com>
110 lines
4.2 KiB
TypeScript
110 lines
4.2 KiB
TypeScript
import { expect, test } from '@playwright/test';
|
|
import { pagePath } from './helpers';
|
|
|
|
test.describe('keyboard and terminal dock', () => {
|
|
test('skip link is first and moves focus to main', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.keyboard.press('Tab');
|
|
const skip = page.locator('.skip-link');
|
|
await expect(skip).toBeFocused();
|
|
await page.keyboard.press('Enter');
|
|
await expect(page.locator('#main-content')).toBeFocused();
|
|
});
|
|
|
|
test('mobile nav toggle keeps aria-expanded in sync', async ({ page, request }) => {
|
|
const ssr = await request.get('/');
|
|
expect(ssr.ok()).toBe(true);
|
|
const html = await ssr.text();
|
|
expect(html).toContain('aria-expanded="true"');
|
|
expect(html).toContain('id="primary-nav"');
|
|
expect(html).toContain('class="site-nav"');
|
|
expect(html).toMatch(/<div[^>]*class="site"/);
|
|
expect(html).not.toMatch(/<div[^>]*class="[^"]*\bsite\b[^"]*\bnav-collapsed\b/);
|
|
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
await page.goto('/');
|
|
const toggle = page.locator('.nav-toggle');
|
|
await expect(toggle).toBeVisible();
|
|
await expect(toggle).toHaveAttribute('aria-expanded', 'false');
|
|
await toggle.click();
|
|
await expect(toggle).toHaveAttribute('aria-expanded', 'true');
|
|
await toggle.click();
|
|
await expect(toggle).toHaveAttribute('aria-expanded', 'false');
|
|
});
|
|
|
|
test('collapsed header stays under 25% of the viewport and is not sticky below md', async ({
|
|
page,
|
|
}) => {
|
|
const viewport = { width: 390, height: 844 };
|
|
await page.setViewportSize(viewport);
|
|
await page.goto('/');
|
|
|
|
const header = page.locator('.site-header');
|
|
const box = await header.boundingBox();
|
|
expect(box).toBeTruthy();
|
|
expect(box!.height).toBeLessThan(viewport.height * 0.25);
|
|
|
|
await expect
|
|
.poll(async () => header.evaluate((element) => getComputedStyle(element).position))
|
|
.not.toBe('sticky');
|
|
|
|
await page.locator('.nav-toggle').click();
|
|
await expect(page.locator('.nav-toggle')).toHaveAttribute('aria-expanded', 'true');
|
|
expect(await header.evaluate((element) => getComputedStyle(element).position)).not.toBe(
|
|
'sticky',
|
|
);
|
|
|
|
for (const width of [768, 820, 1024, 1280, 1440]) {
|
|
await page.setViewportSize({ width, height: 900 });
|
|
await page.goto('/');
|
|
expect(
|
|
await header.evaluate((element) => getComputedStyle(element).position),
|
|
`header must not be sticky at ${width}px`,
|
|
).not.toBe('sticky');
|
|
}
|
|
});
|
|
|
|
test('compact primary nav stays a single row without a services submenu', async ({
|
|
page,
|
|
}, testInfo) => {
|
|
test.skip(testInfo.project.name === 'mobile', 'compact nav applies from md up');
|
|
|
|
await page.setViewportSize({ width: 1024, height: 900 });
|
|
await page.goto('/');
|
|
|
|
const services = page.locator(`.primary-nav > li > a[href="${pagePath('services', 'de')}"]`);
|
|
await expect(services).toBeVisible();
|
|
await expect(page.locator('.primary-nav .submenu')).toHaveCount(0);
|
|
await expect(page.locator('.primary-nav a')).toHaveCount(5);
|
|
|
|
await services.click();
|
|
await page.waitForURL('**/leistungen');
|
|
await expect(services).toHaveAttribute('aria-current', 'page');
|
|
|
|
const overflow = await page.evaluate(
|
|
() => document.documentElement.scrollWidth <= window.innerWidth + 1,
|
|
);
|
|
expect(overflow, 'horizontal overflow at 1024px').toBe(true);
|
|
});
|
|
|
|
test('terminal dock is open on load, does not lock the page, and restores on Escape', async ({
|
|
page,
|
|
}) => {
|
|
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();
|
|
await expect(page.locator('#terminal-dock-input')).not.toBeFocused();
|
|
await expect(page.locator('.site')).not.toHaveAttribute('inert');
|
|
expect(await page.evaluate(() => document.body.style.overflow)).not.toBe('hidden');
|
|
await expect(page.locator('.terminal-dock [role="dialog"]')).toHaveCount(0);
|
|
|
|
await page.locator('#terminal-dock-input').focus();
|
|
await page.keyboard.press('Escape');
|
|
await expect(panel).toHaveCount(0);
|
|
await expect(trigger).toBeFocused();
|
|
});
|
|
});
|