fuzzyworld

explodorama / files / test / test-scenes.test.ts

test-scenes.test.ts

3.4 KB · history · blame

1import { describe, expect, it } from 'vitest'
2import { generateScene, replayScene } from '../src/sim/demo'
3import { buildTestScene, TEST_KINDS } from '../src/sim/testScenes'
4import { step } from '../src/sim/turn'
5import type { GameState } from '../src/sim/types'
6
7/** Plays a test scene to its end: the state after every turn. */
8function states(kind: (typeof TEST_KINDS)[number]): GameState[] {
9 const scene = buildTestScene(kind)
10 const out: GameState[] = []
11 let s = scene.start
12 for (const a of scene.actions) {
13 s = step(s, a).state
14 out.push(s)
15 }
16 return out
17}
18
19describe('developer-mode test scenes (user request, 2026-10-31)', () => {
20 for (const kind of TEST_KINDS) {
21 it(`${kind}: is built, each turn is legal, and generateScene gives the same scene`, () => {
22 const scene = buildTestScene(kind)
23 expect(scene.actions.length).toBe(scene.gestures.length)
24 expect(generateScene(kind, 1)).toEqual(scene)
25 expect(() => replayScene(scene)).not.toThrow()
26 })
27 }
28
29 it('two gems on one slide offer one after the other and end with none open', () => {
30 const [slid, first, second] = states('testTwoGemsSlide')
31 expect(slid!.offer).not.toBeNull()
32 expect(slid!.waitingGems).toHaveLength(1)
33 expect(first!.offer).not.toBeNull()
34 expect(second!.offer).toBeNull()
35 expect(second!.waitingGems).toHaveLength(0)
36 })
37
38 it('oil over two gems does the same', () => {
39 const [slid, first, second] = states('testTwoGemsOil')
40 expect(slid!.offer).not.toBeNull()
41 expect(first!.offer).not.toBeNull()
42 expect(second!.offer).toBeNull()
43 })
44
45 it('two gems with a charge between: the second waits for the charge choice', () => {
46 const [slid, first, sold, second] = states('testGemsAndCharge')
47 expect(slid!.offer).not.toBeNull()
48 expect(slid!.chargeOffer).not.toBeNull()
49 expect(first!.offer).toBeNull()
50 expect(first!.chargeOffer).not.toBeNull()
51 expect(sold!.offer).not.toBeNull()
52 expect(second!.offer).toBeNull()
53 expect(second!.chargeOffer).toBeNull()
54 })
55
56 it('a gem under a Run is taken', () => {
57 expect(states('testGemUnderRun')[0]!.offer).not.toBeNull()
58 })
59
60 it('a gem taken on the turn of death offers nothing', () => {
61 const [dead] = states('testGemDeath')
62 expect(dead!.status).toBe('dead')
63 expect(dead!.offer).toBeNull()
64 })
65
66 it('oil slides stop at a bomb and at an enemy, and on an open exit', () => {
67 expect(states('testOilBomb')[0]!.player).toEqual({ x: 4, y: 1 })
68 const [e] = states('testOilEnemy')
69 expect(e!.player).toEqual({ x: 4, y: 1 })
70 expect(e!.status).toBe('playing')
71 expect(states('testOilExit')[0]!.status).toBe('cleared')
72 })
73
74 it('the autopilot gathers a coin, a charge and a gem, answers wait for it, and ends on the exit (Q73)', () => {
75 const all = states('testAutopilot')
76 expect(all[3]!.chargeOffer).not.toBeNull()
77 expect(all[4]!.chargeOffer).toBeNull()
78 expect(all[6]!.offer).not.toBeNull()
79 expect(all[7]!.offer).toBeNull()
80 expect(all.at(-1)!.status).toBe('cleared')
81 expect(all.at(-1)!.drops).toHaveLength(0)
82 expect(all.at(-1)!.gems).toHaveLength(0)
83 })
84
85 it('the autopilot waits while the crate over the gem crumbles, then fetches the gem (Q73)', () => {
86 const all = states('testAutopilotCrates')
87 expect(all[0]!.player).toEqual({ x: 1, y: 1 })
88 expect(all[1]!.player).toEqual({ x: 1, y: 1 })
89 expect(all[4]!.offer).not.toBeNull()
90 expect(all.at(-1)!.status).toBe('cleared')
91 })
92})