fable/val Public Public: anyone can read this; nobody can change it.
forked from benjivers/val
workbenchthis machine
Files 674c40ddee5c18295fdc6a04cd14d0d0c8bbfce9
| 1 | import { describe, expect, test } from "bun:test"; |
| 2 | import { choosePrompt } from "../static/prompt.js"; |
| 3 | |
| 4 | type Snap = ReturnType<typeof snapshot>; |
| 5 | |
| 6 | const snapshot = (over: Record<string, unknown> = {}, me: Record<string, unknown> = {}, spike: Record<string, unknown> = {}) => ({ |
| 7 | phase: "live", |
| 8 | clock: 40, |
| 9 | result: null, |
| 10 | me: { side: "atk", alive: true, blind: 0, planting: 0, spike: false, ...me }, |
| 11 | spike: { planted: false, carried: false, fuse: 0, defuse: 0, x: 100, y: 100, ...spike }, |
| 12 | ...over, |
| 13 | }); |
| 14 | |
| 15 | describe("the one prompt on screen", () => { |
| 16 | test("the buy phase says what to do, which side you are on, and how long there is", () => { |
| 17 | const text = choosePrompt(snapshot({ phase: "buy", clock: 14.2 })); |
| 18 | expect(text).toBe("Buy phase — 15s left. You attack: plant the spike on A or B. Click a gun you can afford."); |
| 19 | expect(choosePrompt(snapshot({ phase: "buy", clock: 14.2 }, { side: "def" }))).toContain("You defend: hold A and B."); |
| 20 | }); |
| 21 | |
| 22 | test("the terminal is told about keys, not clicks", () => { |
| 23 | const text = choosePrompt(snapshot({ phase: "buy", clock: 14.2 }), { input: "keys" }); |
| 24 | expect(text).toContain("Press b and buy a gun you can afford."); |
| 25 | }); |
| 26 | |
| 27 | test("carrying the spike off a site sends you to one", () => { |
| 28 | expect(choosePrompt(snapshot({}, { spike: true }), { onSite: false })).toBe( |
| 29 | "You have the spike — get to site A or B", |
| 30 | ); |
| 31 | }); |
| 32 | |
| 33 | test("carrying it onto a site says how to plant", () => { |
| 34 | expect(choosePrompt(snapshot({}, { spike: true }), { onSite: true })).toBe("Hold F to plant"); |
| 35 | }); |
| 36 | |
| 37 | test("a defender near a planted spike is told to defuse, with the fuse", () => { |
| 38 | const text = choosePrompt(snapshot({}, { side: "def" }, { planted: true, fuse: 31.4 }), { nearSpike: true }); |
| 39 | expect(text).toBe("Spike down, 32s — hold F to defuse"); |
| 40 | }); |
| 41 | |
| 42 | test("a defender across the map is told to get to it", () => { |
| 43 | const text = choosePrompt(snapshot({}, { side: "def" }, { planted: true, fuse: 31.4 }), { nearSpike: false }); |
| 44 | expect(text).toBe("Spike down, 32s — get to it and hold F"); |
| 45 | }); |
| 46 | |
| 47 | test("an attacker with it planted is told to hold the site", () => { |
| 48 | expect(choosePrompt(snapshot({}, {}, { planted: true, fuse: 10 }))).toBe( |
| 49 | "Spike down, 10s — keep them off it", |
| 50 | ); |
| 51 | }); |
| 52 | |
| 53 | test("blind beats everything else on screen", () => { |
| 54 | const text = choosePrompt(snapshot({}, { blind: 1.4, spike: true }), { onSite: true }); |
| 55 | expect(text).toBe("You are blind — back off until it clears"); |
| 56 | }); |
| 57 | |
| 58 | test("dead in a live round says you are still in the match", () => { |
| 59 | expect(choosePrompt(snapshot({}, { alive: false }))).toBe("Waiting for the next round — you're in it"); |
| 60 | }); |
| 61 | |
| 62 | test("the end of a round says whether you won, why, and the countdown", () => { |
| 63 | // The server's `result` is only ever set when the MATCH is over; the round's |
| 64 | // outcome travels as `last`. The old test fed a snapshot the server never |
| 65 | // sends, and the real one read "Round over" and nothing else. |
| 66 | const last = { round: 3, winner: "blue", why: "Spike defused" }; |
| 67 | const lost = choosePrompt(snapshot({ phase: "end", clock: 4.1, last }, { team: "red" })); |
| 68 | expect(lost).toBe("Round lost — spike defused · next round in 5s"); |
| 69 | const won = choosePrompt(snapshot({ phase: "end", clock: 4.1, last }, { team: "blue" })); |
| 70 | expect(won).toBe("Round won — spike defused · next round in 5s"); |
| 71 | // Dead or alive, the outcome is the thing to say at that moment. |
| 72 | expect(choosePrompt(snapshot({ phase: "end", clock: 4.1, last }, { team: "red", alive: false }))).toBe(lost); |
| 73 | expect(choosePrompt(snapshot({ phase: "end", clock: 4.1, last: null }))).toBe("Round over · next round in 5s"); |
| 74 | }); |
| 75 | |
| 76 | test("the end of the match names the winner and says a new one is coming", () => { |
| 77 | const text = choosePrompt(snapshot({ phase: "over", clock: 11.2, result: "red win 13–7" })); |
| 78 | expect(text).toBe("Match over — red win 13–7 · a new match starts in 12s"); |
| 79 | }); |
| 80 | |
| 81 | test("a live defender is told what defending is", () => { |
| 82 | expect(choosePrompt(snapshot({}, { side: "def" }))).toBe("Defending — hold A and B, 40s"); |
| 83 | }); |
| 84 | |
| 85 | test("an attacker beside a loose spike is told to walk onto it", () => { |
| 86 | expect(choosePrompt(snapshot(), { nearSpike: true })).toBe("Walk onto the spike to pick it up"); |
| 87 | }); |
| 88 | |
| 89 | test("defusing counts down the defuse, not the fuse", () => { |
| 90 | const text = choosePrompt(snapshot({}, { side: "def" }, { planted: true, fuse: 20, defuse: 3.5 }), { |
| 91 | nearSpike: true, |
| 92 | }); |
| 93 | expect(text).toBe("Defusing — keep holding F, 4s"); |
| 94 | }); |
| 95 | |
| 96 | test("no snapshot yet is no prompt", () => { |
| 97 | expect(choosePrompt(null as unknown as Snap)).toBe(""); |
| 98 | }); |
| 99 | }); |