375bcfb0fa
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.
85 lines
3.0 KiB
TypeScript
85 lines
3.0 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
const BASE_URL = process.env.BASE_URL || 'http://localhost:3002';
|
|
|
|
test.describe('US-96: ARIA Labels & Semantic HTML', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/ru-ru/schedule`, { waitUntil: 'networkidle' });
|
|
await page.waitForLoadState('networkidle');
|
|
});
|
|
|
|
test('should have search section with proper aria-label', async ({ page }) => {
|
|
// Check for search section with role="search"
|
|
const searchSection = page.locator('[role="search"]').first();
|
|
if (await searchSection.isVisible()) {
|
|
const ariaLabel = await searchSection.getAttribute('aria-label');
|
|
expect(ariaLabel).toBeTruthy();
|
|
expect(ariaLabel?.length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
test('should have form fields with aria-label or associated labels', async ({ page }) => {
|
|
// Look for search inputs in the form
|
|
const inputs = await page.locator('input[type="text"]').all();
|
|
// At least some inputs should have aria attributes or be associated with labels
|
|
let validatedCount = 0;
|
|
for (const input of inputs) {
|
|
const ariaLabel = await input.getAttribute('aria-label');
|
|
const ariaLabelledby = await input.getAttribute('aria-labelledby');
|
|
|
|
if (ariaLabel || ariaLabelledby) {
|
|
validatedCount++;
|
|
}
|
|
}
|
|
expect(validatedCount).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('should have buttons with aria-label or visible text', async ({ page }) => {
|
|
const buttons = await page.locator('button').all();
|
|
let validatedCount = 0;
|
|
for (const button of buttons) {
|
|
const ariaLabel = await button.getAttribute('aria-label');
|
|
const text = (await button.textContent())?.trim();
|
|
|
|
if (ariaLabel || (text && text.length > 0)) {
|
|
validatedCount++;
|
|
}
|
|
}
|
|
expect(validatedCount).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('should have semantic HTML structure', async ({ page }) => {
|
|
// Check that page has proper semantic structure
|
|
const headings = page.locator('h1, h2, h3, h4, h5, h6');
|
|
const headingCount = await headings.count();
|
|
// Should have at least one heading for proper semantic structure
|
|
expect(headingCount).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
test('should have error messages with aria-live role="alert"', async ({ page }) => {
|
|
// Check if alert role exists (might not if no validation error)
|
|
const alerts = page.locator('[role="alert"]');
|
|
const alertCount = await alerts.count();
|
|
if (alertCount > 0) {
|
|
for (const alert of await alerts.all()) {
|
|
const ariaLive = await alert.getAttribute('aria-live');
|
|
expect(ariaLive).toBeTruthy();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should have zero console errors', async ({ page }) => {
|
|
const errors: string[] = [];
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
errors.push(msg.text());
|
|
}
|
|
});
|
|
|
|
await page.goto(`${BASE_URL}/ru-ru/schedule`, { waitUntil: 'networkidle' });
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
expect(errors).toHaveLength(0);
|
|
});
|
|
});
|