feat: expand vehicle data platform capabilities
This commit is contained in:
@@ -1026,7 +1026,7 @@ test('dashboard renders vehicle service summary metrics', async () => {
|
||||
expect(screen.getByText('档案不完整')).toBeInTheDocument();
|
||||
expect(screen.getByText('366')).toBeInTheDocument();
|
||||
expect(screen.queryByText('NaN%')).not.toBeInTheDocument();
|
||||
expect(fetchMock).toHaveBeenCalledWith('/api/vehicle-service/summary', undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith('/api/vehicle-service/summary', expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('dashboard presents one vehicle service operating posture', async () => {
|
||||
@@ -3159,7 +3159,7 @@ test('opens dashboard coverage from service action queue', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: '补齐 YUTONG_MQTT 来源 983' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3212,7 +3212,7 @@ test('opens vehicle list filtered by service summary KPI', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: '告警车辆 7' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/vehicles?serviceStatus=degraded');
|
||||
});
|
||||
@@ -3731,7 +3731,7 @@ test('filters vehicle list from recommended action', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: '补齐 YUTONG_MQTT 来源' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&missingProtocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&missingProtocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/vehicles?missingProtocol=YUTONG_MQTT');
|
||||
});
|
||||
@@ -3783,7 +3783,7 @@ test('filters vehicle list from action queue', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: '确认平台转发 4' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&serviceStatus=no_data'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&serviceStatus=no_data'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/vehicles?serviceStatus=no_data');
|
||||
});
|
||||
@@ -3851,12 +3851,12 @@ test('shows and clears current vehicle service filters', async () => {
|
||||
expect(screen.getByText('绑定:已绑定')).toBeInTheDocument();
|
||||
expect(screen.getByText('档案:不完整')).toBeInTheDocument();
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('archiveStatus=incomplete'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('archiveStatus=incomplete'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/vehicles');
|
||||
});
|
||||
@@ -3921,9 +3921,9 @@ test('filters vehicle list from result summary actions', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: /^在线车辆 73$/ }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&online=online'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&online=online'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage/summary?online=online'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage/summary?online=online'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(window.location.hash).toBe('#/vehicles?online=online');
|
||||
});
|
||||
|
||||
@@ -4007,7 +4007,7 @@ test('filters vehicle list by missing source evidence', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '缺 YUTONG_MQTT' }));
|
||||
expect(window.location.hash).toBe('#/vehicles?missingProtocol=YUTONG_MQTT');
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('missing-protocol-filter'));
|
||||
const mqttOptions = await screen.findAllByText('缺 YUTONG_MQTT');
|
||||
@@ -4015,7 +4015,7 @@ test('filters vehicle list by missing source evidence', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '查询' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4184,8 +4184,8 @@ test('shows resolved vehicle service status after topbar search', async () => {
|
||||
expect(await screen.findByText('当前车辆:数据通道不完整')).toBeInTheDocument();
|
||||
expect(screen.getByText('粤AG18312 / LB9A32A24R0LS1426')).toBeInTheDocument();
|
||||
expect(screen.getByText('一致性:数据通道不完整')).toBeInTheDocument();
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service/overview?keyword=%E7%B2%A4AG18312'), undefined);
|
||||
expect(fetchMock).not.toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/resolve'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service/overview?keyword=%E7%B2%A4AG18312'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).not.toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/resolve'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '顶部地图态势' }));
|
||||
expect(window.location.hash).toBe('#/map?keyword=LB9A32A24R0LS1426&protocol=JT808');
|
||||
@@ -4435,9 +4435,9 @@ test('filters dashboard coverage from source consistency diagnosis', async () =>
|
||||
fireEvent.click(screen.getByRole('button', { name: '单一来源' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(screen.getByText('当前筛选:来源不完整 / 缺 JT808')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -4542,7 +4542,7 @@ test('opens full vehicle service list from dashboard coverage filters', async ()
|
||||
expect(await screen.findByText('VIN-DASH-FULL-LIST')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: '单一来源' }));
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '查看全部车辆' }));
|
||||
@@ -4780,7 +4780,7 @@ test('filters dashboard coverage by service status', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(screen.getByText('当前筛选:来源不完整')).toBeInTheDocument();
|
||||
});
|
||||
@@ -4826,7 +4826,7 @@ test('filters dashboard coverage by missing source evidence', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(screen.getByText('当前筛选:缺 YUTONG_MQTT')).toBeInTheDocument();
|
||||
});
|
||||
@@ -4874,7 +4874,7 @@ test('opens dashboard coverage from service status distribution', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5348,7 +5348,7 @@ test('uses backend quality notification plan on quality page', async () => {
|
||||
expect(screen.getAllByText('10 分钟确认').length).toBeGreaterThan(0);
|
||||
expect(screen.getByText('后端无来源规则')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('后端 P0 通知策略').length).toBeGreaterThan(0);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/notification-plan?limit=20'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/notification-plan?limit=20'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('renders notification rules as a standalone operations page', async () => {
|
||||
@@ -5500,7 +5500,7 @@ test('renders notification rules as a standalone operations page', async () => {
|
||||
expect(screen.getAllByText('对象:接入运维 + 业务责任人;渠道:邮件 / 企业微信;升级:30 分钟升级').length).toBeGreaterThan(0);
|
||||
expect(screen.getByText('立即升级责任人并同步业务侧')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '复制通知可达性检查' })).toBeInTheDocument();
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/notification-plan?limit=50'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/notification-plan?limit=50'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '复制通知规则Runbook' }));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【通知规则Runbook】'));
|
||||
@@ -5718,8 +5718,8 @@ test('renders ops quality as a separated evidence layer for customer vehicle ser
|
||||
expect(screen.getByText('整车与氢能实时数据主来源')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('覆盖不足').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText('在线 73/340,缺失车辆 693,Kafka Lag 42').length).toBeGreaterThanOrEqual(1);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/ops/health'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/ops/source-readiness'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/ops/health'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/ops/source-readiness'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '复制容量交接' }));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【车辆数据中台运维容量交接】'));
|
||||
@@ -7188,9 +7188,9 @@ test('drills into quality issues by issue type', async () => {
|
||||
fireEvent.click(issueSummaryButton as HTMLElement);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?issueType=NO_SOURCE&limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?issueType=NO_SOURCE&limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?issueType=NO_SOURCE'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?issueType=NO_SOURCE'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('drills into quality issues by protocol bucket', async () => {
|
||||
@@ -7257,9 +7257,9 @@ test('drills into quality issues by protocol bucket', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 质量问题' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?protocol=JT808&limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?protocol=JT808&limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?protocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(window.location.hash).toBe('#/alert-events?protocol=JT808');
|
||||
});
|
||||
|
||||
@@ -7327,9 +7327,9 @@ test('drills into quality issues by issue type bucket', async () => {
|
||||
fireEvent.click(await screen.findByRole('button', { name: '查看 VIN 缺失质量问题' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?issueType=VIN_MISSING&limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?issueType=VIN_MISSING&limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?issueType=VIN_MISSING'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?issueType=VIN_MISSING'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(window.location.hash).toBe('#/alert-events?issueType=VIN_MISSING');
|
||||
});
|
||||
|
||||
@@ -7387,9 +7387,9 @@ test('applies shareable quality filters from hash', async () => {
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE&limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE&limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('shows and clears current quality filters', async () => {
|
||||
@@ -7452,7 +7452,7 @@ test('shows and clears current quality filters', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/alert-events');
|
||||
});
|
||||
@@ -7824,11 +7824,11 @@ test('applies protocol from shareable history hash to API requests', async () =>
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('protocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith('/api/history/raw-frames/query', expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: expect.stringContaining('"protocol":"JT808"')
|
||||
@@ -8183,7 +8183,7 @@ test('shows and clears current history filters while keeping vehicle scope', asy
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?limit=10&offset=0&keyword=VIN-HISTORY-001'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?limit=10&offset=0&keyword=VIN-HISTORY-001'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/history-query?keyword=VIN-HISTORY-001&tab=raw');
|
||||
});
|
||||
@@ -8482,8 +8482,8 @@ test('updates history hash when vehicle history filters are submitted', async ()
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/history?keyword=%E7%B2%A4AG18312&protocol=JT808&dateFrom=2026-07-01+00%3A00%3A00&dateTo=2026-07-01+23%3A59%3A59');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01+00%3A00%3A00'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01+00%3A00%3A00'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith('/api/history/raw-frames/query', expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: expect.stringContaining('"dateFrom":"2026-07-01 00:00:00"')
|
||||
@@ -8536,7 +8536,7 @@ test('prevents unscoped raw parsed-field query from history form', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: 'search 查询' }));
|
||||
|
||||
expect((await screen.findAllByText('字段明细查询需要车辆、时间范围或字段裁剪')).length).toBeGreaterThanOrEqual(1);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
const unscopedRawQueries = fetchMock.mock.calls.filter(([url, init]) => {
|
||||
if (url !== '/api/history/raw-frames/query') return false;
|
||||
const body = JSON.parse(String((init as RequestInit | undefined)?.body ?? '{}')) as Record<string, unknown>;
|
||||
@@ -9259,10 +9259,10 @@ test('applies mileage date range from shareable hash to API requests', async ()
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/mileage/summary?'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/mileage/summary?'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(screen.getByText('当前车辆:VIN-MILEAGE-002')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('数据通道:JT808').length).toBeGreaterThan(0);
|
||||
});
|
||||
@@ -9311,7 +9311,7 @@ test('shows and clears current mileage filters while keeping vehicle scope', asy
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/mileage/summary?keyword=VIN-MILEAGE-002'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/mileage/summary?keyword=VIN-MILEAGE-002'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/mileage?keyword=VIN-MILEAGE-002');
|
||||
});
|
||||
@@ -9363,9 +9363,9 @@ test('updates mileage hash when mileage filters are submitted', async () => {
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/mileage?keyword=%E7%B2%A4AG18312&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/mileage/summary?'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/mileage/summary?'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('opens current vehicle service from mileage header with current source evidence', async () => {
|
||||
@@ -10918,7 +10918,7 @@ test('opens vehicle service from realtime vehicles with primary source evidence'
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/detail?keyword=VIN-MQTT-001&protocol=YUTONG_MQTT');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service/overview?keyword=VIN-MQTT-001&protocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service/overview?keyword=VIN-MQTT-001&protocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('opens vehicle service from realtime vehicles with current source filter', async () => {
|
||||
@@ -11001,7 +11001,7 @@ test('opens vehicle service from realtime vehicles with current source filter',
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/detail?keyword=VIN-RT-FILTER&protocol=JT808');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service/overview?keyword=VIN-RT-FILTER&protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service/overview?keyword=VIN-RT-FILTER&protocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('shows canonical service status in realtime vehicles', async () => {
|
||||
@@ -12635,7 +12635,7 @@ test('loads realtime vehicles from shareable source filter hash', async () => {
|
||||
render(<App />);
|
||||
|
||||
expect((await screen.findAllByText('VIN-RT-FILTERED')).length).toBeGreaterThan(0);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/realtime/vehicles?limit=50&offset=0&keyword=%E7%B2%A4ART002&protocol=JT808&online=online&serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/realtime/vehicles?limit=50&offset=0&keyword=%E7%B2%A4ART002&protocol=JT808&online=online&serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('opens realtime status from quality issue row with source evidence', async () => {
|
||||
@@ -12795,7 +12795,7 @@ test('shows and clears current realtime service filters', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/realtime/vehicles?limit=50&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/realtime/vehicles?limit=50&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
expect(window.location.hash).toBe('#/realtime');
|
||||
});
|
||||
@@ -12833,7 +12833,7 @@ test('updates realtime hash when source filters are submitted', async () => {
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/realtime?keyword=%E7%B2%A4ART002&protocol=JT808');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/realtime/vehicles?limit=50&offset=0&keyword=%E7%B2%A4ART002&protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/realtime/vehicles?limit=50&offset=0&keyword=%E7%B2%A4ART002&protocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('shows vehicle service status in vehicle list', async () => {
|
||||
@@ -13056,8 +13056,8 @@ test('filters vehicle list from source consistency diagnosis', async () => {
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/vehicles?serviceStatus=degraded&missingProtocol=YUTONG_MQTT');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('filters vehicle list from single-source consistency diagnosis', async () => {
|
||||
@@ -13142,7 +13142,7 @@ test('filters vehicle list from single-source consistency diagnosis', async () =
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/vehicles?serviceStatus=degraded&missingProtocol=JT808');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('opens vehicle service from source-filtered vehicle list with source evidence', async () => {
|
||||
@@ -13424,7 +13424,7 @@ test('filters vehicle list by service status', async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '查询' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('serviceStatus=degraded'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13554,7 +13554,7 @@ test('switches vehicle detail to a source from the source matrix', async () => {
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash).toBe('#/detail?keyword=VIN001&protocol=JT808');
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service?keyword=VIN001&protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service?keyword=VIN001&protocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('shows unified service overview on vehicle detail', async () => {
|
||||
@@ -13732,7 +13732,7 @@ test('opens quality governance from vehicle detail overview', async () => {
|
||||
expect(await screen.findByRole('heading', { name: '告警事件' })).toBeInTheDocument();
|
||||
expect(screen.getByText('告警事件闭环')).toBeInTheDocument();
|
||||
expect(screen.getByText('事件触发')).toBeInTheDocument();
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?keyword=VIN001&limit=20&offset=0'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?keyword=VIN001&limit=20&offset=0'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('quality health storage card stays pending before ops health loads', async () => {
|
||||
@@ -14904,7 +14904,7 @@ test('shows selected source scope on vehicle detail', async () => {
|
||||
expect(screen.getAllByText('单一数据通道:JT808').length).toBeGreaterThan(0);
|
||||
expect(screen.getByText('车辆服务状态')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('数据通道不完整').length).toBeGreaterThan(0);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service?keyword=VIN001&protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicle-service?keyword=VIN001&protocol=JT808'), expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||
});
|
||||
|
||||
test('shows cross-source consistency for one vehicle service', async () => {
|
||||
|
||||
@@ -41,6 +41,10 @@ test('renders date-range mileage summary, trend and daily detail list', async ()
|
||||
expect((await screen.findAllByText('210.5 km')).length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getByText('粤A12345')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('80.5').length).toBeGreaterThanOrEqual(1);
|
||||
await waitFor(() => expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), { signal: expect.any(AbortSignal) }));
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('keyword=%E7%B2%A4A12345'), { signal: expect.any(AbortSignal) });
|
||||
await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(2));
|
||||
for (const [path, init] of fetchMock.mock.calls) {
|
||||
expect(['/api/v2/statistics/mileage', '/api/mileage/daily']).toContain(path);
|
||||
expect(init).toMatchObject({ method: 'POST', headers: { 'Content-Type': 'application/json' }, signal: expect.any(AbortSignal) });
|
||||
expect(JSON.parse(String(init?.body))).toMatchObject({ dateFrom: '2026-07-01', dateTo: '2026-07-03', keyword: '粤A12345', protocol: 'JT808' });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user