animal-letter.test.js (2973B)
1 const { ANIMALS, shuffleAnimals, pickAnimal } = require('../../games/animal-letter/lib.js'); 2 const assert = require('node:assert/strict'); 3 const { test } = require('node:test'); 4 5 test('every animal name starts with its declared letter', () => { 6 for (const a of ANIMALS) { 7 assert.equal( 8 a.name[0].toUpperCase(), 9 a.letter, 10 `${a.name} should start with ${a.letter}`, 11 ); 12 } 13 }); 14 15 test('every codepoint is a valid 4-5 char lowercase hex string', () => { 16 for (const a of ANIMALS) { 17 assert.match( 18 a.codepoint, 19 /^[0-9a-f]{4,5}$/, 20 `${a.key} has invalid codepoint: ${a.codepoint}`, 21 ); 22 } 23 }); 24 25 test('all animal keys are unique', () => { 26 const keys = ANIMALS.map(a => a.key); 27 assert.equal(new Set(keys).size, keys.length, 'Duplicate key found'); 28 }); 29 30 test('all animal letters are uppercase single characters A-Z', () => { 31 for (const a of ANIMALS) { 32 assert.match(a.letter, /^[A-Z]$/, `${a.key} letter invalid: ${a.letter}`); 33 } 34 }); 35 36 test('pool is large enough to play a full game without repeats', () => { 37 assert.ok(ANIMALS.length >= 10, `Only ${ANIMALS.length} animals — need at least 10 for one game`); 38 }); 39 40 test('shuffleAnimals returns all animals in a different order', () => { 41 const result = shuffleAnimals(Math.random); 42 assert.equal(result.length, ANIMALS.length, 'Length must match'); 43 // Same keys, possibly different order 44 const origKeys = ANIMALS.map(a => a.key).sort().join(','); 45 const resultKeys = result.map(a => a.key).sort().join(','); 46 assert.equal(origKeys, resultKeys, 'Shuffled array must contain same animals'); 47 }); 48 49 test('shuffleAnimals does not mutate original ANIMALS array', () => { 50 const firstBefore = ANIMALS[0].key; 51 shuffleAnimals(Math.random); 52 assert.equal(ANIMALS[0].key, firstBefore, 'ANIMALS[0] should be unchanged after shuffle'); 53 }); 54 55 test('shuffleAnimals produces varied orderings', () => { 56 const orders = new Set(); 57 for (let i = 0; i < 20; i++) { 58 orders.add(shuffleAnimals(Math.random).map(a => a.key).join(',')); 59 } 60 assert.ok(orders.size > 1, 'shuffleAnimals should produce different orderings'); 61 }); 62 63 test('deck drawn without replacement covers all animals once', () => { 64 const deck = shuffleAnimals(Math.random); 65 const seen = new Set(); 66 while (deck.length) { 67 const a = deck.pop(); 68 assert.ok(!seen.has(a.key), `${a.key} appeared twice in one deck`); 69 seen.add(a.key); 70 } 71 assert.equal(seen.size, ANIMALS.length); 72 }); 73 74 test('pickAnimal returns a different animal when exclusion matches', () => { 75 const first = ANIMALS[0]; 76 const result = pickAnimal(() => 0, first.key); 77 assert.notEqual(result.key, first.key, 'Should not return excluded animal'); 78 }); 79 80 test('pickAnimal with no exclusion can return any animal', () => { 81 const seen = new Set(); 82 for (let i = 0; i < 10000; i++) { 83 seen.add(pickAnimal(Math.random).key); 84 } 85 assert.equal(seen.size, ANIMALS.length, 'All animals should be reachable via pickAnimal'); 86 });