54 lines
3.1 KiB
JavaScript
54 lines
3.1 KiB
JavaScript
// Controlled audio ended events; real capture function, no camera/API writes.
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {execSync} from 'node:child_process';
|
|
import {fileURLToPath,pathToFileURL} from 'node:url';
|
|
const {chromium}=await import(pathToFileURL(execSync('npm root -g',{encoding:'utf8'}).trim()+'/playwright/index.mjs').href);
|
|
const browser=await chromium.launch();
|
|
try {
|
|
const page=await browser.newPage();const errors=[];
|
|
page.on('pageerror',e=>errors.push(e.message));
|
|
const source=fs.readFileSync(fileURLToPath(new URL('../js/app.js',import.meta.url)),'utf8');
|
|
await page.route('**/api/**',r=>{assert.equal(r.request().method(),'GET');return r.fulfill({json:{ok:true,user:{kind:'browser'}}});});
|
|
await page.route('**/assets/voice/*.mp3',r=>r.fulfill({body:r.request().url().split('/').pop()}));
|
|
await page.route('**/js/app.js*',r=>r.fulfill({contentType:'text/javascript',body:source.replace(/\}\)\(\);\s*$/,`
|
|
window.__countdown = {
|
|
start: function(step) { camStep=step; currentScreen='s-cam'; camLive=true; shutterLock=false;
|
|
captureFromVideo=function(){window.__shots.push(step);return 'fixture';};
|
|
checkStill=function(){return Promise.resolve(null);};
|
|
onPhotoCaptured=function(){window.__completed.push(step);}; doCapture(); },
|
|
again:doCapture, cancel:function(){camSeq++; voice.stop(true);},
|
|
busy:function(){return shutterLock;}
|
|
};
|
|
})();`)}));
|
|
await page.addInitScript(()=>{
|
|
window.__audio=[];window.__shots=[];window.__completed=[];
|
|
window.AudioContext=class {
|
|
constructor(){this.state='running';this.destination={};}
|
|
decodeAudioData(ab,resolve){const b={id:new TextDecoder().decode(ab),duration:3};resolve(b);return Promise.resolve(b);}
|
|
createBufferSource(){return {connect(){},stop(){},start(){window.__audio.push(this);}};}
|
|
};
|
|
});
|
|
await page.goto(process.env.H5_BASE_URL||'http://127.0.0.1:8080/');
|
|
await page.locator('body').click({position:{x:2,y:2}});
|
|
await page.waitForTimeout(300);
|
|
for(let step=0;step<3;step++){
|
|
await page.evaluate(n=>window.__countdown.start(n),step);
|
|
await page.waitForFunction(n=>window.__audio.length===n,step+1);
|
|
assert.equal(await page.evaluate(()=>window.__audio.at(-1).buffer.id),'countdown-321.mp3');
|
|
await page.evaluate(()=>window.__countdown.again());
|
|
await page.waitForTimeout(350);
|
|
assert.equal(await page.evaluate(()=>window.__shots.length),step,'no capture before audio ended');
|
|
assert(await page.evaluate(()=>window.__countdown.busy()));
|
|
await page.evaluate(()=>window.__audio.at(-1).onended());
|
|
await page.waitForFunction(n=>window.__completed.length===n,step+1);
|
|
}
|
|
await page.evaluate(()=>window.__countdown.start(0));
|
|
await page.waitForFunction(()=>window.__audio.length===4);
|
|
await page.evaluate(()=>window.__countdown.cancel());
|
|
await page.waitForTimeout(700);
|
|
assert.equal(await page.evaluate(()=>window.__shots.length),3,'cancelled countdown never captures');
|
|
assert.deepEqual(errors,[]);
|
|
console.log('PASS: each of 3 shots waits for countdown ended; duplicate shutter ignored; cancellation safe');
|
|
}finally{await browser.close();}
|