mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(roadtrip): the manual-stop dialog looped on a hint rebuilt per render
Three things the first CI run found, all of them in the new tests rather than in what they cover. The dialog's search effect depended on the location hint object. Its own hook memoises, so nothing looped in the app, but the effect sets state on a query too short to ask about, and a caller whose hook hands back a fresh literal per render turns that pair into a render loop that never yields. The suite mocked it exactly that way, and the worker hung before a single test reported, which is what took the client coverage job past half an hour. The hint is three numbers, so the effect now turns on those and reads the value out of a ref when the request goes out. The mock hands back one object, the way the real hook does. The suite also installed fake timers in a beforeEach, which deadlocks against React's scheduler and Testing Library's own waiting. Every wait is a waitFor now, and the two cases that have to prove something did not happen sit out a real pause. The debounce boundary is no longer asserted against a wall clock, because a busy runner stretches any such window. The charging fixtures are pinned to a fixed instant and the service reads the real clock against a twenty-minute freshness window, so every answer through it was stale by construction and available came back null. Date.now is pinned for those tests, never the timers, since the requests carry an AbortSignal.timeout that has to keep running. And the unidentified-station test counted its two "no reliable data" lines before the answer landed: the price line already says it while the request is out, so the count settled on one and passed for the wrong reason.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { chargingLookupSchema } from '@trek/shared';
|
||||
import { ChargingService, empty } from '../../../src/nest/roadtrip/charging.service';
|
||||
import { ChargingLookupController, ChargingLookupDto } from '../../../src/nest/roadtrip/charging-lookup.controller';
|
||||
@@ -70,6 +70,21 @@ describe('Open charging data', () => {
|
||||
* difference is how the station is named.
|
||||
*/
|
||||
describe('Open charging data before the stop exists', () => {
|
||||
/**
|
||||
* The clock, pinned to the instant the fixtures above are written at.
|
||||
*
|
||||
* `normalizeCharging` takes the current time as an argument and the tests further up
|
||||
* pass it; the service does not, so it reads the real one, and its freshness window is
|
||||
* twenty minutes. Left alone, every answer that goes through the service is stale by
|
||||
* construction and `available` comes back null, which is the field this is here to
|
||||
* prove survives the trip from the registry to the dialog.
|
||||
*
|
||||
* Only `Date.now` is pinned, never the timers: the outbound requests carry an
|
||||
* `AbortSignal.timeout` that has to keep running.
|
||||
*/
|
||||
beforeEach(() => { vi.spyOn(Date, 'now').mockReturnValue(now); });
|
||||
afterEach(() => { vi.restoreAllMocks(); });
|
||||
|
||||
const answers = (tariffs: unknown) => vi.fn(async (url: string) => {
|
||||
if (url.includes('/sources')) return new Response(JSON.stringify({ items: [source] }));
|
||||
if (url.includes('/locations')) return new Response(JSON.stringify({ items: [station], total_count: 1 }));
|
||||
|
||||
Reference in New Issue
Block a user