将分层反馈强化版提升为正式 main,统一协作入口并移除外部构建路径
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
||||
import {Music} from './src/music.mjs';import {HintArrows} from './src/hint-arrows.mjs';import {boot} from './qa/runtime-harness.mjs';import {solve} from './src/upstream/rules.mjs';
|
||||
test('music loops independently, persists mute and cancels in background',()=>{const stored=new Map(),calls=[];const api={getStorageSync:k=>stored.get(k),setStorageSync:(k,v)=>stored.set(k,v),createInnerAudioContext:()=>({stop(){calls.push('stop');},play(){calls.push(this.src);},onError(){}})};const m=new Music(api);m.scene('select');m.scene('select');assert.equal(calls.filter(x=>x==='music/select.wav').length,1);assert.equal(m.audio.loop,true);m.scene('play');m.suspend();m.scene('select');assert.equal(m.playing,null);m.resume();assert.equal(m.playing,'select');m.toggle();assert.equal(new Music(api).enabled,false);});
|
||||
test('old arrows retain distance, rush to endpoint and fresh arrows move at base speed',()=>{const a=new HintArrows(),motion={total:300},events=[];let f=a.frame('a',0,events);a.heads(f,motion,0);f=a.frame('a',100,events);assert.equal(a.heads(f,motion,0)[0],6.5);events.push({sequence:1,kind:'move'});f=a.frame('a',116,events);const at=a.heads(f,motion,30);assert.ok(at[0]>6.5&&at[0]<10);assert.equal(at[1],30);f=a.frame('a',216,events);const next=a.heads(f,motion,30);assert.ok(next[0]>150);assert.equal(next[1],36.5);for(let t=316;t<=416;t+=100)a.heads(a.frame('a',t,events),motion,30);assert.ok(a.particles.every(p=>!p.rush));a.reset();assert.equal(a.key,null);});
|
||||
test('settings have exactly three independent preferences, and hint has its own cue',()=>{const ui=boot();ui.select(3);ui.button('设置');assert.deepEqual(Array.from(ui.api.buttons(),b=>b.label),['音乐:开','音效开','振动:开','完成']);ui.button('完成');ui.button('指路');assert.equal(ui.played.at(-1),'audio/hint.wav');ui.button('选关');assert.ok(ui.played.includes('music/select.wav'));ui.button('下一页');assert.equal(ui.played.at(-1),'audio/ui.wav');});
|
||||
test('actual fixed numeric node uses checkpoint pitch, final cell uses complete chord',()=>{const pack=JSON.parse(fs.readFileSync(new URL('./src/upstream/levels.json',import.meta.url)));const levels=pack.playOrder.map(id=>pack.levels.find(l=>l.id===id));const i=levels.findIndex(l=>l.cells.some(c=>c.clue>1&&c.clue<l.cells.length));const l=levels[i],ui=boot();ui.select(i);const route=solve(l)[0];for(const id of route){ui.advance(80);ui.cell(id);const e=ui.api.snapshot().feedback.events.at(-1);if(e.kind==='checkpoint')assert.equal(ui.played.at(-1),'audio/checkpoint-'+e.step+'.wav');}assert.equal(ui.played.at(-1),'audio/complete.wav');assert.ok(ui.api.snapshot().feedback.events.some(e=>e.kind==='checkpoint'));});
|
||||
test('two original music loops are quiet, nonempty and have a smooth loop seam',()=>{for(const name of ['select','play']){const b=fs.readFileSync(new URL('./music/'+name+'.wav',import.meta.url));assert.equal(b.readUInt32LE(24),22050);assert.ok(b.length>600000);assert.ok(Math.abs(b.readInt16LE(44)-b.readInt16LE(b.length-2))<100);}});
|
||||
Reference in New Issue
Block a user