import assert from 'node:assert/strict'; import {readFile} from 'node:fs/promises'; import ts from 'typescript'; import vm from 'node:vm'; import * as THREE from 'three'; const source=await readFile(new URL('../src/input/MediaLoader.ts',import.meta.url),'utf8'); function harness(text){ const statuses=[];let resolvePlay;let rejectPlay; const video={videoWidth:400,videoHeight:500,paused:false,playCalls:0,pause(){this.paused=true;},load(){},removeAttribute(){},play(){this.playCalls++;return new Promise((resolve,reject)=>{resolvePlay=resolve;rejectPlay=reject;});}}; const exports={};vm.runInNewContext(ts.transpileModule(text,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022}}).outputText,{exports,require:()=>THREE,document:{createElement:()=>video},URL:{createObjectURL:()=> 'blob:video',revokeObjectURL(){}}}); const loader=new exports.MediaLoader(()=>{},message=>statuses.push(message)); return {loader,video,statuses,resolve:()=>resolvePlay(),reject:()=>rejectPlay(new Error('blocked'))}; } const tick=async()=>{for(let i=0;i<6;i++)await Promise.resolve();}; async function testSuccess(text){const h=harness(text);h.loader.load({type:'video/mp4'});h.video.onloadeddata();h.reject();await tick();assert.match(h.statuses.at(-1),/자동 재생/);h.loader.retry();h.resolve();await tick();const result=h.statuses.at(-1);h.loader.dispose();return result;} const prior=source.replace(".then(() => { if (token === this.token && video === this.activeVideo) this.onStatus(''); })",''); assert.notEqual(await testSuccess(prior),'','mutation without retry success status reproduces stuck error'); assert.equal(await testSuccess(source),'','actual successful retry clears playback error'); const stale=harness(source);stale.loader.load({type:'video/mp4'});stale.video.onloadeddata();stale.reject();await tick();stale.loader.retry();stale.loader.cancelPending();stale.resolve();await tick();assert.match(stale.statuses.at(-1),/自|자동/,'stale retry may not announce ready for replaced media');stale.loader.dispose(); console.log('Media retry: successful playback emits recovery, blocked play and stale retry preserve error (actual MediaLoader, DOM/play promises doubled)'); const recovered=harness(source);recovered.loader.load({type:'video/mp4'});recovered.video.onloadeddata();recovered.reject();await tick(); recovered.loader.cancelPending(true);recovered.loader.retry(); assert.equal(recovered.video.playCalls,2,'context recovery preserves replay of the active blocked video'); recovered.resolve();await tick();assert.equal(recovered.statuses.at(-1),'');recovered.loader.dispose();