import { test, expect, Page } from '@playwright/test'; import { TESTIDS } from '../src/utils/testids'; // 与 user-flows.spec.ts 一致的鉴权策略:注入 token 绕过登录门,并 mock /api/**, // 让用例脱离活的后端 hermetic 运行。 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('/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('/streets')) { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ streets: [] }) }); 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: [], trend: [], total: 0 }) }); return; } route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [], items: [], total: 0 }) }); }); } // 粒度(granularity)以 URL query 参数为真相来源(source of truth)。 // 监测页通过 useSearchParams 读取它,drilldownStore 单向派生。 test.describe('monitoring granularity URL source-of-truth', () => { test.beforeEach(async ({ page }) => { await seedAuthAndMockApi(page); }); test('deep-link granularity=street mounts page and reflects street in control', async ({ page }) => { await page.goto('/monitoring?granularity=street'); await expect(page.getByTestId(TESTIDS.pageMonitoring)).toBeVisible(); const control = page.getByTestId(TESTIDS.granularityControl); await expect(control).toBeVisible(); // 街道分段为激活态(Segmented 给激活按钮加 bg-primary)。 const streetBtn = page.getByTestId(`${TESTIDS.granularityControl}-street`); await expect(streetBtn).toHaveClass(/bg-primary/); }); test('clicking a granularity control updates the URL granularity param', async ({ page }) => { await page.goto('/monitoring?granularity=street'); await expect(page.getByTestId(TESTIDS.pageMonitoring)).toBeVisible(); // 切到「区域」应把 URL 写为 granularity=district。 await page.getByTestId(`${TESTIDS.granularityControl}-district`).click(); await expect(page).toHaveURL(/granularity=district/); // 切到「全市」应把 URL 写为 granularity=city。 await page.getByTestId(`${TESTIDS.granularityControl}-city`).click(); await expect(page).toHaveURL(/granularity=city/); }); test('deep-link granularity=district survives a reload', async ({ page }) => { await page.goto('/monitoring?granularity=district'); await expect(page.getByTestId(TESTIDS.pageMonitoring)).toBeVisible(); await expect(page).toHaveURL(/granularity=district/); await page.reload(); await expect(page.getByTestId(TESTIDS.pageMonitoring)).toBeVisible(); await expect(page).toHaveURL(/granularity=district/); await expect(page.getByTestId(`${TESTIDS.granularityControl}-district`)).toHaveClass(/bg-primary/); }); });