import { describe, expect, it } from 'vitest'; import { Duel } from './duel.svelte'; import { resolveTurn } from './resolve'; import { createGame, type GameState } from './state'; import type { Gesture } from './spells'; import { noop, play } from './test-helpers'; /** A is one gesture from a lightning bolt and has just been struck by amnesia. */ function amnesiaBeforeLightning(): GameState { let s = createGame({ A: 'You', B: 'Foe' }, 1); const left = 'DFFD'; const foe = '-DPP'; for (let i = 0; i < 4; i++) { s = play(s, { left: left[i] as Gesture }, { left: foe[i] as Gesture, casts: i === 3 ? [{ hand: 'left', spellId: 'amnesia' }] : [] }); } expect(s.wizards.A.constraints.amnesia).toBe(true); return s; } describe('the duel store', () => { it('casts the spell a forced repeat completes, without a click', () => { const duel = new Duel(amnesiaBeforeLightning()); expect(duel.forced.left).toBe('D'); expect(duel.completions.main.left.map((c) => c.spell.id)).toContain('lightning_bolt'); expect(duel.sets.main.left.spellId).toBe('lightning_bolt'); expect(duel.ready).toBe(true); duel.reveal(); expect(duel.foe.hp).toBe(10); }); }); describe('threats at a crowded table', () => { it('keys each opponent apart when two build the same spell with the same hand', () => { let s = createGame({ A: 'You', B: 'Bryn', C: 'Cass' }, 1); s = resolveTurn(s, { A: noop(), B: { ...noop(), left: 'S' }, C: { ...noop(), left: 'S' } }); const duel = new Duel(s); const missiles = duel.threatsNow.filter((t) => t.spell.id === 'missile'); expect(missiles.map((t) => t.who).sort()).toEqual(['B', 'C']); const keys = duel.threats.map((t) => duel.threatKey(t)); expect(new Set(keys).size).toBe(keys.length); }); it('labels targets with health and condition', () => { let s = createGame({ A: 'You', B: 'Bryn', C: 'Cass' }, 1); s = resolveTurn(s, { A: noop(), B: noop(), C: noop() }); s.wizards.C.hp = 8; s.wizards.C.invisibleTurns = 2; const duel = new Duel(s); expect(duel.targetLabel('C')).toBe('Cass · 8 HP · invisible'); }); }); describe('typing a move', () => { it('fills the left hand, then the right, and backspace takes the last one back', () => { const duel = new Duel(createGame({ A: 'You', B: 'Foe' }, 1)); expect(duel.typeGesture('S')).toBe(true); expect(duel.typeGesture('P')).toBe(true); expect(duel.sets.main.left.gesture).toBe('S'); expect(duel.sets.main.right.gesture).toBe('P'); expect(duel.typeGesture('W')).toBe(false); duel.untype(); expect(duel.sets.main.right.gesture).toBeNull(); expect(duel.sets.main.left.gesture).toBe('S'); }); it('warns of a clap made with one hand before the turn is sealed', () => { const duel = new Duel(createGame({ A: 'You', B: 'Foe' }, 1)); duel.typeGesture('C'); duel.typeGesture('W'); expect(duel.loneClap).toBe(true); expect(duel.ready).toBe(true); duel.untype(); duel.typeGesture('C'); expect(duel.loneClap).toBe(false); }); });