fix(tracks): sync query state with navigation
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { afterEach, beforeEach, expect, test, vi } from 'vitest';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MemoryRouter, useNavigate } from 'react-router-dom';
|
||||
import type { TrackPlaybackResponse } from '../../api/types';
|
||||
import TrackPage from './TrackPage';
|
||||
import { ROUTER_FUTURE } from '../routing/routerConfig';
|
||||
|
||||
const mocks = vi.hoisted(() => ({ trackPlayback: vi.fn(), reverseGeocode: vi.fn(), vehicles: vi.fn() }));
|
||||
vi.mock('../../api/client', () => ({ api: mocks }));
|
||||
vi.mock('../map/TrackMap', () => ({ TrackMap: ({ activeIndex, followDurationMs }: { activeIndex: number; followDurationMs: number }) => <div data-testid="track-map" data-active-index={activeIndex} data-follow-duration={followDurationMs} /> }));
|
||||
vi.mock('../map/TrackMap', () => ({ TrackMap: ({ activeIndex, followDurationMs, points }: { activeIndex: number; followDurationMs: number; points: unknown[] }) => <div data-testid="track-map" data-active-index={activeIndex} data-follow-duration={followDurationMs} data-point-count={points.length} /> }));
|
||||
|
||||
const track = {
|
||||
vin: 'LTEST000000000001', plate: '粤A12345', total: 3, truncated: false, sampled: false, asOf: '2026-07-15T08:00:00Z',
|
||||
@@ -38,6 +38,34 @@ beforeEach(() => {
|
||||
});
|
||||
afterEach(() => { cleanup(); Object.values(mocks).forEach((mock) => mock.mockReset()); });
|
||||
|
||||
function TrackNavigationHarness() {
|
||||
const navigate = useNavigate();
|
||||
return <><button type="button" onClick={() => navigate('/tracks')}>清空轨迹路由</button><button type="button" onClick={() => navigate(-1)}>后退轨迹路由</button><button type="button" onClick={() => navigate(1)}>前进轨迹路由</button><TrackPage /></>;
|
||||
}
|
||||
|
||||
test('keeps committed track criteria authoritative to same-route navigation and browser history', async () => {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
render(<QueryClientProvider client={client}><MemoryRouter future={ROUTER_FUTURE} initialEntries={['/tracks?keyword=LTEST000000000001&dateFrom=2026-07-15T00:00&dateTo=2026-07-15T23:59']}><TrackNavigationHarness /></MemoryRouter></QueryClientProvider>);
|
||||
|
||||
expect((await screen.findAllByText('粤A12345')).length).toBeGreaterThan(0);
|
||||
expect(screen.getByTestId('track-map')).toHaveAttribute('data-point-count', '3');
|
||||
expect(screen.getByRole('textbox', { name: '搜索轨迹车辆' })).toHaveValue('LTEST000000000001');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空轨迹路由' }));
|
||||
expect(await screen.findByText('先选择车辆,再开始轨迹回放')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('track-map')).toHaveAttribute('data-point-count', '0');
|
||||
expect(screen.getByRole('textbox', { name: '搜索轨迹车辆' })).toHaveValue('');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '后退轨迹路由' }));
|
||||
expect((await screen.findAllByText('粤A12345')).length).toBeGreaterThan(0);
|
||||
expect(screen.getByTestId('track-map')).toHaveAttribute('data-point-count', '3');
|
||||
expect(screen.getByRole('textbox', { name: '搜索轨迹车辆' })).toHaveValue('LTEST000000000001');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '前进轨迹路由' }));
|
||||
expect(await screen.findByText('先选择车辆,再开始轨迹回放')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('track-map')).toHaveAttribute('data-point-count', '0');
|
||||
});
|
||||
|
||||
test('renders a map-first replay workspace and connects stop, event, and panel interactions', async () => {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
const view = render(<QueryClientProvider client={client}><MemoryRouter future={ROUTER_FUTURE} initialEntries={['/tracks?keyword=LTEST000000000001&dateFrom=2026-07-15T00:00&dateTo=2026-07-15T23:59']}><TrackPage /></MemoryRouter></QueryClientProvider>);
|
||||
|
||||
@@ -188,14 +188,17 @@ const SegmentRail = memo(function SegmentRail({ track, onSelectIndex }: { track:
|
||||
export default function TrackPage() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const fallback = useMemo(defaultTrackWindow, []);
|
||||
const initialDraft = useMemo<Draft>(() => ({
|
||||
keyword: searchParams.get('vin') || searchParams.get('keyword') || '',
|
||||
dateFrom: searchParams.get('dateFrom') || fallback.dateFrom,
|
||||
dateTo: searchParams.get('dateTo') || fallback.dateTo,
|
||||
protocol: searchParams.get('protocol') || ''
|
||||
}), []);
|
||||
const [draft, setDraft] = useState(initialDraft);
|
||||
const [criteria, setCriteria] = useState(initialDraft);
|
||||
const routeKey = searchParams.toString();
|
||||
const criteria = useMemo<Draft>(() => {
|
||||
const params = new URLSearchParams(routeKey);
|
||||
return {
|
||||
keyword: params.get('vin') || params.get('keyword') || '',
|
||||
dateFrom: params.get('dateFrom') || fallback.dateFrom,
|
||||
dateTo: params.get('dateTo') || fallback.dateTo,
|
||||
protocol: params.get('protocol') || ''
|
||||
};
|
||||
}, [fallback, routeKey]);
|
||||
const [draft, setDraft] = useState(criteria);
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [playing, setPlaying] = useState(false);
|
||||
const [playbackSpeed, setPlaybackSpeed] = useState<PlaybackSpeed>(1);
|
||||
@@ -224,6 +227,7 @@ export default function TrackPage() {
|
||||
const currentAddressPoint = useMemo(() => trackAddressCoordinate(current?.longitude, current?.latitude), [current?.latitude, current?.longitude]);
|
||||
const [addressPoint, setAddressPoint] = useState<TrackAddressCoordinate>();
|
||||
|
||||
useEffect(() => { setDraft(criteria); }, [criteria]);
|
||||
useEffect(() => {
|
||||
if (playing || !currentAddressPoint) return;
|
||||
const timer = window.setTimeout(() => setAddressPoint(currentAddressPoint), TRACK_ADDRESS_SETTLE_MS);
|
||||
@@ -264,7 +268,6 @@ export default function TrackPage() {
|
||||
const keyword = draft.keyword.trim();
|
||||
if (!keyword) return;
|
||||
const next = { ...draft, keyword };
|
||||
setCriteria(next);
|
||||
const url = new URLSearchParams({ keyword });
|
||||
if (next.dateFrom) url.set('dateFrom', next.dateFrom);
|
||||
if (next.dateTo) url.set('dateTo', next.dateTo);
|
||||
|
||||
Reference in New Issue
Block a user