89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
// Expected focus ring resolved colors
|
|
// Light: --c-focus-ring: #012851 (brand-navy)
|
|
const FOCUS_RING_LIGHT = 'rgb(1, 40, 81)';
|
|
// Dark: --c-focus-ring: #a1dcd8 (brand-mint)
|
|
const FOCUS_RING_DARK = 'rgb(161, 220, 216)';
|
|
|
|
test.describe('Focus ring token — CSS custom property', () => {
|
|
test('--c-focus-ring is defined in light mode', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.waitForSelector('[data-hydrated]');
|
|
|
|
const value = await page.evaluate(() =>
|
|
getComputedStyle(document.documentElement).getPropertyValue('--c-focus-ring').trim()
|
|
);
|
|
expect(value).toBe('#012851');
|
|
});
|
|
|
|
test('--c-focus-ring is defined in dark mode', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.waitForSelector('[data-hydrated]');
|
|
await page.evaluate(() => document.documentElement.setAttribute('data-theme', 'dark'));
|
|
|
|
const value = await page.evaluate(() =>
|
|
getComputedStyle(document.documentElement).getPropertyValue('--c-focus-ring').trim()
|
|
);
|
|
expect(value).toBe('#a1dcd8');
|
|
});
|
|
});
|
|
|
|
test.describe('Focus ring — header interactive elements', () => {
|
|
test('ThemeToggle has brand-navy ring in light mode', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.waitForSelector('[data-hydrated]');
|
|
|
|
await page.getByRole('button', { name: /dark mode|dunkelmodus/i }).focus();
|
|
const boxShadow = await page.evaluate(
|
|
() => getComputedStyle(document.activeElement as HTMLElement).boxShadow
|
|
);
|
|
expect(boxShadow).toContain(FOCUS_RING_LIGHT);
|
|
});
|
|
|
|
test('AppNav link has brand-mint ring in dark mode', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.waitForSelector('[data-hydrated]');
|
|
await page.evaluate(() => document.documentElement.setAttribute('data-theme', 'dark'));
|
|
|
|
// Focus first desktop nav link
|
|
await page.locator('header nav').getByRole('link').first().focus();
|
|
const boxShadow = await page.evaluate(
|
|
() => getComputedStyle(document.activeElement as HTMLElement).boxShadow
|
|
);
|
|
expect(boxShadow).toContain(FOCUS_RING_DARK);
|
|
});
|
|
});
|
|
|
|
test.describe('Focus ring — form inputs', () => {
|
|
test.use({ storageState: { cookies: [], origins: [] } });
|
|
|
|
test('login username input has brand-mint ring in dark mode', async ({ page }) => {
|
|
await page.goto('/login');
|
|
await page.evaluate(() => document.documentElement.setAttribute('data-theme', 'dark'));
|
|
|
|
await page.locator('#username').focus();
|
|
const boxShadow = await page.evaluate(
|
|
() => getComputedStyle(document.activeElement as HTMLElement).boxShadow
|
|
);
|
|
expect(boxShadow).toContain(FOCUS_RING_DARK);
|
|
});
|
|
});
|
|
|
|
test.describe('Focus ring — PersonTypeahead', () => {
|
|
test('PersonTypeahead input has brand-navy ring in light mode', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.waitForSelector('[data-hydrated]');
|
|
|
|
// Open advanced filter panel to expose the sender PersonTypeahead
|
|
await page.getByRole('button', { name: /filter/i }).click();
|
|
await page.waitForSelector('#senderId-search');
|
|
|
|
await page.locator('#senderId-search').focus();
|
|
const boxShadow = await page.evaluate(
|
|
() => getComputedStyle(document.activeElement as HTMLElement).boxShadow
|
|
);
|
|
expect(boxShadow).toContain(FOCUS_RING_LIGHT);
|
|
});
|
|
});
|