Files
flights_web/tests/e2e-angular/ru-ru/focus-visible.spec.ts
T
gnezim 375bcfb0fa Add e2e test suite from flights-front with Angular API mocks
Copies Playwright e2e tests (58 specs, 300+ tests) designed for cross-app
testing. Adapts API mocks to match real Aeroflot dictionary format (title
objects with multilingual keys), adds board/schedule/days endpoint mocks,
and provides Angular-specific Playwright config on port 4203.
2026-04-15 23:07:44 +03:00

101 lines
3.2 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('US-98: Focus Visible', () => {
test('should show focus outline on button when tabbed to', async ({ page }) => {
await page.goto('/ru-ru/schedule');
await page.waitForLoadState('networkidle');
// Tab to first interactive element
await page.keyboard.press('Tab');
await page.waitForTimeout(100);
const focusInfo = await page.evaluate(() => {
const el = document.activeElement as HTMLElement;
if (!el) return { hasFocusVisible: false, outlineWidth: '0px' };
const style = window.getComputedStyle(el);
return {
tagName: el.tagName,
hasFocusVisible: style.outlineWidth !== '0px' && style.outlineWidth !== 'auto',
outlineWidth: style.outlineWidth,
outlineColor: style.outlineColor,
};
});
expect(focusInfo.hasFocusVisible).toBe(true);
});
test('should show focus outline on input field', async ({ page }) => {
await page.goto('/ru-ru/schedule');
await page.waitForLoadState('networkidle');
// Find and focus on an input
const inputs = page.locator('input[type="text"]');
const count = await inputs.count();
if (count > 0) {
const firstInput = inputs.first();
await firstInput.focus();
await page.waitForTimeout(100);
const focusInfo = await firstInput.evaluate((el) => {
const style = window.getComputedStyle(el);
return {
hasFocusVisible: style.outlineWidth !== '0px' && style.outlineWidth !== 'auto',
outlineWidth: style.outlineWidth,
outlineColor: style.outlineColor,
};
});
expect(focusInfo.hasFocusVisible).toBe(true);
}
});
test('should have sufficient color contrast for focus outline (blue)', async ({ page }) => {
await page.goto('/ru-ru/schedule');
await page.waitForLoadState('networkidle');
// Tab to first button/interactive element
await page.keyboard.press('Tab');
await page.waitForTimeout(100);
const focusInfo = await page.evaluate(() => {
const el = document.activeElement as HTMLElement;
const style = window.getComputedStyle(el);
return {
outlineWidth: style.outlineWidth,
outlineColor: style.outlineColor,
outlineStyle: style.outlineStyle,
};
});
// Check that outline is visible (not 0px)
expect(focusInfo.outlineWidth).not.toMatch(/^0px$/);
// Check that outline color is the expected blue (0066cc = rgb(0, 102, 204))
expect(focusInfo.outlineColor).toMatch(/rgb\(0,\s*102,\s*204\)/);
});
test('should have zero console errors on focus interaction', async ({ page }) => {
const errors: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
// Filter out expected dev/JSX runtime errors that aren't related to focus
if (!msg.text().includes('factory') && !msg.text().includes('undefined')) {
errors.push(msg.text());
}
}
});
await page.goto('/ru-ru/schedule');
await page.waitForLoadState('networkidle');
// Tab through several elements
for (let i = 0; i < 5; i++) {
await page.keyboard.press('Tab');
await page.waitForTimeout(50);
}
expect(errors).toHaveLength(0);
});
});