/** * Phase-3 acceptance tests: 视角/perspective switcher (D2 — frontend view-presets only). * * Roles are NOT access control: the switcher only changes the default landing page + * granularity/filter presets. This suite verifies the switcher renders, selecting a role * navigates to that role's default landing URL (with its query params), and the choice * survives a reload (persisted to localStorage['cbpoa_role']). * * Auth + API mocking mirror e2e/user-flows.spec.ts so the suite runs hermetically. */ import { test, expect, Page } from '@playwright/test'; import { TESTIDS } from '../src/utils/testids'; /** Seed auth token and mock all /api/** calls (shapes copied from user-flows.spec.ts). */ async function seedAuthAndMockApi(page: Page) { await page.addInitScript(() => { localStorage.setItem('cbpoa_token', 'e2e-test-token'); }); await page.route('/api/**', (route) => { const url = route.request().url(); if (url.includes('/alerts')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ alerts: [], total: 0 }), }); return; } if (url.includes('/history/aggregated')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ aggregations: [], total_records: 0 }), }); return; } if (url.includes('/grids')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ type: 'FeatureCollection', features: [] }), }); return; } if (url.includes('/cases/demographics')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ age_distribution: [], gender_split: { male: { outpatient: 0, inpatient: 0 }, female: { outpatient: 0, inpatient: 0 } }, age_diagnosis_matrix: [], }), }); return; } if (url.includes('/cases/diagnosis-distribution') || url.includes('/cases/disease-seasonality')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]) }); return; } if (url.includes('/cases/districts') || url.includes('/districts')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]) }); return; } if (url.includes('/cases/trend') || url.includes('/cases')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [], total: 0 }), }); return; } route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [], items: [], total: 0 }), }); }); } test.describe('视角/perspective switcher (Phase 3)', () => { // Use a desktop viewport so the top bar renders the switcher inline. test.use({ viewport: { width: 1280, height: 800 } }); test.beforeEach(async ({ page }) => { await seedAuthAndMockApi(page); }); test('perspective-switcher is visible in the top bar', async ({ page }) => { await page.goto('/monitoring'); await expect(page.locator(`[data-testid="${TESTIDS.perspectiveSwitcher}"]`)).toBeVisible(); }); test('selecting 厅领导 (official) navigates to /overview?granularity=district', async ({ page }) => { await page.goto('/monitoring'); const switcher = page.locator(`[data-testid="${TESTIDS.perspectiveSwitcher}"]`); await expect(switcher).toBeVisible(); await switcher.selectOption('official'); await expect(page).toHaveURL(/\/overview/); await expect(page).toHaveURL(/granularity=district/); }); test('selecting 医生 (doctor) navigates to /alerts?view=cluster', async ({ page }) => { await page.goto('/monitoring'); const switcher = page.locator(`[data-testid="${TESTIDS.perspectiveSwitcher}"]`); await expect(switcher).toBeVisible(); await switcher.selectOption('doctor'); await expect(page).toHaveURL(/\/alerts/); await expect(page).toHaveURL(/view=cluster/); }); test('selected role persists across reload (localStorage cbpoa_role)', async ({ page }) => { await page.goto('/monitoring'); const switcher = page.locator(`[data-testid="${TESTIDS.perspectiveSwitcher}"]`); await switcher.selectOption('doctor'); await expect(page).toHaveURL(/\/alerts/); // localStorage should now hold the chosen role. const stored = await page.evaluate(() => localStorage.getItem('cbpoa_role')); expect(stored).toBe('doctor'); await page.reload(); // After reload the switcher reflects the persisted role. await expect(page.locator(`[data-testid="${TESTIDS.perspectiveSwitcher}"]`)).toHaveValue('doctor'); }); });