Files
galaxy-game/ui/frontend/tests/wasm-core-calc.test.ts
T
Ilia Denisov 9ae7b88b89
Tests · UI / test (push) Successful in 2m14s
Tests · Go / test (push) Successful in 2m25s
feat(ui): Phase 30 ship-class calculator with goal-seek and reach circles
Fuse the standalone ship-class designer (Phases 17/18) into a sidebar calculator: live mass/speed/attack/defence/bombing results, a planet build-rate readout, single-target goal-seek, a modernization-cost mode, and auto reach circles on the map for the selected planet.

pkg/calc becomes the single source for the new math (no mirroring): extract BombingPower from the engine model and the per-turn ship-production loop from controller.ProduceShip into pkg/calc (engine now delegates), and add inverse goal-seek solvers in pkg/calc/solve.go. Thin-bridge the combat, planet-build, and solver functions through ui/core/calc + ui/wasm and rebuild core.wasm.

Remove the standalone designer view/route; the ship-classes table and the view/bottom menus open the calculator via a shared request store.

Docs: rewrite ui/PLAN.md Phase 30, adjust Phase 34 (realistic forecast + CAP/COL ownership), add ui/docs/calculator-ux.md, extend calc-bridge.md, fix navigation.md; remove ui/CALCULATOR.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 20:04:07 +02:00

74 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Smoke test for the Phase 30 calculator bridge against the real
// (TinyGo-built) core.wasm. The calc-model and component suites use a
// fake Core; this file boots the actual WASM module to confirm every new
// function is registered in `ui/wasm/main.go` and marshals correctly —
// including the object return of `produceShipsInTurn` and the `null`
// infeasible result of the solvers. Requires `make wasm` to have run.
import { beforeAll, describe, expect, test } from "vitest";
import type { Core } from "../src/platform/core/index";
import { loadWasmCoreForTest } from "./setup-wasm";
let core: Core;
beforeAll(async () => {
core = await loadWasmCoreForTest();
});
describe("WasmCore calculator bridge (Phase 30)", () => {
test("combat results", () => {
expect(core.effectiveAttack({ weapons: 15, weaponsTech: 1.5 })).toBeCloseTo(
22.5,
9,
);
expect(
core.effectiveDefence({ shields: 20, shieldsTech: 1, fullMass: 45 }),
).toBeCloseTo((20 / Math.cbrt(45)) * Math.cbrt(30), 6);
expect(
core.bombingPower({ weapons: 30, weaponsTech: 1, armament: 3, number: 1 }),
).toBeCloseTo(139.29503, 3);
});
test("planet build", () => {
expect(
core.shipBuildCost({ shipMass: 10, material: 3, resources: 0.5 }),
).toBeCloseTo(114, 9);
const r = core.produceShipsInTurn({
productionAvailable: 100,
material: 100,
resources: 10,
shipMass: 1,
});
expect(r).toEqual({
ships: 10,
materialLeft: 90,
productionUsed: 0,
progress: 0,
});
});
test("goal-seek solvers, including infeasible", () => {
expect(
core.weaponsForAttack({ targetAttack: 30, weaponsTech: 1.5 }),
).toBeCloseTo(20, 9);
expect(
core.cargoForEmptyMass({ targetEmptyMass: 42, restMass: 30 }),
).toBeCloseTo(12, 9);
expect(
core.loadForFullMass({ targetFullMass: 65, emptyMass: 45, cargoTech: 1 }),
).toBeCloseTo(20, 9);
const shields = core.shieldsForDefence({
targetDefence: 5,
shieldsTech: 1,
restMass: 40,
});
expect(shields).not.toBeNull();
expect(shields as number).toBeGreaterThan(0);
// Speed at/above the stripped-hull ceiling (20 × driveTech) is
// unreachable: the bridge returns null.
expect(
core.driveForSpeed({ targetSpeed: 100, driveTech: 1.2, restMass: 35 }),
).toBeNull();
});
});