Two-plane load fix + e2e coverage (ISS-055, v0.31.0)
CI / build + unit + e2e (pull_request) Failing after 8m13s
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:
@@ -466,14 +466,16 @@ export default function LeftPane({ state, loading, error, onRefresh, applySnapsh
|
||||
add control reusing this pane's already-fetched airport options (no second fetch). */}
|
||||
<div className="queue-subsection">
|
||||
<span className="queue-heading">Queue</span>
|
||||
{/* ISS-055 (v0.31.0): testids scoped by plane id — with two on-board blocks the
|
||||
unscoped ids duplicated in the DOM and broke Playwright strict mode. */}
|
||||
{plane.queue.map((icao, i) => (
|
||||
<div key={`${icao}-${i}`} data-testid={`queue-leg-${i}`} className="queue-row">
|
||||
<div key={`${icao}-${i}`} data-testid={`queue-leg-${plane.id}-${i}`} className="queue-row">
|
||||
<span className="contract-route">
|
||||
{airportOptions?.find((a) => a.icao === icao)?.name ?? icao} ({icao})
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
data-testid={`queue-cancel-${i}`}
|
||||
data-testid={`queue-cancel-${plane.id}-${i}`}
|
||||
className="pane-btn"
|
||||
disabled={actionsBusy}
|
||||
onClick={() => void runAction(`/api/planes/${plane.id}/queue/cancel`, { index: i })}
|
||||
@@ -484,7 +486,7 @@ export default function LeftPane({ state, loading, error, onRefresh, applySnapsh
|
||||
))}
|
||||
<div className="market-row">
|
||||
<select
|
||||
data-testid="queue-add-dest"
|
||||
data-testid={`queue-add-dest-${plane.id}`}
|
||||
aria-label="Airport to add to the flight queue"
|
||||
value={queueAddDestIcao ?? ''}
|
||||
onChange={(e) => setQueueAddDestIcao(e.target.value || null)}
|
||||
@@ -498,7 +500,7 @@ export default function LeftPane({ state, loading, error, onRefresh, applySnapsh
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="queue-add"
|
||||
data-testid={`queue-add-${plane.id}`}
|
||||
className="pane-btn"
|
||||
disabled={actionsBusy || queueAddDestIcao === null}
|
||||
onClick={() => {
|
||||
|
||||
@@ -49,8 +49,9 @@ export function loadEligiblePlanes(state: StateSnapshot, pkg: PackageState): Pla
|
||||
// Load controls for one open package: a single Load button when exactly one plane
|
||||
// is eligible (it acts on that plane directly), a small plane picker + Load when
|
||||
// several are, and a disabled button with the reason otherwise. Each row owns its
|
||||
// selection in local state and defaults to the "Select a plane…" placeholder —
|
||||
// never preselecting — so rows stay visibly independent (v0.10.1 pattern).
|
||||
// selection in local state; ISS-055 (v0.31.0): the multi-plane path PRESELECTS the
|
||||
// first eligible plane so Load is one-click out of the box (matching the single-plane
|
||||
// UX) while the picker still allows choosing a different plane.
|
||||
function LoadControls({
|
||||
pkg,
|
||||
eligible,
|
||||
@@ -63,8 +64,9 @@ function LoadControls({
|
||||
onLoad: (planeId: string) => void;
|
||||
}) {
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
// The user's pick while it stays eligible, else nothing (placeholder).
|
||||
const effective = eligible.find((p) => p.id === selectedId) ?? null;
|
||||
// ISS-055 (v0.31.0): the user's pick while it stays eligible, else the FIRST eligible plane —
|
||||
// Load is enabled and one-click whenever ≥1 plane qualifies; the picker still allows a different pick.
|
||||
const effective = eligible.find((p) => p.id === selectedId) ?? eligible[0] ?? null;
|
||||
|
||||
if (eligible.length === 1) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user