Two-plane load fix + e2e coverage (ISS-055, v0.31.0)
CI / build + unit + e2e (pull_request) Failing after 8m13s

- LoadControls preselects the first eligible plane so Load is one-click with N planes
- LeftPane queue testids scoped by plane id (queue-leg/cancel/add[-dest]-{plane.id})
  — unscoped ids duplicated in the DOM with two on-board blocks
- new POST /api/test/add-cash hook (FLIGHT_TEST_HOOKS=1, default €1M) so e2e can
  afford a second plane; returns the full state snapshot
- new serial spec e2e/two-planes.spec.ts: load, parallel fly + ISS-057 slow/resume,
  refuel, relocate, per-plane queues with auto-chain, sell (6 tests)
- e2e/queue.spec.ts locators updated to the scoped testids
This commit is contained in:
2026-09-20 21:26:16 +00:00
parent 57cc6705f2
commit 1e3992f872
7 changed files with 663 additions and 14 deletions
+6 -5
View File
@@ -217,7 +217,8 @@ test('queue display + cancel via UI (ISS-043 part 2)', async ({ page }) => {
await expect(onboardRow, 'loaded package appears in the On board section').toBeVisible({ timeout: 15_000 });
// LeftPane's own /api/airports fetch populates the queue-add select — wait for it.
const addSelect = page.getByTestId('queue-add-dest');
// ISS-055 (v0.31.0): queue testids are scoped by plane id (the e2e fleet is one plane here).
const addSelect = page.getByTestId('queue-add-dest-plane-starter');
await expect(addSelect.locator(`option[value="${QUEUE}"]`)).toHaveCount(1, { timeout: 15_000 });
// START leg 1 via the UI (fly-to button in the on-board block).
@@ -233,19 +234,19 @@ test('queue display + cancel via UI (ISS-043 part 2)', async ({ page }) => {
await postSim(page, { paused: true }); // pause-sim pattern: deterministic window for UI clicks
// ADD a leg to the queue via the UI. The button is disabled until an airport is selected…
const addButton = page.getByTestId('queue-add');
const addButton = page.getByTestId('queue-add-plane-starter');
await expect(addButton).toBeDisabled();
await addSelect.selectOption(QUEUE);
await expect(addButton).toBeEnabled();
await addButton.click();
// …and the new leg appears as queue-leg-0 with its destination.
const legRow = page.getByTestId('queue-leg-0');
const legRow = page.getByTestId('queue-leg-plane-starter-0');
await expect(legRow, 'the queued leg appears in the Queue sub-section').toContainText(QUEUE, { timeout: 15_000 });
// CANCEL it via the UI and assert it's gone.
await page.getByTestId('queue-cancel-0').click();
await expect(page.getByTestId('queue-leg-0'), 'the cancelled leg is removed from the queue').toHaveCount(0, { timeout: 15_000 });
await page.getByTestId('queue-cancel-plane-starter-0').click();
await expect(page.getByTestId('queue-leg-plane-starter-0'), 'the cancelled leg is removed from the queue').toHaveCount(0, { timeout: 15_000 });
// Cleanup: resume + fast-forward to arrival at DEST (empty queue → plain landing), then fly home.
await setScale(page, SCALE);