explodorama / files / test / targetLabel.test.ts
targetLabel.test.ts
ebcd0a8f 2026-11-02 Pavel Safronov | 1 | import { describe, expect, it } from 'vitest' |
| 2 | import { targetLabel } from '../src/ui/targetLabel' | |
| 3 | import { board, v } from './helpers' | |
| 4 | ||
| 5 | // A roomy empty level, the player in the middle; enemies and bombs are added per case. | |
| 6 | const room = () => | |
| 7 | board(` | |
| 8 | ####### | |
| 9 | #.....# | |
| 10 | #.....# | |
| 11 | #..P..# | |
| 12 | #.....# | |
| 13 | #.....# | |
| 14 | #######`) | |
| 15 | ||
| 16 | describe('the controller target label', () => { | |
| 17 | it('Move, Bomb and Wait', () => { | |
| 18 | const s = room() | |
| 19 | expect(targetLabel(s, 'move', v(4, 3))).toBe('Move to this tile') | |
| 20 | expect(targetLabel(s, 'bomb', v(4, 3))).toBe('Place a bomb on this tile') | |
| 21 | expect(targetLabel(s, 'wait', null)).toBe('Wait a turn') | |
| 22 | }) | |
| 23 | it('a button with no tile and no Wait has nothing to do', () => { | |
| 24 | expect(targetLabel(room(), 'move', null)).toBe('Nothing to do here') | |
| 25 | }) | |
| 26 | it('Run, Diagonal and Slide are told apart by the tile', () => { | |
| 27 | const s = room() | |
| 28 | s.powers.run = true | |
| 29 | s.powers.diagonal = true | |
| 30 | expect(targetLabel(s, 'move', v(5, 3))).toBe('Run to this tile') | |
| 31 | expect(targetLabel(s, 'move', v(4, 2))).toBe('Step diagonally to this tile') | |
| 32 | }) | |
| 33 | it('Kick, with a bomb next to the player', () => { | |
| 34 | const s = board(` | |
| 35 | ###### | |
| 36 | #P3..# | |
| 37 | ######`) | |
| 38 | s.powers.kick = true | |
| 39 | expect(targetLabel(s, 'move', v(2, 1))).toBe('Kick the bomb on this tile') | |
| 40 | }) | |
| 41 | it('Kick and Bomb Pass together ask which', () => { | |
| 42 | const s = board(` | |
| 43 | ###### | |
| 44 | #P8..# | |
| 45 | ######`) | |
| 46 | s.powers.kick = true | |
| 47 | s.powers.bombPass = true | |
| 48 | expect(targetLabel(s, 'move', v(2, 1))).toBe('Choose what to do with the bomb on this tile') | |
| 49 | }) | |
| 50 | it('Bomb Pass alone walks onto the bomb', () => { | |
| 51 | const s = board(` | |
| 52 | ###### | |
| 53 | #P8..# | |
| 54 | ######`) | |
| 55 | s.powers.bombPass = true | |
| 56 | expect(targetLabel(s, 'move', v(2, 1))).toBe('Walk onto the bomb on this tile') | |
| 57 | }) | |
| 58 | it('Throw, RPG and Detonator', () => { | |
| 59 | const s = room() | |
| 60 | s.powers.throw = true | |
| 61 | s.powers.rpg = true | |
| 62 | expect(targetLabel(s, 'bomb', v(5, 3))).toBe('Throw a bomb to this tile') | |
| 63 | expect(targetLabel(s, 'bomb', v(5, 3))).not.toContain('RPG') | |
| 64 | // The RPG lands at the end of a straight line, further than a throw reaches. | |
| 65 | const lane = board(` | |
| 66 | ######## | |
| 67 | #P.....# | |
| 68 | ########`) | |
| 69 | lane.powers.throw = true | |
| 70 | lane.powers.rpg = true | |
| 71 | expect(targetLabel(lane, 'bomb', v(3, 1))).toBe('Throw a bomb to this tile') | |
| 72 | expect(targetLabel(lane, 'bomb', v(6, 1))).toBe('Fire an RPG bomb to this tile') | |
| 73 | const d = board(` | |
| 74 | ###### | |
| 75 | #P.7.# | |
| 76 | ######`) | |
| 77 | d.powers.detonate = true | |
| 78 | expect(targetLabel(d, 'bomb', v(3, 1))).toBe('Set off the bomb on this tile') | |
| 79 | }) | |
| 80 | it('each charge', () => { | |
| 81 | const s = room() | |
| 82 | s.charge = { kind: 'nuke', left: 1 } | |
| 83 | expect(targetLabel(s, 'charged', v(4, 3))).toBe('Place a Nuke bomb on this tile') | |
| 84 | s.charge = { kind: 'pierce', left: 1 } | |
| 85 | expect(targetLabel(s, 'charged', v(4, 3))).toBe('Place a Pierce bomb on this tile') | |
| 86 | s.charge = { kind: 'freeze', left: 1 } | |
| 87 | expect(targetLabel(s, 'charged', v(3, 3))).toBe('Freeze every enemy') | |
| 88 | s.charge = { kind: 'decoy', left: 1 } | |
| 89 | expect(targetLabel(s, 'charged', v(4, 3))).toContain('Put a decoy on this tile') | |
| 90 | s.charge = { kind: 'icbm', left: 1 } | |
| 91 | expect(targetLabel(s, 'charged', v(1, 3))).toContain('Launch an ICBM to this tile') | |
| 92 | s.charge = { kind: 'teleport', left: 1 } | |
| 93 | expect(targetLabel(s, 'charged', v(5, 4))).toBe('Teleport to this tile') | |
| 94 | }) | |
| 95 | it('says so when it would cost a life', () => { | |
| 96 | // A bomb about to go off two tiles away: stepping next to it is deadly. | |
| 97 | const s = board(` | |
| 98 | ####### | |
| 99 | #P.1..# | |
| 100 | #######`) | |
| 101 | expect(targetLabel(s, 'move', v(2, 1))).toContain('(costs a life!)') | |
| 102 | }) | |
| 103 | it('a tile that means nothing says so', () => { | |
| 104 | expect(targetLabel(room(), 'move', v(1, 1))).toBe('Nothing to do here') | |
| 105 | }) | |
| 106 | }) | |
| 107 | ||
| 108 | describe('the controller target label: oil', () => { | |
| 109 | it('a step or a run onto oil slides on', () => { | |
| 110 | const s = board(` | |
| 111 | ####### | |
| 112 | #P~~~.# | |
| 113 | #######`) | |
| 114 | s.powers.run = true | |
| 115 | expect(targetLabel(s, 'move', v(2, 1))).toBe('Slide to the end of the oil') | |
| 116 | expect(targetLabel(s, 'move', v(3, 1))).toBe('Slide to the end of the oil') | |
| 117 | // A lone oil tile has nowhere to slide on to. | |
| 118 | const one = board(` | |
| 119 | ###### | |
| 120 | #P~.## | |
| 121 | ######`) | |
| 122 | expect(targetLabel(one, 'move', v(2, 1))).toBe('Move to this tile') | |
| 123 | }) | |
| 124 | }) |