explodorama / files / test / padHold.test.ts
padHold.test.ts
| 1 | import { describe, expect, it } from 'vitest' |
| 2 | import { cancelHold, HOLD_SECONDS, holdProgress, newHold, startHold, stepHold } from '../src/ui/padHold' |
| 3 | |
| 4 | const FULL = HOLD_SECONDS * 1000 |
| 5 | const down = (...faces: number[]) => (f: number) => faces.includes(f) |
| 6 | |
| 7 | describe('padHold', () => { |
| 8 | it('fills linearly and reaches 1 at HOLD_SECONDS', () => { |
| 9 | expect(holdProgress(1000, 1000)).toBe(0) |
| 10 | expect(holdProgress(1000, 1000 + FULL / 2)).toBeCloseTo(0.5) |
| 11 | expect(holdProgress(1000, 1000 + FULL)).toBe(1) |
| 12 | expect(holdProgress(1000, 1000 + FULL * 5)).toBe(1) |
| 13 | }) |
| 14 | |
| 15 | it('reports progress while held and fires once, the moment the ring fills', () => { |
| 16 | const h = newHold() |
| 17 | expect(startHold(h, 0, 0)).toBe(true) |
| 18 | expect(stepHold(h, down(0), FULL / 2)).toEqual([{ kind: 'progress', face: 0, progress: 0.5 }]) |
| 19 | expect(stepHold(h, down(0), FULL)).toEqual([{ kind: 'progress', face: 0, progress: 1 }, { kind: 'fire', face: 0 }]) |
| 20 | }) |
| 21 | |
| 22 | it('does not fire again while still held, and the release only clears the ring', () => { |
| 23 | const h = newHold() |
| 24 | startHold(h, 0, 0) |
| 25 | stepHold(h, down(0), FULL) |
| 26 | expect(stepHold(h, down(0), FULL + 16)).toEqual([]) |
| 27 | expect(stepHold(h, down(0), FULL * 10)).toEqual([]) |
| 28 | expect(stepHold(h, down(), FULL * 10 + 16)).toEqual([{ kind: 'release', face: 0 }]) |
| 29 | expect(stepHold(h, down(), FULL * 10 + 32)).toEqual([]) |
| 30 | }) |
| 31 | |
| 32 | it('keeps the button used up until it is let go: no new hold, not even the same button', () => { |
| 33 | const h = newHold() |
| 34 | startHold(h, 0, 0) |
| 35 | stepHold(h, down(0), FULL) |
| 36 | expect(startHold(h, 0, FULL + 10)).toBe(false) |
| 37 | expect(startHold(h, 1, FULL + 20)).toBe(false) |
| 38 | stepHold(h, down(0), FULL + 30) |
| 39 | stepHold(h, down(), FULL + 40) |
| 40 | expect(startHold(h, 0, FULL + 50)).toBe(true) |
| 41 | }) |
| 42 | |
| 43 | it('cancels, with no action, on an early release', () => { |
| 44 | const h = newHold() |
| 45 | startHold(h, 3, 0) |
| 46 | expect(stepHold(h, down(), FULL - 1)).toEqual([{ kind: 'cancel', face: 3 }]) |
| 47 | expect(stepHold(h, down(), FULL + 100)).toEqual([]) |
| 48 | }) |
| 49 | |
| 50 | it('ignores a second button while one is held, and allows one after', () => { |
| 51 | const h = newHold() |
| 52 | startHold(h, 0, 0) |
| 53 | expect(startHold(h, 1, 100)).toBe(false) |
| 54 | expect(stepHold(h, down(0, 1), 200)).toEqual([{ kind: 'progress', face: 0, progress: 0.4 }]) |
| 55 | stepHold(h, down(), 300) |
| 56 | expect(startHold(h, 1, 400)).toBe(true) |
| 57 | }) |
| 58 | |
| 59 | it('cancel (blur, a swapped pad) ends a hold with no action', () => { |
| 60 | const h = newHold() |
| 61 | expect(cancelHold(h)).toEqual([]) |
| 62 | startHold(h, 2, 0) |
| 63 | expect(cancelHold(h)).toEqual([{ kind: 'cancel', face: 2 }]) |
| 64 | expect(stepHold(h, down(2), FULL)).toEqual([]) |
| 65 | }) |
| 66 | |
| 67 | it('cancel on a used-up button frees it, with no action', () => { |
| 68 | const h = newHold() |
| 69 | startHold(h, 2, 0) |
| 70 | stepHold(h, down(2), FULL) |
| 71 | expect(cancelHold(h)).toEqual([{ kind: 'cancel', face: 2 }]) |
| 72 | expect(startHold(h, 2, FULL + 1)).toBe(true) |
| 73 | }) |
| 74 | }) |