feat(operations): add source diagnosis workspace
This commit is contained in:
@@ -1,14 +1,22 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { afterEach, expect, test, vi } from 'vitest';
|
||||
import OperationsPage from './OperationsPage';
|
||||
|
||||
const mocks = vi.hoisted(() => ({ opsHealth: vi.fn(), sourceReadiness: vi.fn() }));
|
||||
const mocks = vi.hoisted(() => ({
|
||||
opsHealth: vi.fn(), sourceReadiness: vi.fn(), session: vi.fn(), vehicleCoverage: vi.fn(),
|
||||
vehicleSourceDiagnostic: vi.fn(), updateVehicleSourcePolicy: vi.fn()
|
||||
}));
|
||||
vi.mock('../../api/client', () => ({ api: mocks }));
|
||||
|
||||
afterEach(() => { cleanup(); mocks.opsHealth.mockReset(); mocks.sourceReadiness.mockReset(); });
|
||||
afterEach(() => { cleanup(); Object.values(mocks).forEach((mock) => mock.mockReset()); });
|
||||
|
||||
function seedSession() {
|
||||
mocks.session.mockResolvedValue({ name: '平台管理员', role: 'admin', userType: 'admin', authMode: 'enforce', menuKeys: ['operations'] });
|
||||
}
|
||||
|
||||
test('reconciles service identities with bound and identity-required vehicles', async () => {
|
||||
seedSession();
|
||||
mocks.opsHealth.mockResolvedValue({
|
||||
linkHealth: [], kafkaLag: 0, activeConnections: 10, capacityFindings: [], redisOnlineKeys: 5,
|
||||
tdengineWritable: true, mysqlWritable: true,
|
||||
@@ -34,6 +42,7 @@ test('reconciles service identities with bound and identity-required vehicles',
|
||||
});
|
||||
|
||||
test('keeps health evidence visible when source readiness fails and retries that section', async () => {
|
||||
seedSession();
|
||||
mocks.opsHealth.mockResolvedValue({
|
||||
linkHealth: [], kafkaLag: 0, activeConnections: 10, capacityFindings: [], redisOnlineKeys: 5,
|
||||
tdengineWritable: true, mysqlWritable: true,
|
||||
@@ -54,3 +63,39 @@ test('keeps health evidence visible when source readiness fails and retries that
|
||||
expect(screen.queryByText('来源就绪度暂时不可用')).not.toBeInTheDocument();
|
||||
expect(mocks.sourceReadiness).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('fuzzy searches a vehicle and renders all source diagnosis evidence', async () => {
|
||||
seedSession();
|
||||
mocks.opsHealth.mockResolvedValue({
|
||||
linkHealth: [], kafkaLag: 0, activeConnections: 10, capacityFindings: [], redisOnlineKeys: 5,
|
||||
tdengineWritable: true, mysqlWritable: true,
|
||||
runtime: { platformRelease: 'test-release', dataMode: 'production', requestTimeoutMs: 5000, amapSecurityProxyEnabled: true, amapSecurityCodeExposed: false }
|
||||
});
|
||||
mocks.sourceReadiness.mockResolvedValue({ totalVehicles: 1, boundVehicles: 1, identityRequiredVehicles: 0, onlineVehicles: 1, sources: [] });
|
||||
mocks.vehicleCoverage.mockResolvedValue({ items: [{ vin: 'VIN001', plate: '粤A00001', protocols: ['JT808'], missingProtocols: [], sourceStatus: [], sourceCount: 2, onlineSourceCount: 2, online: true, lastSeen: '', bindingStatus: 'bound' }], total: 1, limit: 20, offset: 0 });
|
||||
mocks.vehicleSourceDiagnostic.mockResolvedValue({
|
||||
evidence: {
|
||||
vin: 'VIN001', plate: '粤A00001', mileageDate: '2026-07-16', recommendedLocationProtocol: 'JT808',
|
||||
recommendedLocationLabel: 'G7', locationConflict: true, conflictDistanceM: 233,
|
||||
locationSources: [{
|
||||
protocol: 'JT808', sourceLabel: 'G7', terminalLabel: '终端 133****0001', sourceKind: 'PLATFORM', sourceRef: 'a'.repeat(64),
|
||||
selectedWithinProtocol: true, recommended: true, enabled: true, priority: 20, online: true, qualityStatus: 'OK', qualityReason: '',
|
||||
longitude: 113.1, latitude: 23.1, speedKmh: 30, totalMileageKm: 1000, eventTime: '2026-07-16 10:00:00',
|
||||
receivedAt: '2026-07-16 10:00:01', firstSeenAt: '2026-03-01 08:00:00', reportIntervalSec: 10, reportSampleCount: 1000,
|
||||
selectionReason: '当前融合推荐'
|
||||
}],
|
||||
mileageSources: [], comparison: { locationMaxDistanceM: 233, totalMileageDeltaKm: 0, dailyMileageDeltaKm: 0, reportTimeDeltaSeconds: 0 }, asOf: ''
|
||||
},
|
||||
policy: { vin: 'VIN001', version: 1, updatedBy: 'system', updatedAt: '', audit: [] },
|
||||
recommendationReason: '当前推荐 G7', refreshHint: '下一次有效上报后重新选举'
|
||||
});
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
render(<QueryClientProvider client={client}><OperationsPage /></QueryClientProvider>);
|
||||
fireEvent.change(screen.getByLabelText('按车牌或 VIN 搜索诊断车辆'), { target: { value: '粤A' } });
|
||||
expect(await screen.findByText('粤A00001')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('粤A00001'));
|
||||
expect(await screen.findByText('当前推荐 G7')).toBeInTheDocument();
|
||||
expect(screen.getByText('终端 133****0001')).toBeInTheDocument();
|
||||
expect(screen.getByText('10s')).toBeInTheDocument();
|
||||
await waitFor(() => expect(mocks.vehicleSourceDiagnostic).toHaveBeenCalledWith('VIN001', expect.any(AbortSignal)));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user