Files
flights_web/tests/e2e-angular/ru-ru/persistent-state.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

118 lines
3.6 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('US-101: Persistent State Management', () => {
test('should persist search form state across page reload', async ({ page, context }) => {
await page.goto('http://localhost:3002/ru-ru/schedule');
await page.waitForLoadState('networkidle');
// Fill search form
await page
.locator('input[placeholder*="city"], [aria-label*="город отправления"]')
.first()
.fill('Moscow');
await page
.locator('input[placeholder*="city"], [aria-label*="город прибытия"]')
.nth(1)
.fill('St Petersburg');
// Reload page
await page.reload();
await page.waitForLoadState('networkidle');
// Check that form values are still there
const fromInput = await page.locator('input').first().inputValue();
const toInput = await page.locator('input').nth(1).inputValue();
expect(fromInput).toBe('Moscow');
expect(toInput).toBe('St Petersburg');
});
test('should respect 30-day expiration for persisted state', async ({ page }) => {
await page.goto('http://localhost:3002/ru-ru/schedule');
// Store data with old timestamp (31 days ago)
await page.evaluate(() => {
const thirtyOneDaysAgo = Date.now() - 31 * 24 * 60 * 60 * 1000;
const data = JSON.stringify({
value: { test: 'data' },
timestamp: thirtyOneDaysAgo,
});
localStorage.setItem('aeroflot_expiredTest', data);
});
// Reload and check if expired data is gone
await page.reload();
await page.waitForLoadState('networkidle');
const expiredData = await page.evaluate(() => {
return localStorage.getItem('aeroflot_expiredTest');
});
expect(expiredData).toBeNull();
});
test('should handle localStorage quota gracefully', async ({ page }) => {
await page.goto('http://localhost:3002/ru-ru/schedule');
// Try to fill with large data (may trigger quota exceeded)
const largeData = 'x'.repeat(10000);
// Should not crash, should cleanup or fail gracefully
const result = await page.evaluate(async (data) => {
try {
localStorage.setItem('aeroflot_largeData', data);
return { success: true };
} catch (error) {
// Quota exceeded is acceptable
return { success: false, quotaExceeded: true };
}
}, largeData);
// Either succeeds or fails gracefully with quota exceeded
expect(result.success || result.quotaExceeded).toBe(true);
});
test('should clear state when requested', async ({ page }) => {
await page.goto('http://localhost:3002/ru-ru/schedule');
// Store data
await page.evaluate(() => {
localStorage.setItem(
'aeroflot_clearTest',
JSON.stringify({
value: { test: 'data' },
timestamp: Date.now(),
}),
);
});
// Clear it
await page.evaluate(() => {
localStorage.removeItem('aeroflot_clearTest');
});
// Verify it's gone
const cleared = await page.evaluate(() => {
return localStorage.getItem('aeroflot_clearTest');
});
expect(cleared).toBeNull();
});
test('should console have zero errors', async ({ page }) => {
const errors: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') errors.push(msg.text());
});
await page.goto('http://localhost:3002/ru-ru/schedule');
await page.waitForLoadState('networkidle');
// Interact with persistent state
await page.locator('input').first().fill('Moscow');
await page.reload();
expect(errors).toHaveLength(0);
});
});