feat(sprint1-step2): core economy TS + useEconomy hook (lazy calc) + 13 tests vitest

This commit is contained in:
2026-03-17 06:36:51 +01:00
parent c414cf2d07
commit c69da320cc
13 changed files with 2627 additions and 174 deletions

View File

@@ -0,0 +1,112 @@
import { describe, it, expect } from "vitest";
import {
generatorCost,
totalProductionPerSecond,
computeIdleGains,
applyClick,
buyGenerator,
applyPrestige,
canPrestige,
DEFAULT_STATE,
DEFAULT_GENERATORS,
} from "../core/economy";
describe("generatorCost", () => {
it("retourne baseCost quand owned = 0", () => {
const gen = { ...DEFAULT_GENERATORS[0], owned: 0 };
expect(generatorCost(gen)).toBe(gen.baseCost);
});
it("applique la formule base × 1.15^n", () => {
const gen = { ...DEFAULT_GENERATORS[0], owned: 2 };
expect(generatorCost(gen)).toBe(Math.floor(gen.baseCost * Math.pow(1.15, 2)));
});
});
describe("totalProductionPerSecond", () => {
it("retourne 0 si aucun générateur acheté", () => {
expect(totalProductionPerSecond(DEFAULT_STATE)).toBe(0);
});
it("somme correctement la production de plusieurs générateurs", () => {
const state = {
...DEFAULT_STATE,
generators: DEFAULT_STATE.generators.map((g, i) =>
i === 0 ? { ...g, owned: 2 } : i === 1 ? { ...g, owned: 1 } : g
),
};
const expected = (DEFAULT_GENERATORS[0].baseProduction * 2 + DEFAULT_GENERATORS[1].baseProduction * 1) * 1;
expect(totalProductionPerSecond(state)).toBeCloseTo(expected);
});
it("applique le multiplicateur de prestige", () => {
const state = { ...DEFAULT_STATE, generators: DEFAULT_STATE.generators.map((g, i) => i === 0 ? { ...g, owned: 1 } : g), prestigeMultiplier: 1.5 };
expect(totalProductionPerSecond(state)).toBeCloseTo(DEFAULT_GENERATORS[0].baseProduction * 1.5);
});
});
describe("computeIdleGains (lazy calculation)", () => {
it("calcule les gains proportionnellement au temps écoulé", () => {
const state = {
...DEFAULT_STATE,
generators: DEFAULT_STATE.generators.map((g, i) => i === 0 ? { ...g, owned: 10 } : g),
lastTick: 0,
};
const gains = computeIdleGains(state, 5000); // 5 secondes
const expected = DEFAULT_GENERATORS[0].baseProduction * 10 * 5;
expect(gains).toBeCloseTo(expected);
});
it("retourne 0 si aucun temps écoulé", () => {
const now = Date.now();
const state = { ...DEFAULT_STATE, lastTick: now };
expect(computeIdleGains(state, now)).toBeCloseTo(0);
});
});
describe("applyClick", () => {
it("augmente les ressources du clickMultiplier × prestigeMultiplier", () => {
const state = { ...DEFAULT_STATE, clickMultiplier: 3, prestigeMultiplier: 2 };
const result = applyClick(state);
expect(result.resources).toBe(6);
});
});
describe("buyGenerator", () => {
it("retourne null si fonds insuffisants", () => {
const result = buyGenerator(DEFAULT_STATE, "manic");
expect(result).toBeNull(); // 0 ressources, coût = 15
});
it("achète correctement et déduit le coût", () => {
const state = { ...DEFAULT_STATE, resources: 100 };
const result = buyGenerator(state, "manic");
expect(result).not.toBeNull();
expect(result!.generators.find((g) => g.id === "manic")!.owned).toBe(1);
expect(result!.resources).toBe(100 - DEFAULT_GENERATORS[0].baseCost);
});
});
describe("prestige", () => {
it("canPrestige retourne false si < 1 000 000 ressources", () => {
expect(canPrestige({ ...DEFAULT_STATE, resources: 999_999 })).toBe(false);
});
it("canPrestige retourne true si ≥ 1 000 000 ressources", () => {
expect(canPrestige({ ...DEFAULT_STATE, resources: 1_000_000 })).toBe(true);
});
it("reset les ressources + générateurs + incrémente le multiplicateur", () => {
const state = {
...DEFAULT_STATE,
resources: 2_000_000,
generators: DEFAULT_STATE.generators.map((g) => ({ ...g, owned: 5 })),
prestigeCount: 0,
};
const result = applyPrestige(state);
expect(result.resources).toBe(0);
expect(result.prestigeCount).toBe(1);
expect(result.prestigeMultiplier).toBeCloseTo(1.1);
expect(result.generators.every((g) => g.owned === 0)).toBe(true);
});
});