diff --git a/DECISIONS.md b/DECISIONS.md index 1298155..72ab8dc 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1281,3 +1281,7 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` ## Step 12.4 - **"Close the page" is a real page close**; the return is a fresh page in the same browser session, as when reopening the installed app. + +## Step 12.5 + +- **The Mars window is computed, not waited for**: the test finds the next date the Clipper can reach Mars and fly on, and fast-forwards to it. diff --git a/apps/web/e2e/12-5-discovery.e2e.ts b/apps/web/e2e/12-5-discovery.e2e.ts new file mode 100644 index 0000000..fbba6cc --- /dev/null +++ b/apps/web/e2e/12-5-discovery.e2e.ts @@ -0,0 +1,51 @@ +import { expect, test } from "@playwright/test"; +import { + addCredits, + advanceTo, + board, + dismissLogbook, + logbook, + nextMarsWindow, + playToDeal, + serverNow, + state, + tryDispatch, +} from "./support"; + +test.describe("end to end (Phase 12)", () => { + test("12.5: a first contact to Mars discovers it, opens its board and lets you lease there", async ({ + page, + }) => { + const owner = await playToDeal(page); + const clipper = owner.ships.find((s) => s.modelId === "clipper")!; + const veteran = owner.pilots.find((p) => p.isVeteran)!; + + // A date when the Clipper can reach Mars, Long Haul for the trip, and fuel money. + await advanceTo(page, nextMarsWindow(await serverNow(page))); + await page.goto("/pilots"); + const raise = page.getByRole("button", { name: `Raise Long Haul for ${veteran.name}` }); + while ((await state(page)).pilots.find((p) => p.id === veteran.id)!.skillPointsAvailable > 0) { + await raise.click(); + } + await addCredits(page, 100_000); + + // The board offers a first contact the Clipper can fly (decision 0.5.85). + const offer = (await board(page, "earth")).contracts.find( + (c) => c.firstContact && c.destinationId === "mars", + ); + expect(offer, "a first contact to Mars on the Earth board").toBeDefined(); + const flight = await tryDispatch(page, offer!.id, clipper.id, veteran.id); + expect(flight, "the Clipper and veteran can take it").not.toBeNull(); + await advanceTo(page, flight!.arrivalAt); + await page.goto("/"); + await expect(logbook(page)).toContainText("Discovered Mars!"); + await dismissLogbook(page); + + // Mars is discovered on the Locations screen and can be leased; its board is open without a bay (CR-002). + await page.goto("/locations"); + await expect(page.getByRole("button", { name: "Lease bay at Mars" })).toBeEnabled(); + const marsBoard = await page.request.get("/api/locations/mars/board"); + expect(marsBoard.ok()).toBe(true); + expect((await state(page)).bays.map((b) => b.locationId)).toEqual(["earth"]); + }); +}); diff --git a/memory-bank/progress.md b/memory-bank/progress.md index b5947c6..9394063 100644 --- a/memory-bank/progress.md +++ b/memory-bank/progress.md @@ -310,5 +310,5 @@ Spec: `memory-bank/change-requests/CR-013-veterans-clipper.md` (received as "CR- - [x] **Step 12.2 — Revisit the tutorial economy test.** The amended Step 2.5 check ("the tutorial share plus starting credits covers fuel for three Courier Earth→Moon runs") no longer assumes the lowest-paying tutorial contract: the simulator records the tutorial share actually earned and the credits at the deal, and `packages/sim/test/balance.test.ts` checks, in every seeded run, four tutorial runs, credits at the deal = starting credits + share earned, and at least three Courier Earth→Moon fuel loads. The placeholder test left `packages/content/test/config.test.ts` (content can't import the sim). Also added `test/first-contact-fit.test.ts` for decision 0.5.85 (Step 12.1): every Earth board over four hours offers a first contact to Mars that the deal's Clipper crew can take, and none once Mars is discovered. - [x] **Step 12.3 — End-to-end: tutorial to first ship.** Playwright now also starts the real API server (port 3135) on `TEST_DATABASE_URL`, migrated first, next to the production web build with `/api` proxied to it; tests run one at a time because the developer clock is shared. `e2e/support.ts` drives play: start a company, fly the tutorial board, shake on the deal, dispatch from a board through the sheet, dismiss the logbook, and fast-forward with the developer routes (CR-011). Test (`e2e/12-3-first-ship.e2e.ts`): guest → four tutorial runs in the UI → deal → the state has the Courier (avatar) and Clipper (veteran) at Earth, one Earth bay, the 66,600 cr loan and no tutorial → one contract dispatched in the dispatch sheet and resolved, its logbook entry shows the repayment and the loan went down. - [x] **Step 12.4 — End-to-end: offline progress.** Test (`e2e/12-4-offline-progress.e2e.ts`): dispatch a contract, close the page, move the server clock past the arrival, open a new page: the logbook shows the delivery, credits went up by exactly the delivery's net payout, and the ship is at the destination. -- [ ] Step 12.5 — End-to-end: discovery +- [x] **Step 12.5 — End-to-end: discovery.** Test (`e2e/12-5-discovery.e2e.ts`): after the deal, the clock moves to a date when a base Clipper can fly Earth → Mars (computed with the sim, so the test doesn't depend on today's planets); the veteran's points go into Long Haul in the Pilots screen; the Earth board offers a first contact to Mars the Clipper can take (decision 0.5.85); on arrival the logbook says "Discovered Mars!", the Locations screen offers "Lease bay at Mars", and Mars's board loads with no bay there (CR-002). - [ ] Step 12.6 — End-to-end: pilot progression