v0.18.0 — ISS-010 relocate empty planes + bigger airport markers + popup options #20
@@ -8,6 +8,7 @@
|
||||
- No server or OpenAPI changes — both surfaces reuse the existing fly endpoint (validations unchanged: 404 unknown plane / 409 flying or insufficient fuel / 400 unknown ICAO, strict unknown-field rejection kept)
|
||||
- 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
|
||||
|
||||
## 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` `<ToastStack>` (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`
|
||||
|
||||
@@ -151,13 +151,14 @@ test('airport popup offers Relocate options for grounded planes', async ({ page
|
||||
{ timeout: 15_000 },
|
||||
).toBe(true);
|
||||
|
||||
// Click the LFRS marker (projected center — same pattern as e2e/map.spec.ts).
|
||||
const pt = await page.evaluate(() => {
|
||||
// Click the LFRS marker (projected center — same pattern as e2e/map.spec.ts). The constant is
|
||||
// passed AS AN ARGUMENT: the evaluate callback runs in the browser, where Node-scope values don't exist.
|
||||
const pt = await page.evaluate(({ lon, lat }) => {
|
||||
const map = (window as any).__flightMap;
|
||||
const p = map.project([POPUP_AIRPORT.lon, POPUP_AIRPORT.lat]);
|
||||
const p = map.project([lon, lat]);
|
||||
const rect = map.getContainer().getBoundingClientRect();
|
||||
return { x: rect.left + p.x, y: rect.top + p.y };
|
||||
});
|
||||
}, POPUP_AIRPORT);
|
||||
await page.mouse.click(pt.x, pt.y);
|
||||
|
||||
const popup = page.getByTestId('airport-popup');
|
||||
|
||||
Reference in New Issue
Block a user