import test from "node:test"; import assert from "node:assert/strict"; import { createSplashState, advanceSplash, setSplashReduced, describeSplash, splashPosition, splashVisible, } from "../src/scripts/splash-motion-state.mjs"; test("six adjacent swaps return every card to its initial slot without a loop boundary jump", () => { const initial = Object.freeze(createSplashState()); for (let leg = 0; leg < 6; leg++) { const held = describeSplash( advanceSplash(initial, leg * 6000 + 3700, true), ); const flight = describeSplash( advanceSplash(initial, leg * 6000 + 4500, true), ); const settled = describeSplash( advanceSplash(initial, leg * 6000 + 5300, true), ); assert.equal(held.cards.filter((card) => card.progress !== 0).length, 0); assert.equal( flight.cards.filter((card) => card.progress > 0 && card.progress < 1) .length, 2, ); assert.equal(flight.phase, "moving"); assert.equal(new Set(settled.cards.map((card) => card.slot)).size, 3); const next = describeSplash(advanceSplash(initial, (leg + 1) * 6000, true)); assert.deepEqual( settled.cards.map((card) => card.slot), next.cards.map((card) => card.slot), ); } assert.deepEqual( describeSplash(advanceSplash(initial, 36000, true)), describeSplash(initial), ); assert.equal(advanceSplash(initial, 36000 * 12 + 1234, true).elapsed, 1234); assert.equal(initial.elapsed, 0); }); test("capture phases freeze, unknown phase settles, and reduced motion can resume only outside capture", () => { for (const phase of ["queued", "moving", "review"]) { const state = createSplashState(`?capture=1&phase=${phase}`); assert.equal(describeSplash(state).phase, phase); assert.deepEqual(advanceSplash(state, 9999, true), state); assert.equal(setSplashReduced(state, false).locked, true); } assert.equal( describeSplash(createSplashState("?capture=1&phase=bad")).phase, "review", ); assert.equal(describeSplash(createSplashState("?capture=1")).phase, "review"); assert.equal( describeSplash(createSplashState("?phase=review")).phase, "queued", ); const reduced = setSplashReduced(createSplashState(), true); assert.equal(describeSplash(reduced).phase, "review"); assert.equal(reduced.locked, true); assert.equal(setSplashReduced(reduced, false).locked, false); }); test("hidden or invalid elapsed time cannot advance playback", () => { const state = createSplashState(); for (const time of [-1, Infinity, NaN]) assert.deepEqual(advanceSplash(state, time, true), state); assert.deepEqual(advanceSplash(state, 5000, false), state); assert.equal(splashVisible(800, 300, 600), true); assert.equal(splashVisible(800, 299, 600), false); assert.equal(splashVisible(0, 0, 600), false); }); test("actual desktop and vertical phone anchors share exact endpoints and bounded passing movement", () => { for (const [from, to, compact] of [ [{ x: 20, y: 170 }, { x: 620, y: 54 }, false], [{ x: 12, y: 24 }, { x: 12, y: 224 }, true], ]) { assert.deepEqual(splashPosition(0, from, to, compact, 1), from); assert.deepEqual(splashPosition(1, from, to, compact, -1), to); const midway = splashPosition(0.5, from, to, compact, 1); assert.equal(midway.x, (from.x + to.x) / 2 + (compact ? 6 : 0)); assert.equal(midway.y, (from.y + to.y) / 2 - (compact ? 0 : 6)); } });