diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c093a..061482c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - **UI badge.** Open-package rows (`components/RightPane.tsx`) and on-board rows (`components/LeftPane.tsx`) show a sky-blue "Priority" pill next to the route when the package has a special status (new `.special-badge` class, `package-special-{id}` testid); label via new `formatSpecialLabel` in `lib/format.ts` - **Test hooks & spec.** POST /api/test/create-package accepts `special` (string or null; omitted → forced null so existing e2e reward/rep assertions stay deterministic — documented in the route header), and expire-package passes `special: null` explicitly. OpenAPI PackageState gains optional `special: string | null` - **Tests.** New unit tests: registry application (reward ×multiplier, deadline ×scale, rep bonus at delivery), pickSpecial distribution with a fixed RNG, forced-value draw skip, and removing an entry cleanly disabling the status; existing reward/deadline assertions scoped for special packages. E2E: new right-pane test forces `special: 'priority'` via the hook and asserts the row shows the "Priority" badge +- **E2E self-heal hardening.** The `flyHomeViaApi` helper in `e2e/right-pane.spec.ts` now abandons any leftover loaded/expired package bound to plane-starter once it's back at EDDF (the "open packages render" test leaves a 4 t package on board, which made later hook-package loads hit the payload check), and both that helper and `e2e/slow-on-landing.spec.ts`'s equivalent now refuel-and-retry the repositioning flight when it fails on insufficient fuel (modeled on `e2e/two-planes.spec.ts`) ## v0.36.0 — 2026-09-21 08:45 - **Refuel-for-flight now buys 150% of the required fuel for the leg (ISS-071).** `refuelPlane` mode `'forFlight'` (`lib/game/actions.ts`) tops the tank up to `min(maxFuel, max(current fuel, 1.5 × required))` instead of exactly the requirement — a margin so burn variance doesn't strand planes at the far end. The "does not fit a full tank" 409 guard now compares against the weather-adjusted requirement (see below). No UI change: the per-leg Refuel button has no amount preview, and the left-pane "Refuel to full" row is unaffected diff --git a/e2e/right-pane.spec.ts b/e2e/right-pane.spec.ts index 3e10b43..8263f96 100644 --- a/e2e/right-pane.spec.ts +++ b/e2e/right-pane.spec.ts @@ -199,8 +199,13 @@ async function flyHomeViaApi(page: Page): Promise { // ISS-041: the landing above paused the sim — setScale clears pause so the return leg // fast-forwards instead of taking real-time hours. await setScale(page, SCALE); - const res = await page.request.post('/api/planes/plane-starter/fly', { data: { destIcao: HUB } }); - expect(res.status()).toBe(200); // repositioning needs no package (v0.12.0 manual flight) + let flyHome = await page.request.post('/api/planes/plane-starter/fly', { data: { destIcao: HUB } }); + if (!flyHome.ok()) { + // A long outbound leg can leave the tank too empty for the return — top up and retry. + expect((await page.request.post('/api/planes/plane-starter/refuel')).status()).toBe(200); + flyHome = await page.request.post('/api/planes/plane-starter/fly', { data: { destIcao: HUB } }); + } + expect(flyHome.status()).toBe(200); // repositioning needs no package (v0.12.0 manual flight) await expect .poll(async () => (await getState(page)).planes.find((p) => p.id === 'plane-starter')?.locationIcao === HUB, { timeout: 240_000, @@ -208,6 +213,14 @@ async function flyHomeViaApi(page: Page): Promise { }) .toBe(true); } + // Abandon leftover loaded/expired packages (the baseline is captured AFTER this cleanup). + const s1 = await getState(page); + for (const pkg of s1.packages) { + if (pkg.planeId === 'plane-starter' && (pkg.status === 'loaded' || pkg.status === 'expired')) { + const res = await page.request.post(`/api/packages/${pkg.id}/abandon`); + expect(res.ok()).toBeTruthy(); + } + } } test('open packages render with names, reward and deadline; Load is enabled at a package origin', async ({ page }) => { diff --git a/e2e/slow-on-landing.spec.ts b/e2e/slow-on-landing.spec.ts index ceab3df..c0004c8 100644 --- a/e2e/slow-on-landing.spec.ts +++ b/e2e/slow-on-landing.spec.ts @@ -80,8 +80,13 @@ async function flyHomeViaApi(page: Page): Promise { // ISS-057: the landing above slowed the sim to 1× — setScale restores 1000× (and records it as // lastSelectedTimeScale) so the return leg fast-forwards instead of taking real-time hours. await setScale(page, SCALE); - const res = await page.request.post(`/api/planes/${plane.id}/fly`, { data: { destIcao: HUB } }); - expect(res.ok()).toBeTruthy(); // repositioning needs no package (v0.12.0 manual flight) + let flyHome = await page.request.post(`/api/planes/${plane.id}/fly`, { data: { destIcao: HUB } }); + if (!flyHome.ok()) { + // A long outbound leg can leave the tank too empty for the return — top up and retry. + expect((await page.request.post(`/api/planes/${plane.id}/refuel`)).status()).toBe(200); + flyHome = await page.request.post(`/api/planes/${plane.id}/fly`, { data: { destIcao: HUB } }); + } + expect(flyHome.ok()).toBeTruthy(); // repositioning needs no package (v0.12.0 manual flight) await expect.poll(async () => ((await getState(page)).planes.find((p) => p.id === 'plane-starter')!.locationIcao), { timeout: 240_000 }).toBe(HUB); } }