work-lib.test.js (2854B)
1 'use strict'; 2 const { test } = require('node:test'); 3 const assert = require('node:assert/strict'); 4 5 const lib = require('../../games/work/lib.js'); 6 7 test('fillTemplate substitutes all blanks and leaves no braces', () => { 8 lib.MADLIB_TEMPLATES.forEach((tpl) => { 9 const values = {}; 10 tpl.blanks.forEach((b) => { values[b.key] = 'X' + b.key; }); 11 const out = lib.fillTemplate(tpl, values); 12 assert.ok(!/[{}]/.test(out), `${tpl.id}: leftover braces in "${out}"`); 13 tpl.blanks.forEach((b) => { 14 assert.ok(out.includes('X' + b.key), `${tpl.id}: missing value for ${b.key}`); 15 }); 16 }); 17 }); 18 19 test('every story placeholder has a matching blank key', () => { 20 lib.MADLIB_TEMPLATES.forEach((tpl) => { 21 const placeholders = new Set((tpl.story.match(/\{(\w+)\}/g) || []).map(s => s.slice(1, -1))); 22 const keys = new Set(tpl.blanks.map(b => b.key)); 23 placeholders.forEach((p) => assert.ok(keys.has(p), `${tpl.id}: placeholder {${p}} has no blank`)); 24 keys.forEach((k) => assert.ok(placeholders.has(k), `${tpl.id}: blank ${k} unused in story`)); 25 }); 26 }); 27 28 test('typewriterSteps passes through common prefix then ends at target', () => { 29 const steps = lib.typewriterSteps('cat', 'car'); 30 assert.equal(steps[steps.length - 1], 'car'); 31 assert.ok(steps.includes('ca'), 'should backspace to common prefix "ca"'); 32 }); 33 34 test('typewriterSteps from empty only grows', () => { 35 assert.deepEqual(lib.typewriterSteps('', 'hi'), ['h', 'hi']); 36 }); 37 38 test('normalizeName trims, collapses, lowercases', () => { 39 assert.equal(lib.normalizeName(' Sam Smith '), 'sam smith'); 40 }); 41 42 test('isNameReady needs at least 2 chars', () => { 43 assert.equal(lib.isNameReady('a'), false); 44 assert.equal(lib.isNameReady(' a '), false); 45 assert.equal(lib.isNameReady('Bo'), true); 46 }); 47 48 test('formatTime formats seconds to 2 decimals', () => { 49 assert.equal(lib.formatTime(3420), '3.42 s'); 50 assert.equal(lib.formatTime(0), '0.00 s'); 51 }); 52 53 test('isNewRecord: null best, faster, slower', () => { 54 assert.equal(lib.isNewRecord(1000, null), true); 55 assert.equal(lib.isNewRecord(900, 1000), true); 56 assert.equal(lib.isNewRecord(1000, 1000), false); 57 assert.equal(lib.isNewRecord(1100, 1000), false); 58 }); 59 60 test('pickTemplate returns a real template', () => { 61 const t = lib.pickTemplate(() => 0); 62 assert.equal(t, lib.MADLIB_TEMPLATES[0]); 63 }); 64 65 test('every mad lib cites a public-domain source with author and link', () => { 66 lib.MADLIB_TEMPLATES.forEach((tpl) => { 67 assert.ok(tpl.source, `${tpl.id}: missing source`); 68 assert.ok(tpl.source.title && tpl.source.title.length > 3, `${tpl.id}: source needs a title`); 69 assert.ok(tpl.source.author && tpl.source.author.length > 2, `${tpl.id}: source needs an author`); 70 assert.match(tpl.source.url, /^https:\/\/www\.gutenberg\.org\//, `${tpl.id}: source needs a public link`); 71 }); 72 });