fix: v0.10.1 — dispatch pickers independent per accepted contract (placeholder default, no first-eligible auto-fallback; stale-select fix via explicit placeholder option)
This commit is contained in:
@@ -261,3 +261,85 @@ test('market buy/sell render with price and payout previews from the catalog in
|
||||
await expect(page.getByTestId('market-sell-payout')).toContainText(eur(payout));
|
||||
await expect(page.getByTestId('market-sell')).toBeVisible();
|
||||
});
|
||||
|
||||
test('dispatch pickers are independent per contract — selecting one does not leak into the others (v0.10.1)', async ({ page }) => {
|
||||
test.setTimeout(240_000); // two short flights at scale 60 plus UI steps
|
||||
|
||||
// Self-heal first: a previous interrupted run may have left plane-starter mid-flight or at
|
||||
// another airport (same pattern as the dispatch-loop test above).
|
||||
let body = await getState(page);
|
||||
const starter0 = body.planes.find((p) => p.id === 'plane-starter');
|
||||
expect(starter0).toBeDefined();
|
||||
if (starter0!.status === 'flying') {
|
||||
await postSim(page, { timeScale: SCALE });
|
||||
await expect
|
||||
.poll(async () => (await getState(page)).planes.find((p) => p.id === 'plane-starter')?.status === 'available', {
|
||||
timeout: 90_000,
|
||||
message: 'waiting for an in-flight plane-starter to land',
|
||||
})
|
||||
.toBe(true);
|
||||
body = await getState(page);
|
||||
}
|
||||
if (body.planes.find((p) => p.id === 'plane-starter')!.locationIcao !== HUB) {
|
||||
const from = body.planes.find((p) => p.id === 'plane-starter')!.locationIcao;
|
||||
await flyViaApi(page, from, HUB);
|
||||
}
|
||||
|
||||
// Two hook contracts, both originating at EDDF on the shortest route.
|
||||
const nearest = await nearestToHub(page);
|
||||
const a = await createContract(page, HUB, nearest.icao);
|
||||
const b = await createContract(page, HUB, nearest.icao);
|
||||
|
||||
await page.goto('/');
|
||||
// Accept BOTH through the UI buttons.
|
||||
for (const c of [a, b]) {
|
||||
const row = page.locator(`li[data-testid="open-contract-${c.id}"]`);
|
||||
await expect(row).toBeVisible({ timeout: 15_000 });
|
||||
await page.getByTestId(`accept-${c.id}`).click();
|
||||
}
|
||||
|
||||
const accA = page.getByTestId(`accepted-contract-${a.id}`);
|
||||
const accB = page.getByTestId(`accepted-contract-${b.id}`);
|
||||
await expect(accA).toBeVisible({ timeout: 10_000 });
|
||||
await expect(accB).toBeVisible();
|
||||
|
||||
// Both dispatch pickers render with the placeholder default — nothing preselected (v0.10.1)…
|
||||
const pickerA = page.getByTestId(`dispatch-plane-${a.id}`);
|
||||
const pickerB = page.getByTestId(`dispatch-plane-${b.id}`);
|
||||
await expect(pickerA).toBeVisible();
|
||||
await expect(pickerB).toBeVisible();
|
||||
await expect(pickerA).toHaveValue('');
|
||||
await expect(pickerB).toHaveValue('');
|
||||
await expect(pickerA.locator('option[value=""]')).toHaveText(/select a plane/i);
|
||||
|
||||
// …and the Dispatch buttons stay disabled until a valid plane is chosen.
|
||||
await expect(page.getByTestId(`dispatch-${a.id}`)).toBeDisabled();
|
||||
await expect(page.getByTestId(`dispatch-${b.id}`)).toBeDisabled();
|
||||
|
||||
// Select plane-starter in contract A's picker → contract B's picker must STILL show the
|
||||
// placeholder (the v0.10.1 regression: selections used to appear shared across rows).
|
||||
await pickerA.selectOption('plane-starter');
|
||||
await expect(pickerA).toHaveValue('plane-starter');
|
||||
await expect(pickerB).toHaveValue('');
|
||||
|
||||
// Dispatch A with the selected plane → it goes 'flying' and its row shows the in-flight…
|
||||
await page.getByTestId(`dispatch-${a.id}`).click();
|
||||
await expect(page.getByTestId(`contract-inflight-${a.id}`)).toBeVisible({ timeout: 10_000 });
|
||||
body = await getState(page);
|
||||
expect(body.planes.find((p) => p.id === 'plane-starter')!.status).toBe('flying');
|
||||
|
||||
// …indicator, while B remains accepted with its own independent picker on the placeholder.
|
||||
await expect(accB).toBeVisible();
|
||||
await expect(pickerB).toHaveValue('');
|
||||
await expect(page.getByTestId(`dispatch-${b.id}`)).toBeDisabled();
|
||||
|
||||
// Restore: let A's flight finish and fly plane-starter home so later specs start clean.
|
||||
await postSim(page, { timeScale: SCALE });
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const p = (await getState(page)).planes.find((x) => x.id === 'plane-starter');
|
||||
return !!p && p.status === 'available' && p.locationIcao === nearest.icao;
|
||||
}, { timeout: 90_000, message: `waiting for arrival at ${nearest.icao} (scale 60)` })
|
||||
.toBe(true);
|
||||
await flyViaApi(page, nearest.icao, HUB);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user