Skip to content

Commit 41e0aa7

Browse files
committed
test(e2e): make reactor-layout spec project-independent
The spec hardcoded vanilla-Py reactor numbers (2 GW breeder → 3 reactors, 2×2 → 1), so it failed on a py-hard-mode active project where the breeder is 10 GW (→ 0.6 reactors) and heat has several producers behind a picker dialog instead of a single-candidate auto-add. Assert the INVARIANT instead: the breeder's neighbour_bonus (1 → ×3 heat at 2×2) is a Py constant, so read the base reactor count at runtime and check the 2×2 farm both shows '×3 heat' and drops the count to a third — true in any Py config. Also handle the multi-candidate heat picker (wait for it, pick the breeder) and drop an unused import. Closes #122
1 parent 994e442 commit 41e0aa7

1 file changed

Lines changed: 33 additions & 13 deletions

File tree

app/e2e/mut/reactor-layout.e2e.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import { expect, test } from "@playwright/test";
2-
import { createBlock, goalRateButton, goto } from "./helpers";
2+
import { createBlock, goalRateButton } from "./helpers";
33

44
/**
55
* Reactor neighbour bonus (#94): a heat block's reactor row carries a farm
6-
* layout chip. Picking 2×2 scales each reactor's heat output ×3 (Py's breeder
7-
* reactor has neighbour_bonus 1 = +100% per adjacent working reactor), so the
8-
* solved reactor count drops to a third — and the choice persists.
6+
* layout chip. Picking 2×2 gives each reactor 2 working neighbours → Py's
7+
* breeder reactor (neighbour_bonus 1 = +100% each) makes ×3 heat, so the solved
8+
* reactor count drops to a third — and the choice persists.
9+
*
10+
* Project-independent (#122): the breeder's ×3 bonus is a Py constant, but its
11+
* raw power (hence the absolute reactor count) differs between mod configs
12+
* (2 GW in vanilla Py, 10 GW in py-hard-mode). So assert the INVARIANT — the
13+
* ×3 layout bonus and a strictly lower count — with the base count read at
14+
* runtime, not hardcoded. The heat goal also has several producers in some
15+
* configs, so pick the breeder from the picker when one opens.
916
*/
1017
test("reactor row: picking a 2×2 farm scales heat ×3 and persists", async ({ page }) => {
1118
await createBlock(page);
@@ -23,32 +30,45 @@ test("reactor row: picking a 2×2 farm scales heat ×3 and persists", async ({ p
2330
await rateInput.press("Enter");
2431
await expect(goalRateButton(page)).toHaveText("6 GW");
2532

26-
// the goal is unmade — click its icon to add the producing recipe (a single
27-
// candidate — the breeder-reactor heat recipe — is auto-added, no dialog)
33+
// click the goal icon to add a producer: one heat candidate auto-adds, several
34+
// open a picker — pick the breeder reactor either way
2835
await page.locator('button[title^="click to add a recipe that makes this goal"]').click();
36+
// the picker opens asynchronously (multi-candidate configs); give it a beat to
37+
// appear, then pick the breeder. A single-candidate config auto-adds — no dialog.
38+
const heatPicker = page.getByRole("dialog", { name: /Recipes that make/ });
39+
await heatPicker.waitFor({ state: "visible", timeout: 2000 }).catch(() => {});
40+
if (await heatPicker.isVisible().catch(() => false)) {
41+
await heatPicker.getByRole("button", { name: /Breeder reactor heat/ }).click();
42+
await expect(heatPicker).toBeHidden();
43+
}
44+
// the reactor row is in the grid now
2945
await expect(page.getByText("Breeder reactor heat")).toBeVisible();
3046

31-
// flat-rated (1×1): 6 GW ÷ 2 GW per reactor = 3 reactors, chip shows no bonus.
32-
// The building count is now its own click-to-fix field (#121) beside the
33-
// machine icon — unpinned here, so it carries the "click to fix" title.
47+
// flat-rated (1×1): some whole+fraction of reactors, chip shows no bonus. The
48+
// building count is its own click-to-fix field (#121) beside the machine icon.
3449
const machineChip = page.locator('button[title="click to fix the building count"]');
35-
await expect(machineChip).toContainText("3");
50+
await expect(machineChip).toBeVisible();
51+
const baseCount = Number((await machineChip.textContent())?.trim());
52+
expect(baseCount).toBeGreaterThan(0);
3653
const layoutChip = page.locator('button[title^="reactor farm"]');
3754
await expect(layoutChip).toContainText("1×1");
3855
await expect(layoutChip).not.toContainText("heat");
3956

40-
// pick a 2×2 farm: each reactor gains 2 neighbours → ×3 heat → 1 reactor
57+
// pick a 2×2 farm: each reactor gains 2 neighbours → ×3 heat → a third the count
4158
await layoutChip.click();
4259
await page.getByRole("menuitem", { name: /^2×2/ }).click();
4360
await expect(layoutChip).toContainText("2×2");
4461
await expect(layoutChip).toContainText("×3 heat");
45-
await expect(machineChip).toContainText("1");
62+
const bonusCount = Number((await machineChip.textContent())?.trim());
63+
expect(bonusCount).toBeCloseTo(baseCount / 3, 2);
4664

4765
// outlive the editor's 700ms auto-save debounce, then reload: the layout
4866
// (and the rescaled count) persisted with the block doc
4967
await page.waitForTimeout(1200);
5068
await page.reload();
5169
await expect(layoutChip).toContainText("2×2");
5270
await expect(layoutChip).toContainText("×3 heat");
53-
await expect(machineChip).toContainText("1");
71+
await expect(machineChip).toBeVisible();
72+
const persisted = Number((await machineChip.textContent())?.trim());
73+
expect(persisted).toBeCloseTo(bonusCount, 2);
5474
});

0 commit comments

Comments
 (0)