diff --git a/CHANGELOG.md b/CHANGELOG.md index b316a7b..cae7e87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Tests: e2e — new `e2e/relocation.spec.ts` (serial mode, SCALE=1000, self-heal fly-home in afterEach like actions.spec.ts): market-row test ensures plane-starter grounded at the hub via API, picks it + the nearest non-hub airport (shortest leg) and asserts `/api/state` shows `flying` with that destIcao after clicking Relocate; popup test clicks the isolated LFRS marker (projected-center pattern from map.spec.ts), asserts the select lists "ATR 72-600 — EDDF" and the button is disabled until a plane is picked, then relocates via the popup. Marker-size regression gate = the existing map.spec.ts click tests keep passing - Verified: `tsc --noEmit` clean; unit suite green locally (no lib/ changes — flyPlane's zero-package case already covered by actions.test.ts); e2e not run locally by design — CI verifies against an isolated stack - **Fix (CI run #50): POPUP_AIRPORT scoping in the popup relocation e2e.** The LFRS marker click passed `POPUP_AIRPORT` into a `page.evaluate(() => …)` callback that runs in the BROWSER, where Node-scope constants don't exist — deterministic `ReferenceError: POPUP_AIRPORT is not defined` (relocation.spec.ts popup test, both attempts of run #50). The constant is now passed as an evaluate argument (`page.evaluate(({lon, lat}) => …, POPUP_AIRPORT)`); the other evaluate in the file only touches browser globals and needed no change. Test-only — no app code touched +- **Fix (CI run #51): strict-mode locator in the popup relocation e2e.** `expect(planeSel.locator('option')).toContainText(…)` resolved to BOTH options (placeholder + plane) → strict mode violation (relocation.spec.ts popup test, both attempts of run #51; the app rendered correctly). The assertion now targets `option[value="plane-starter"]` specifically with `toHaveText`. Test-only — no app code touched ## v0.17.0 — 2026-09-19 14:49 - **Bottom-right toasts for action errors (ISS-008).** Error messages like "insufficient funds: a ATR 72-600 costs 200000, you have 62721" now appear as toasts in the bottom-right corner — new `lib/useToasts.ts` hook (`useToasts() → {toasts, push(kind, msg), dismiss(id)}`, auto-dismiss after ~5 s, queue capped at 4 dropping the oldest; pure core `pushToast` unit-tested) and new `components/Toasts.tsx` `` (fixed container `.toasts`, items `[data-testid="toast"]` with class `toast toast-error|toast-info` + a × dismiss button). Wired into BOTH error paths: `RightPane.runAction`'s catch now calls the shell's `onError` in addition to keeping the inline `[data-testid="right-error"]` pane error, and `LeftPane.applySimControls`'s catch (previously console.error-only) reports "Failed to update time controls (…)" through the same callback. The shell (`app/page.tsx`) owns the hook and renders the stack; CSS in `app/globals.css` diff --git a/e2e/relocation.spec.ts b/e2e/relocation.spec.ts index d69e798..3e21af9 100644 --- a/e2e/relocation.spec.ts +++ b/e2e/relocation.spec.ts @@ -168,7 +168,9 @@ test('airport popup offers Relocate options for grounded planes', async ({ page // The Relocate row: a select of grounded planes + the button (disabled until one is picked). const planeSel = page.getByTestId('airport-popup-plane'); await expect(planeSel).toBeVisible(); - await expect(planeSel.locator('option')).toContainText(/ATR 72-600 — EDDF/); + // Target THE PLANE OPTION specifically — locator('option') also matches the placeholder and + // trips strict mode (CI run #51). + await expect(planeSel.locator('option[value="plane-starter"]')).toHaveText(/ATR 72-600 — EDDF/); const goBtn = page.getByTestId('airport-popup-relocate'); await expect(goBtn).toBeDisabled(); // placeholder selected