Cover large timeline keyframe selections in the browser suite

This commit is contained in:
Olive Vaughn 2026-10-04 02:14:02 -04:00
parent 6de71c4c66
commit 064a3d7c19

View file

@ -247,8 +247,48 @@ try {
await evaluate(`document.querySelector('.tl-tracks').dispatchEvent(new KeyboardEvent('keydown',{key:'a',metaKey:true,bubbles:true}))`); await evaluate(`document.querySelector('.tl-tracks').dispatchEvent(new KeyboardEvent('keydown',{key:'a',metaKey:true,bubbles:true}))`);
await sleep(100); await sleep(100);
assert.equal(await evaluate('document.querySelectorAll("button.tl-key.selected").length'), 4, 'Command-A selects all visible keyframes'); assert.equal(await evaluate('document.querySelectorAll("button.tl-key.selected").length'), 4, 'Command-A selects all visible keyframes');
await evaluate(`(() => {
const k=cljs.core.keyword,v=cljs.core.vector,m=cljs.core.hash_map;
let c=cljs.core.get(arthur.footage.store.entry(cljs.core.get(cljs.core.deref(re_frame.db.app_db),k('clip/current'))),k('clip'));
let keys=m();
for(let i=0;i<1000;i++) keys=cljs.core.assoc(keys,i,v(i,0));
for(const channel of ['pos','scale']) c=cljs.core.assoc_in(c,v(k('symbols'),k('main'),k('nodes'),k('a'),k('channels'),v(k('xform'),k(channel))),arthur.domain.channel.keyed(keys,k('linear')));
c=cljs.core.assoc_in(c,v(k('symbols'),k('main'),k('frames')),1200);
const id=arthur.footage.store.install_BANG_(m(k('clip'),c,k('store'),m()),'large-selection-browser');
cljs.core.swap_BANG_(re_frame.db.app_db,db=>cljs.core.assoc(db,k('clip/current'),id));
})()`);
await sleep(300);
assert.equal(await evaluate('document.querySelectorAll("button.tl-key").length'),2000);
await evaluate(`(() => {
window.shiftCalls=0;
window.originalShifted=arthur.domain.keyframes.shifted;
arthur.domain.keyframes.shifted=(...args)=>{window.shiftCalls++;return window.originalShifted(...args);};
document.querySelector('.tl-tracks').dispatchEvent(new KeyboardEvent('keydown',{key:'a',metaKey:true,bubbles:true}));
})()`);
await sleep(150);
assert.equal(await evaluate('document.querySelectorAll("button.tl-key.selected").length'),2000);
assert.equal(await evaluate('window.shiftCalls'),0,'selection performs no group shift calculations per marker');
await evaluate(`(() => {
const key=document.querySelector('button.tl-key'), b=key.parentElement.getBoundingClientRect();
key.dispatchEvent(new PointerEvent('pointerdown',{bubbles:true,pointerId:90,clientX:b.left}));
key.dispatchEvent(new PointerEvent('pointermove',{bubbles:true,pointerId:90,clientX:b.left+b.width*2/1200}));
})()`);
await sleep(150);
assert.equal(await evaluate('window.shiftCalls'),1,'large group drag computes shifted positions once for all 2000 markers');
await evaluate(`(() => {
const key=document.querySelector('button.tl-key');
key.dispatchEvent(new PointerEvent('pointerup',{bubbles:true,pointerId:90}));
arthur.domain.keyframes.shifted=window.originalShifted;
const k=cljs.core.keyword,v=cljs.core.vector;
const c=arthur.footage.store.entry(cljs.core.get(cljs.core.deref(re_frame.db.app_db),k('clip/current')));
return cljs.core.clj__GT_js(cljs.core.sort(cljs.core.keys(cljs.core.get_in(c,
v(k('clip'),k('symbols'),k('main'),k('nodes'),k('a'),k('channels'),v(k('xform'),k('pos')),k('keys'))))));
})()`).then(keys=>assert.equal(keys[0],2,'drop commits before the pointerup handler returns'));
await sleep(150);
assert.equal(await evaluate('document.querySelectorAll("button.tl-key.selected").length'),2000,'drop preserves the entire large selection');
assert.equal(await evaluate('[...document.querySelectorAll("button.tl-key")].filter(el=>el.style.transform).length'),0,'committed keys replace the preview without leftover transforms');
assert.equal(errors.length, 0, JSON.stringify(errors)); assert.equal(errors.length, 0, JSON.stringify(errors));
console.log('PASS: passive overview ticks; automation keyframe selection, dragging, marquee, keyboard editing, and undo'); console.log('PASS: passive overview ticks; automation editing, group edits, undo, and 2000-key selection performance');
} finally { } finally {
if (ws?.readyState === WebSocket.OPEN) ws.close(); if (ws?.readyState === WebSocket.OPEN) ws.close();
chrome.kill('SIGTERM'); chrome.kill('SIGTERM');