kgames

KGames — free keyboard games for kids
git clone https://www.keyboard.games/code/kgames.git
Log | Files | Refs | README | LICENSE

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 });