| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
import { describe, expect, test } from "bun:test"; |
| 6 |
import { banner, drawBanner } from "../static/banner.js"; |
| 7 |
|
| 8 |
const snap = (over: Record<string, unknown> = {}, me: Record<string, unknown> | null = { team: "red", side: "atk" }) => ({ |
| 9 |
phase: "live", |
| 10 |
clock: 40, |
| 11 |
round: 5, |
| 12 |
result: null, |
| 13 |
last: { round: 4, winner: "blue", why: "Spike defused" }, |
| 14 |
me, |
| 15 |
...over, |
| 16 |
}); |
| 17 |
|
| 18 |
describe("what the banner says", () => { |
| 19 |
test("a live round says nothing: the view is the game", () => { |
| 20 |
expect(banner(snap())).toBe(null); |
| 21 |
expect(banner(null)).toBe(null); |
| 22 |
}); |
| 23 |
|
| 24 |
test("a round over says whether you won, why, and when the next one starts", () => { |
| 25 |
const lost = banner(snap({ phase: "end", clock: 3.2 })); |
| 26 |
expect(lost).toEqual({ title: "Round lost", sub: "spike defused · next round in 4s", alpha: 1 }); |
| 27 |
const won = banner(snap({ phase: "end", clock: 3.2 }, { team: "blue", side: "def" })); |
| 28 |
expect(won?.title).toBe("Round won"); |
| 29 |
}); |
| 30 |
|
| 31 |
test("a round over with no outcome yet still says the round is over", () => { |
| 32 |
expect(banner(snap({ phase: "end", clock: 2, last: null }))).toEqual({ title: "Round over", sub: "next round in 2s", alpha: 1 }); |
| 33 |
}); |
| 34 |
|
| 35 |
test("a match over names the winner and the countdown to the next match", () => { |
| 36 |
const words = banner(snap({ phase: "over", clock: 9.9, result: "red win 13–7" })); |
| 37 |
expect(words?.title).toBe("red win 13–7"); |
| 38 |
expect(words?.sub).toBe("match over · a new match starts in 10s"); |
| 39 |
}); |
| 40 |
|
| 41 |
test("a round starting shows its number and your side for three seconds, then fades out", () => { |
| 42 |
|
| 43 |
const fresh = banner(snap({ phase: "buy", clock: 14 })); |
| 44 |
expect(fresh).toEqual({ title: "Round 5", sub: "you attack — plant the spike on A or B", alpha: 1 }); |
| 45 |
expect(banner(snap({ phase: "buy", clock: 13 }, { team: "blue", side: "def" }))?.sub).toBe("you defend — hold A and B"); |
| 46 |
|
| 47 |
const leaving = banner(snap({ phase: "buy", clock: 11.25 })); |
| 48 |
expect(leaving?.alpha).toBeCloseTo(0.5, 5); |
| 49 |
expect(banner(snap({ phase: "buy", clock: 11 }))).toBe(null); |
| 50 |
expect(banner(snap({ phase: "buy", clock: 3 }))).toBe(null); |
| 51 |
}); |
| 52 |
|
| 53 |
test("a watcher with no side is told the team that took it", () => { |
| 54 |
expect(banner(snap({ phase: "end", clock: 3 }, null))?.title).toBe("blue take the round"); |
| 55 |
}); |
| 56 |
}); |
| 57 |
|
| 58 |
test("drawing it is one band and two lines of text, and nothing when there is nothing to say", () => { |
| 59 |
const ops: string[] = []; |
| 60 |
const ctx = new Proxy({} as Record<string, unknown>, { |
| 61 |
get: (_, prop: string) => (...args: unknown[]) => ops.push(`${prop}(${args.map(String).join(",")})`), |
| 62 |
set: () => true, |
| 63 |
}); |
| 64 |
drawBanner(ctx as never, banner(snap({ phase: "end", clock: 3 })), 900, 570); |
| 65 |
expect(ops.filter((op) => op.startsWith("fillRect")).length).toBe(1); |
| 66 |
expect(ops.some((op) => op.startsWith("fillText(Round lost"))).toBe(true); |
| 67 |
expect(ops.some((op) => op.startsWith("fillText(spike defused"))).toBe(true); |
| 68 |
ops.length = 0; |
| 69 |
drawBanner(ctx as never, null, 900, 570); |
| 70 |
drawBanner(ctx as never, { title: "x", sub: "y", alpha: 0 }, 900, 570); |
| 71 |
expect(ops.length).toBe(0); |
| 72 |
}); |