Files
flights_web/tests/e2e-angular/ru-ru/unicode-support.spec.ts
T
gnezim 20c19d15f4
CI / ci (push) Failing after 23s
Deploy / build-and-deploy (push) Failing after 5s
Add standalone API proxy via curl (bypasses WAF TLS fingerprinting)
Modern.js SSR intercepts all routes before any Express middleware,
so the API proxy runs as a separate Express server on port 8080.
Modern.js runs on 8081. The proxy uses curl subprocesses which go
through the system HTTPS proxy (GOST) with a proper TLS fingerprint
that the Aeroflot WAF accepts.

Usage: node scripts/dev-server.mjs (replaces pnpm dev for full-stack)

Also: remove stray e2e-angular test directory, fix env default to
same-origin /api.
2026-04-15 23:04:24 +03:00

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);
});
});
});