From 15c1a5ae0670dbcd34e7030348696f978c5edaa7 Mon Sep 17 00:00:00 2001 From: Maurice Date: Sun, 6 Sep 2026 23:34:59 +0200 Subject: [PATCH] test(mobile): seed the store the location hint is actually read from useLocationBias reads useTripStore; the sheet's harness only ever built a planner prop. So the hook saw an empty store, sent no hint, and the one case that asserts a box went red while its three siblings passed vacuously - they expect undefined, which an empty store produces no matter what they seed. capturedBias now seeds places, assignments and selectedDayId the way the running app has them, which puts all four cases back to work. The 500km case is retargeted from Tokyo/Sapporo to Tokyo/Nagoya: 264km across, biased under the old diagonal rule and dropped under the 60km radius one, so it guards the rule that actually shipped. A new 029b pins the day-first precedence - a trip too wide to bias still hints at the day being planned. --- .../unit/mobile/trip/MPlaceEditSheet.test.tsx | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/client/tests/unit/mobile/trip/MPlaceEditSheet.test.tsx b/client/tests/unit/mobile/trip/MPlaceEditSheet.test.tsx index 7965daea5..0119b0671 100644 --- a/client/tests/unit/mobile/trip/MPlaceEditSheet.test.tsx +++ b/client/tests/unit/mobile/trip/MPlaceEditSheet.test.tsx @@ -5,7 +5,9 @@ import type { TripPlanner } from '../../../../src/mobile/screens/trip/MTripShell import type { Assignment, Category, Place } from '../../../../src/types' import { buildPlanner } from '../../../helpers/mobileTrip' import { useAddonStore } from '../../../../src/store/addonStore' +import { useTripStore } from '../../../../src/store/tripStore' import { server } from '../../../helpers/msw/server' +import { resetAllStores, seedStore } from '../../../helpers/store' import { fireEvent, render, screen, waitFor } from '../../../helpers/render' // FE-MOB-PLEDIT-001 to FE-MOB-PLEDIT-024, plus FE-MOB-PLEDIT-033 to -035 @@ -38,6 +40,7 @@ const submit = () => screen.getByRole('button', { name: /^(common\.add|common\.s describe('MPlaceEditSheet', () => { beforeEach(() => { + resetAllStores() server.use( http.post('/api/maps/search', () => HttpResponse.json({ source: 'osm', @@ -354,32 +357,57 @@ describe('MPlaceEditSheet', () => { expect(screen.queryByText('ticket.png')).not.toBeInTheDocument() }) - /** Types into the search row and returns the bias the autocomplete request carried. */ - async function capturedBias(places: Place[]) { + /** + * Types into the search row and returns the bias the autocomplete request + * carried. The hint comes from useLocationBias, which reads the trip store, + * not the planner prop, so both are seeded the way the running app has them. + */ + async function capturedBias(places: Place[], day?: { id: number; placeIds: number[] }) { const bodies: Record[] = [] server.use(http.post('/api/maps/autocomplete', async ({ request }) => { bodies.push(await request.json() as Record) return HttpResponse.json({ source: 'osm', suggestions: [] }) })) + seedStore(useTripStore, { + places, + assignments: day ? { [String(day.id)]: day.placeIds.map(id => ({ place_id: id })) } : {}, + selectedDayId: day?.id ?? null, + }) setup({ places }) fireEvent.change(screen.getByPlaceholderText('places.mapsSearchPlaceholder'), { target: { value: 'ueno' } }) await waitFor(() => expect(bodies).toHaveLength(1)) return bodies[0].locationBias } - it('FE-MOB-PLEDIT-029: biases the maps search on the trip bounding box', async () => { + it('FE-MOB-PLEDIT-029: biases the maps search on the trip box while the trip fits one region', async () => { const places = [ { id: 1, name: 'A', lat: 35.6, lng: 139.7 }, { id: 2, name: 'B', lat: 35.8, lng: 139.9 }, { id: 3, name: 'C', lat: null, lng: null }, ] as unknown as Place[] + // 25km across and no day open, so the trip is the best hint there is. expect(await capturedBias(places)).toEqual({ low: { lat: 35.6, lng: 139.7 }, high: { lat: 35.8, lng: 139.9 } }) }) - it('FE-MOB-PLEDIT-030: drops the bias for a trip that spans more than 500 km', async () => { + it('FE-MOB-PLEDIT-029b: narrows the bias to the open day when the trip is too wide for one', async () => { + const places = [ + { id: 1, name: 'Ueno', lat: 35.71, lng: 139.77 }, + { id: 2, name: 'Asakusa', lat: 35.71, lng: 139.8 }, + { id: 3, name: 'Nagoya', lat: 35.18, lng: 136.91 }, + ] as unknown as Place[] + // The trip reaches Nagoya and is dropped, but the day being planned still + // gets a hint. That is what preferring the day buys. + expect(await capturedBias(places, { id: 7, placeIds: [1, 2] })).toEqual({ + low: { lat: 35.71, lng: 139.77 }, high: { lat: 35.71, lng: 139.8 }, + }) + }) + + it('FE-MOB-PLEDIT-030: drops the bias for a trip that outgrows one region', async () => { + // Tokyo to Nagoya, 264km across: inside the old 500km diagonal rule, outside + // the 60km radius one. A box that wide has its centre in open country. const places = [ { id: 1, name: 'Tokyo', lat: 35.68, lng: 139.76 }, - { id: 2, name: 'Sapporo', lat: 43.06, lng: 141.35 }, + { id: 2, name: 'Nagoya', lat: 35.18, lng: 136.91 }, ] as unknown as Place[] expect(await capturedBias(places)).toBeUndefined() })