diff --git a/vehicle-data-platform/apps/web/src/test/App.test.tsx b/vehicle-data-platform/apps/web/src/test/App.test.tsx index 712730e1..1b6e74d3 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -464,6 +464,173 @@ test('shows vehicle context when opening detail from shareable hash', async () = expect(screen.getByText('当前车辆:部分来源离线')).toBeInTheDocument(); }); +test('refreshes vehicle context when hash changes to another detail vehicle', async () => { + window.history.replaceState(null, '', '/#/dashboard'); + vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => { + const path = String(input); + if (path.includes('/api/vehicles/resolve')) { + return { + ok: true, + json: async () => ({ + data: { + lookupKey: 'VIN002', + resolved: true, + vin: 'VIN002', + plate: '粤B20002', + phone: '', + oem: 'G7s', + protocols: ['JT808'], + online: false, + lastSeen: '2026-07-03 20:10:10', + serviceStatus: { + status: 'offline', + severity: 'error', + title: '车辆离线', + detail: '所有已知数据来源均未在线', + sourceCount: 1, + onlineSourceCount: 0 + } + }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + if (path.includes('/api/dashboard/summary')) { + return { + ok: true, + json: async () => ({ + data: { onlineVehicles: 3, activeToday: 4, frameToday: 1286320, issueVehicles: 7, kafkaLag: 0, protocols: [], serviceStatuses: [], linkHealth: [] }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + if (path.includes('/api/vehicle-service')) { + return { + ok: true, + json: async () => ({ + data: { + vin: 'VIN002', + lookupKey: 'VIN002', + lookupResolved: true, + sources: ['JT808'], + sourceStatus: [], + realtime: [], + history: { items: [], total: 0, limit: 20, offset: 0 }, + raw: { items: [], total: 0, limit: 10, offset: 0 }, + mileage: { items: [], total: 0, limit: 20, offset: 0 }, + quality: { items: [], total: 0, limit: 20, offset: 0 } + }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + return { + ok: true, + json: async () => ({ + data: path.includes('/api/ops/health') + ? { linkHealth: [], kafkaLag: 0, redisOnlineKeys: 0, tdengineWritable: true, mysqlWritable: true, runtime: { requestTimeoutMs: 5000 } } + : { items: [], total: 0, limit: 10, offset: 0 }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + }); + + render(); + + window.history.pushState(null, '', '/#/detail?keyword=VIN002'); + window.dispatchEvent(new HashChangeEvent('hashchange')); + + expect(await screen.findByText('粤B20002 / VIN002')).toBeInTheDocument(); + expect(screen.getByText('当前车辆:车辆离线')).toBeInTheDocument(); +}); + +test('shows vehicle context when opening detail from sidebar navigation', async () => { + window.history.replaceState(null, '', '/#/dashboard'); + vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => { + const path = String(input); + if (path.includes('/api/vehicles/resolve')) { + return { + ok: true, + json: async () => ({ + data: { + lookupKey: 'LB9A32A24R0LS1426', + resolved: true, + vin: 'LB9A32A24R0LS1426', + plate: '粤AGQ8398', + phone: '', + oem: 'G7s', + protocols: ['JT808'], + online: false, + lastSeen: '2026-07-03 20:10:10', + serviceStatus: { + status: 'offline', + severity: 'error', + title: '车辆离线', + detail: '所有已知数据来源均未在线', + sourceCount: 1, + onlineSourceCount: 0 + } + }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + if (path.includes('/api/dashboard/summary')) { + return { + ok: true, + json: async () => ({ + data: { onlineVehicles: 3, activeToday: 4, frameToday: 1286320, issueVehicles: 7, kafkaLag: 0, protocols: [], serviceStatuses: [], linkHealth: [] }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + if (path.includes('/api/vehicle-service')) { + return { + ok: true, + json: async () => ({ + data: { + vin: 'LB9A32A24R0LS1426', + lookupKey: 'LB9A32A24R0LS1426', + lookupResolved: true, + sources: ['JT808'], + sourceStatus: [], + realtime: [], + history: { items: [], total: 0, limit: 20, offset: 0 }, + raw: { items: [], total: 0, limit: 10, offset: 0 }, + mileage: { items: [], total: 0, limit: 20, offset: 0 }, + quality: { items: [], total: 0, limit: 20, offset: 0 } + }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + return { + ok: true, + json: async () => ({ + data: path.includes('/api/ops/health') + ? { linkHealth: [], kafkaLag: 0, redisOnlineKeys: 0, tdengineWritable: true, mysqlWritable: true, runtime: { requestTimeoutMs: 5000 } } + : { items: [], total: 0, limit: 10, offset: 0 }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + }); + + render(); + + fireEvent.click(screen.getAllByText('车辆详情')[0]); + + expect(await screen.findByText('粤AGQ8398 / LB9A32A24R0LS1426')).toBeInTheDocument(); + expect(screen.getByText('当前车辆:车辆离线')).toBeInTheDocument(); +}); + test('applies protocol from shareable history hash to API requests', async () => { window.history.replaceState(null, '', '/#/history?keyword=%E7%B2%A4AG18312&protocol=JT808'); const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input, init) => {