| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import { describe, expect, it } from "vitest";
- import {
- buildingShopAt,
- dialogueActiveInWorld,
- dialogueChoicesFromNode,
- inventorySummary,
- playerStatsFromSnapshot,
- seedListFromSnapshot,
- shopRowsFromDef,
- } from "../src/renderer/playtest-hud.js";
- describe("playerStatsFromSnapshot", () => {
- it("reads gold, stamina, seed and inventory from the player entity", () => {
- const stats = playerStatsFromSnapshot([
- { id: "plot:0:0", type: "plot" },
- { id: "player", type: "player", gold: 42, stamina: 30, selectedSeed: "carrot-seed", inventory: { carrot: 3, "carrot-seed": 1 } },
- ]);
- expect(stats.gold).toBe(42);
- expect(stats.stamina).toBe(30);
- expect(stats.selectedSeed).toBe("carrot-seed");
- expect(stats.inventory).toEqual({ carrot: 3, "carrot-seed": 1 });
- });
- it("defaults when the player or fields are missing", () => {
- const stats = playerStatsFromSnapshot([]);
- expect(stats.gold).toBe(0);
- expect(stats.stamina).toBe(0);
- expect(stats.selectedSeed).toBeNull();
- expect(stats.inventory).toEqual({});
- });
- it("drops zero/negative inventory quantities", () => {
- const stats = playerStatsFromSnapshot([
- { id: "player", type: "player", inventory: { carrot: 2, hoe: 0, weed: -1 } },
- ]);
- expect(stats.inventory).toEqual({ carrot: 2 });
- });
- });
- describe("inventorySummary", () => {
- it("joins inventory items", () => {
- expect(inventorySummary({ inventory: { carrot: 3, hoe: 1 }, gold: 0, stamina: 0, selectedSeed: null })).toBe(
- "carrot ×3 · hoe ×1",
- );
- });
- it("shows a placeholder for an empty inventory", () => {
- expect(inventorySummary({ inventory: {}, gold: 0, stamina: 0, selectedSeed: null })).toBe("items: —");
- });
- });
- describe("seedListFromSnapshot", () => {
- const world = [
- { id: "player", type: "player", inventory: { "carrot-seed": 2, carrot: 3, hoe: 1 } },
- ];
- const items: Array<{ id: string; name: string; kind: string }> = [
- { id: "carrot-seed", name: "Carrot Seeds", kind: "seed" },
- { id: "carrot", name: "Carrot", kind: "material" },
- { id: "hoe", name: "Hoe", kind: "tool" },
- ];
- it("keeps only seed-kind items when an item catalog is given", () => {
- expect(seedListFromSnapshot(world, items as never)).toEqual([{ id: "carrot-seed", name: "Carrot Seeds", qty: 2 }]);
- });
- it("offers every inventory item without a catalog (ws parity)", () => {
- expect(seedListFromSnapshot(world)).toEqual([
- { id: "carrot-seed", name: "carrot-seed", qty: 2 },
- { id: "carrot", name: "carrot", qty: 3 },
- { id: "hoe", name: "hoe", qty: 1 },
- ]);
- });
- it("returns an empty list for an empty inventory", () => {
- expect(seedListFromSnapshot([])).toEqual([]);
- });
- });
- describe("shopRowsFromDef", () => {
- it("maps buys/sells with the shop-viewpoint convention and names from the catalog", () => {
- const rows = shopRowsFromDef(
- {
- id: "general-store",
- name: "General Store",
- buys: [{ itemId: "carrot-seed", price: 20 }],
- sells: [{ itemId: "carrot", price: 15, stock: 5 }],
- } as never,
- { carrot: 2 },
- [
- { id: "carrot-seed", name: "Carrot Seeds", kind: "seed" },
- { id: "carrot", name: "Carrot", kind: "material" },
- ] as never,
- );
- expect(rows.shopId).toBe("general-store");
- expect(rows.buyRows).toEqual([{ itemId: "carrot-seed", name: "Carrot Seeds", price: 20, stock: null, owned: 0 }]);
- expect(rows.sellRows).toEqual([{ itemId: "carrot", name: "Carrot", price: 15, stock: 5, owned: 2 }]);
- });
- it("falls back to the item id without a catalog and handles empty lines", () => {
- const rows = shopRowsFromDef({ id: "s", buys: [], sells: [{ itemId: "egg", price: 40 }] } as never, undefined);
- expect(rows.buyRows).toEqual([]);
- expect(rows.sellRows).toEqual([{ itemId: "egg", name: "egg", price: 40, stock: null, owned: 0 }]);
- });
- });
- describe("dialogueChoicesFromNode", () => {
- it("maps text and choice labels", () => {
- const view = dialogueChoicesFromNode({
- dialogueId: "mayor",
- nodeId: "n1",
- text: "Hello!",
- choices: [{ text: "Hi", to: "n2" }, { text: "Bye", to: "n3" }],
- });
- expect(view.text).toBe("Hello!");
- expect(view.choices).toEqual(["Hi", "Bye"]);
- });
- it("returns empty for an absent dialogue state", () => {
- expect(dialogueChoicesFromNode(undefined)).toEqual({ text: "", choices: [] });
- });
- });
- describe("buildingShopAt", () => {
- const world = [
- { id: "building:shed:2:3", type: "building", x: 2, y: 3, w: 2, h: 2, shop: "general-store" },
- { id: "building:barn:0:0", type: "building", x: 0, y: 0, w: 1, h: 1 },
- ];
- it("finds the shop whose footprint contains the tile", () => {
- expect(buildingShopAt(world, { x: 3, y: 4 })).toEqual({ buildingId: "building:shed:2:3", shopId: "general-store" });
- });
- it("misses outside the footprint, on shopless buildings and on empty world", () => {
- expect(buildingShopAt(world, { x: 4, y: 4 })).toBeUndefined();
- expect(buildingShopAt(world, { x: 0, y: 0 })).toBeUndefined();
- expect(buildingShopAt([], { x: 0, y: 0 })).toBeUndefined();
- });
- });
- describe("dialogueActiveInWorld", () => {
- it("detects the dialogue:active sentinel entity", () => {
- expect(dialogueActiveInWorld([{ id: "dialogue:active", type: "dialogue" }])).toBe(true);
- expect(dialogueActiveInWorld([{ id: "player", type: "player" }])).toBe(false);
- expect(dialogueActiveInWorld([])).toBe(false);
- });
- });
|