From e9393e9e6cb1b419d25b509616225d511c5fc7fb Mon Sep 17 00:00:00 2001 From: Maurice Date: Tue, 22 Sep 2026 00:45:58 +0000 Subject: [PATCH] fix(help): a duplicated trip outlived its guide and broke another screen The duplicate-trip guide dropped its copy by position, keeping whatever the trips endpoint happened to answer first. The copy survived, and three files later the journey dialog offered two entries starting "Weekend in Lisbon" and the create-journey guide could not say which one it meant. The copy is now dropped by name and the delete is checked, and the journey dialog picks its trip by accessible name rather than by a substring another trip shares. Each file passed on its own before this; only the whole suite in one run showed it. --- client/e2e/help/dashboard.guide.ts | 14 ++++++++++---- client/e2e/help/journey.guide.ts | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/client/e2e/help/dashboard.guide.ts b/client/e2e/help/dashboard.guide.ts index 84100dbc5..32df705a7 100644 --- a/client/e2e/help/dashboard.guide.ts +++ b/client/e2e/help/dashboard.guide.ts @@ -164,11 +164,17 @@ const SCRIPTS: Record = { }, ], cleanup: async p => { - // Drop the copy over the API so the grid is back to the seed for the next guide. + // Drop the copy over the API so the grid is back to the seed for the next + // guide. By title, not by position: the list came back in an order that + // left the copy standing, and a trip nobody expected then broke a guide + // three files later, in a screen that has nothing to do with this one. const res = await p.request.get('/api/trips') - const { trips } = (await res.json()) as { trips: { id: number; title: string }[] } - const copies = trips.filter(t => t.title.startsWith(LISBON)).slice(1) - for (const t of copies) await p.request.delete(`/api/trips/${t.id}`) + const body = (await res.json()) as { trips?: { id: number; title: string }[] } | { id: number; title: string }[] + const trips = Array.isArray(body) ? body : (body.trips ?? []) + for (const t of trips.filter(x => x.title !== LISBON && x.title.startsWith(LISBON))) { + const dropped = await p.request.delete(`/api/trips/${t.id}`) + if (!dropped.ok()) throw new Error(`could not drop the copy "${t.title}": ${dropped.status()}`) + } }, }, diff --git a/client/e2e/help/journey.guide.ts b/client/e2e/help/journey.guide.ts index 3db30a99a..85e44b43b 100644 --- a/client/e2e/help/journey.guide.ts +++ b/client/e2e/help/journey.guide.ts @@ -147,7 +147,9 @@ const SCRIPTS: Record = { act: async p => { await typeInto(p, dialog(p).locator('input').first(), 'Lisbon weekend') await typeInto(p, dialog(p).locator('input').nth(1), 'Two days of tiles and custard tarts') - await dialog(p).getByRole('checkbox').filter({ hasText: 'Weekend in Lisbon' }).click() + // By accessible name, not by a substring: a copy of the trip made by + // another screen's guide is also "Weekend in Lisbon something". + await dialog(p).getByRole('checkbox', { name: /^Weekend in Lisbon \d+ days/ }).click() await beat(p, 400) }, },