/** * 综合概览大屏 (/overview) 验收测试。 * * 与 user-flows.spec.ts 一致:用 addInitScript 注入 cbpoa_token 绕过登录门, * page.route 拦截 /api/** 使套件 hermetic(无需 :8000)。/wuhan_districts.geojson * 走真实静态资源(dev server 提供),由 Leaflet 取用。 */ import { test, expect, Page } from '@playwright/test'; import { TESTIDS } from '../src/utils/testids'; /** 13 区里造两条数据,断言 choropleth 能着色、toggle 能切换。 */ function districtPayload() { return { districts: [ { district: '武昌区', outpatient: 120, inpatient: 30, total: 150, outpatient_ratio: 0.8, inpatient_ratio: 0.2 }, { district: '江岸', outpatient: 60, inpatient: 10, total: 70, outpatient_ratio: 0.86, inpatient_ratio: 0.14 }, ], total: 220, }; } 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(); const json = (body: unknown) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) }); if (url.includes('/alerts')) { return json({ alerts: [], total: 0 }); } if (url.includes('/cases/stats')) { return json({ total_outpatient: 1000, total_inpatient: 200, date_range: { start: '2023-01-01', end: '2023-12-01' }, top_districts: [], top_diagnoses: [ { diagnosis: '上呼吸道感染', outpatient: 300, inpatient: 40 }, { diagnosis: '肺炎', outpatient: 120, inpatient: 80 }, ], }); } if (url.includes('/cases/trend')) { return json({ trend: [ { date: '2023-11-01', outpatient: 10, inpatient: 2, total: 12 }, { date: '2023-11-02', outpatient: 14, inpatient: 3, total: 17 }, ], summary: { total_outpatient: 24, total_inpatient: 5, period_count: 2, avg_daily_outpatient: 12, avg_daily_inpatient: 2.5, }, }); } if (url.includes('/cases/districts')) { return json(districtPayload()); } if (url.includes('/risk/stats')) { return json({ high_risk_count: 7, total_grids: 100, avg_risk: 0.4 }); } if (url.includes('/environment/pollutants')) { return json({ data: [{ date: '2023-11-01', AQI: 80 }, { date: '2023-11-02', AQI: 95 }] }); } return json({ data: [], items: [], total: 0 }); }); } test.describe('Overview 大屏', () => { test.use({ viewport: { width: 1280, height: 900 } }); test.beforeEach(async ({ page }) => { await seedAuthAndMockApi(page); }); test('renders kpi-row, choropleth, as-of badge and metric toggle', async ({ page }) => { await page.goto('/overview'); await expect(page.locator(`[data-testid="${TESTIDS.pageOverview}"]`)).toBeVisible(); await expect(page.locator(`[data-testid="${TESTIDS.kpiRow}"]`)).toBeVisible(); await expect(page.locator(`[data-testid="${TESTIDS.choroplethWrapper}"]`)).toBeVisible(); // Literal honesty badge — exact text. const badge = page.locator(`[data-testid="${TESTIDS.asofBadge}"]`); await expect(badge).toBeVisible(); await expect(badge).toHaveText('数据截至2023-12'); }); test('门诊/住院 toggle switches active segment without error', async ({ page }) => { await page.goto('/overview'); await expect(page.locator(`[data-testid="${TESTIDS.choroplethWrapper}"]`)).toBeVisible(); const outBtn = page.locator(`[data-testid="${TESTIDS.outinpatientToggle}-outpatient"]`); const inBtn = page.locator(`[data-testid="${TESTIDS.outinpatientToggle}-inpatient"]`); const allBtn = page.locator(`[data-testid="${TESTIDS.outinpatientToggle}-all"]`); // Default: 全部 active (primary background). await expect(allBtn).toHaveClass(/bg-primary/); await outBtn.click(); await expect(outBtn).toHaveClass(/bg-primary/); await expect(allBtn).not.toHaveClass(/bg-primary/); await inBtn.click(); await expect(inBtn).toHaveClass(/bg-primary/); await expect(outBtn).not.toHaveClass(/bg-primary/); // Wrapper still mounted after toggling — no render crash. await expect(page.locator(`[data-testid="${TESTIDS.choroplethWrapper}"]`)).toBeVisible(); }); });