/** Native input while a real progressive copy is still publishing. */ import assert from 'node:assert/strict'; export async function editDuringCopy({call,evaluate,wait,count}){ assert.ok(count>=1000,'concurrent input probe requires at least 1000 source nodes'); await wait('window.__canvasPerformance.read().firstPresentedFrameMs!==null','copy did not present before native input'); assert.equal(await evaluate('window.__canvasPerformance.read().localCompleteMs===null'),true,'copy finished before input probe'); // Copied cards overlap originals. Find an actually exposed point; never send a // synthetic double-click through the copied card to the original underneath. const point=await evaluate(`(()=>{ const label=document.querySelector('.react-flow__node[data-id="perf-0"] [aria-label^="单击选中"]'); if(!label)throw Error('original text label is missing'); const rect=label.getBoundingClientRect(); for(let y=Math.max(0,rect.top)+3;y{ const element=document.activeElement,samples=[]; const input=()=>{ const sample={inputAt:performance.now(),value:element.value,phase:window.__copyInputProbe.phase,committed:window.__copyInputProbe.progress(),copyActive:window.__canvasPerformance.read().localCompleteMs===null}; samples.push(sample); requestAnimationFrame(()=>requestAnimationFrame(()=>{ sample.frameAt=performance.now();sample.frameDelayMs=sample.frameAt-sample.inputAt; sample.retained=element.isConnected&&document.activeElement===element; sample.presentedValue=element.value;sample.mountedNodes=document.querySelectorAll('.react-flow__node').length; })); }; element.addEventListener('input',input); window.__copyInputProbe={element,samples,phase:'early',progress(){ const status=document.querySelector('[aria-label="导入任务 1"] p[role="status"]')?.textContent??''; return Number(status.match(/·\\s*(\\d+)\\s*项/)?.[1]??0); },dispose(){element.removeEventListener('input',input);}}; })()`); await call('Input.imeSetComposition',{text:'复',selectionStart:1,selectionEnd:1}); await call('Input.insertText',{text:'复制期间输入'}); for(const text of [' A',' B',' C']){ await call('Input.insertText',{text}); await wait(`window.__copyInputProbe.samples.at(-1)?.frameAt!==undefined`,'native input did not reach its next frame'); } // Keep the same native editor alive through later publication and ACK work. // Small scenarios can finish during the early burst; the scale gate uses 10k. if(count>=10000)for(const [phase,fraction,text] of [['middle',.5,' M'],['tail',.9,' T']]){ await wait(`window.__copyInputProbe.progress()>=${Math.floor((count+3)*fraction)}`,'copy did not reach '+phase+' publication'); assert.equal(await evaluate('window.__canvasPerformance.read().localCompleteMs===null'),true,'copy completed before '+phase+' input'); await evaluate(`window.__copyInputProbe.phase=${JSON.stringify(phase)};true`); const started=performance.now();await call('Input.insertText',{text}); const dispatchRoundTripMs=performance.now()-started; await wait(`window.__copyInputProbe.samples.at(-1)?.phase===${JSON.stringify(phase)}&&window.__copyInputProbe.samples.at(-1)?.frameAt!==undefined`,phase+' input did not reach a frame'); await evaluate(`window.__copyInputProbe.samples.at(-1).dispatchRoundTripMs=${dispatchRoundTripMs};true`); } const result=await evaluate(`(()=>{ const probe=window.__copyInputProbe,result={samples:probe.samples,value:probe.element.value,retained:probe.element.isConnected&&document.activeElement===probe.element}; probe.dispose();probe.element.blur();delete window.__copyInputProbe;return result; })()`); assert.equal(result.retained,true,'copy discarded native input DOM or focus'); assert.ok(result.value.endsWith(count>=10000?'复制期间输入 A B C M T':'复制期间输入 A B C'),'native composition/typing was overwritten'); assert.ok(result.samples.some(sample=>sample.copyActive),'all native input happened after copy completion'); if(count>=10000)for(const phase of ['middle','tail'])assert.ok(result.samples.some(sample=>sample.phase===phase&&sample.copyActive),phase+' input was not observed before completion'); assert.ok(result.samples.every(sample=>sample.retained),'copy interrupted an input presentation frame'); assert.ok(result.samples.every(sample=>sample.mountedNodes<100),'native editing mounted offscreen nodes during copy'); return result; }