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