clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

main
miau-is-true / tests / word-lab.test.js
word-lab.test.js 3.7K
1import test from 'node:test';2import assert from 'node:assert/strict';3import { readFile } from 'node:fs/promises';4import { createGame } from '../src/engine.js';5import { loadMod } from '../src/mods.js';6import { checkLevel } from '../src/solver/check-level.js';78const source = await readFile(new URL('../mods/word-lab.cjs', import.meta.url), 'utf8');9const pack = loadMod(source, { filename: 'word-lab.cjs' });10const move = (game, direction, count = 1) => {11 const delta = { up: [0, -1], down: [0, 1], left: [-1, 0], right: [1, 0] }[direction];12 for (let index = 0; index < count; index++) game.step(...delta);13};1415test('Word Lab has a stable identity and three authored levels', () => {16 assert.equal(pack.manifest.rules, 2);17 assert.equal(pack.manifest.id, 'word-lab');18 assert.equal(pack.manifest.version, '1.0.0');19 assert.deepEqual(pack.levels.map(level => level.id), [20 'shared-control',21 'change-what-you-are',22 'rules-are-cargo',23 ]);24 assert.equal(pack.palette.GEM, '💎');25 const cargo = pack.levels[2];26 assert.equal(cargo.title, 'Push beats stop');27 assert.equal(cargo.hint, 'ROCK is STOP and PUSH at once. Which one wins when you walk into it?');28 assert.equal(cargo.allowBypass, true);29 assert.equal(cargo.allowHandsOff, true);30});3132test('shared control uses AND to let ROCK solve the level while MIAU is stopped', () => {33 const game = createGame(pack.levels[0]);34 assert.equal(game.has('MIAU', 'YOU'), true);35 assert.equal(game.has('ROCK', 'YOU'), true);36 assert.equal(game.has('WALL', 'STOP'), true);3738 const first = game.step(1, 0);39 assert.equal(first.accepted, true);40 assert.deepEqual(41 (({ id, kind, noun, x, y }) => ({ id, kind, noun, x, y }))(game.getState().objects.find(object => object.id === 'shared-player')),42 { id: 'shared-player', kind: 'object', noun: 'MIAU', x: 1, y: 2 },43 );44 assert.equal(game.getState().objects.find(object => object.id === 'shared-rock-object').x, 6);45 move(game, 'right', 2);46 assert.equal(game.getState().won, true);47});4849test('noun transformation changes ROCK into the controllable GEM', () => {50 const game = createGame(pack.levels[1]);51 const transformed = game.getState().objects.find(object => object.id === 'change-rock-object');52 assert.equal(transformed.noun, 'GEM');53 assert.equal(game.has('ROCK', 'GEM'), true);54 assert.equal(game.has('GEM', 'YOU'), true);55 assert.equal(game.getState().objects.some(object => game.properties(object).includes('YOU') && object.noun === 'ROCK'), false);5657 move(game, 'right', 6);58 assert.equal(game.getState().won, true);59});6061test('PUSH beats STOP in the authored cargo proof', () => {62 const game = createGame(pack.levels[2]);63 assert.equal(game.has('ROCK', 'PUSH'), true);64 assert.equal(game.has('ROCK', 'STOP'), true);6566 move(game, 'right', 7);67 assert.equal(game.getState().won, true);68 assert.equal(game.has('ROCK', 'STOP'), true);69});7071test('cargo proof imports cleanly and classifies its allowed routes', () => {72 const result = checkLevel(pack.levels[2], { cap: 100_000 });73 assert.equal(result.ok, true);74 assert.equal(result.issues.length, 0);75 assert.deepEqual(result.warnings, []);76 assert.equal(result.checks.result.status, 'SOLVED');77 assert.equal(result.checks.bypass.status, 'SOLVED');78 assert.equal(result.checks.handsOff.status, 'SOLVED');79});8081test('editing a stacked predicate removes STOP while preserving PUSH', () => {82 const game = createGame(pack.levels[2]);83 move(game, 'right', 4);8485 // Reach the STOP word from below and push it out of the sentence.86 move(game, 'up', 2);87 assert.equal(game.has('ROCK', 'STOP'), false);88 assert.equal(game.has('ROCK', 'PUSH'), true);8990 // Return to the left of ROCK and push it onto FLAG.91 move(game, 'down', 2);92 move(game, 'right', 3);93 assert.equal(game.getState().won, true);94});