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.
279 lines
11 KiB
TypeScript
279 lines
11 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Unicode Character Support (US-92)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/');
|
|
// Accept any cookie consent if present
|
|
const cookieButton = page.locator('button:has-text("Accept")').first();
|
|
if (await cookieButton.isVisible({ timeout: 1000 }).catch(() => false)) {
|
|
await cookieButton.click();
|
|
}
|
|
});
|
|
|
|
test.describe('Unicode City Names - CJK Languages', () => {
|
|
test('should accept Chinese city names (北京)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Chinese city name
|
|
await departureInput.fill('北京');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('北京');
|
|
});
|
|
|
|
test('should accept Japanese city names (東京)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Japanese city name
|
|
await departureInput.fill('東京');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('東京');
|
|
});
|
|
|
|
test('should accept Korean city names (서울)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Korean city name
|
|
await departureInput.fill('서울');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('서울');
|
|
});
|
|
});
|
|
|
|
test.describe('Unicode City Names - Arabic', () => {
|
|
test('should accept Arabic city names (مصر)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Arabic city name
|
|
await departureInput.fill('مصر');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('مصر');
|
|
});
|
|
|
|
test('should accept Arabic city names (القاهرة)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Arabic city name
|
|
await departureInput.fill('القاهرة');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('القاهرة');
|
|
});
|
|
|
|
test('should accept Arabic city names (دبي)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Arabic city name
|
|
await departureInput.fill('دبي');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('دبي');
|
|
});
|
|
});
|
|
|
|
test.describe('Unicode City Names - Thai', () => {
|
|
test('should accept Thai city names (กรุงเทพ)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Thai city name
|
|
await departureInput.fill('กรุงเทพ');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('กรุงเทพ');
|
|
});
|
|
|
|
test('should accept Thai city names (เชียงใหม่)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Thai city name
|
|
await departureInput.fill('เชียงใหม่');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('เชียงใหม่');
|
|
});
|
|
});
|
|
|
|
test.describe('Unicode with Punctuation and Spaces', () => {
|
|
test('should accept Cyrillic with hyphens (Санкт-Петербург)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Cyrillic city with hyphen
|
|
await departureInput.fill('Санкт-Петербург');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('Санкт-Петербург');
|
|
});
|
|
|
|
test('should accept Latin with spaces (New York)', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Latin city with space
|
|
await departureInput.fill('New York');
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('New York');
|
|
});
|
|
|
|
test("should accept Latin with apostrophes (L'Aquila)", async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Latin city with apostrophe
|
|
await departureInput.fill("L'Aquila");
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe("L'Aquila");
|
|
});
|
|
});
|
|
|
|
test.describe('Unicode Rejection - Invalid Characters', () => {
|
|
test('should reject emoji characters', async ({ page }) => {
|
|
const consoleErrors: string[] = [];
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
consoleErrors.push(msg.text());
|
|
}
|
|
});
|
|
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Try to enter emoji with text
|
|
await departureInput.fill('Москва 🎉');
|
|
await departureInput.blur();
|
|
await page.waitForTimeout(100);
|
|
|
|
// Input should not accept or display emoji
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).not.toContain('🎉');
|
|
});
|
|
|
|
test('should reject numeric characters', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Try to enter text with numbers
|
|
await departureInput.fill('City123');
|
|
await departureInput.blur();
|
|
await page.waitForTimeout(100);
|
|
|
|
// Input should not accept numbers
|
|
const inputValue = await departureInput.inputValue();
|
|
expect(inputValue).not.toContain('123');
|
|
});
|
|
});
|
|
|
|
test.describe('Unicode Preservation in UI', () => {
|
|
test('should preserve Unicode characters when clearing and re-entering', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// First entry
|
|
await departureInput.fill('北京');
|
|
let inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('北京');
|
|
|
|
// Clear and re-enter
|
|
await departureInput.clear();
|
|
await departureInput.fill('北京');
|
|
inputValue = await departureInput.inputValue();
|
|
expect(inputValue).toBe('北京');
|
|
});
|
|
|
|
test('should handle multiple Unicode scripts in sequence', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
const arrivalContainer = page.locator('[data-testid="filter-route-arrival-input"]');
|
|
const arrivalInput = arrivalContainer.locator('input').first();
|
|
|
|
// Enter different Unicode scripts
|
|
await departureInput.fill('北京');
|
|
await arrivalInput.fill('مصر');
|
|
|
|
expect(await departureInput.inputValue()).toBe('北京');
|
|
expect(await arrivalInput.inputValue()).toBe('مصر');
|
|
});
|
|
|
|
test('should trim whitespace from Unicode city names', async ({ page }) => {
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Enter Unicode with whitespace
|
|
await departureInput.fill(' 東京 ');
|
|
await departureInput.blur();
|
|
|
|
const inputValue = await departureInput.inputValue();
|
|
// After sanitization, whitespace should be trimmed
|
|
expect(inputValue.trim()).toBe('東京');
|
|
});
|
|
});
|
|
|
|
test.describe('Console - No Errors on Unicode Input', () => {
|
|
test('should not produce errors when handling Unicode characters', async ({ page }) => {
|
|
const consoleErrors: string[] = [];
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
consoleErrors.push(msg.text());
|
|
}
|
|
});
|
|
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
|
|
// Test various Unicode scripts
|
|
const testInputs = ['北京', 'مصر', 'กรุงเทพ', 'Москва', 'Paris'];
|
|
|
|
for (const input of testInputs) {
|
|
await departureInput.clear();
|
|
await departureInput.fill(input);
|
|
await departureInput.blur();
|
|
await page.waitForTimeout(50);
|
|
}
|
|
|
|
// Should not have any console errors related to Unicode handling
|
|
expect(consoleErrors).toHaveLength(0);
|
|
});
|
|
|
|
test('should not throw errors on search with Unicode input', async ({ page }) => {
|
|
const consoleErrors: string[] = [];
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
consoleErrors.push(msg.text());
|
|
}
|
|
});
|
|
|
|
const departureContainer = page.locator('[data-testid="filter-route-departure-input"]');
|
|
const departureInput = departureContainer.locator('input').first();
|
|
const arrivalContainer = page.locator('[data-testid="filter-route-arrival-input"]');
|
|
const arrivalInput = arrivalContainer.locator('input').first();
|
|
const searchBtn = page.locator('[data-testid="filter-route-search"]');
|
|
|
|
// Enter Unicode cities and attempt search
|
|
await departureInput.fill('北京');
|
|
await arrivalInput.fill('مصر');
|
|
|
|
// Try to click search (if enabled)
|
|
if (await searchBtn.isEnabled()) {
|
|
await searchBtn.click();
|
|
await page.waitForTimeout(200);
|
|
}
|
|
|
|
// Should not have console errors
|
|
expect(consoleErrors).toHaveLength(0);
|
|
});
|
|
});
|
|
});
|