aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-14 13:46:58 -0700
committerAdam Soltys <[email protected]>2026-09-14 13:46:58 -0700
commit0c0ba1b0129a140dc540f0fb8588b3ffdd44350c (patch)
tree26c5e00dc2a7fb6fc1ba13caa8015e5ee09f1e68 /tools
parentd730ea49feb389b43362b1044964f5a9e03ae4ff (diff)
downloadcoinosv3-0c0ba1b0129a140dc540f0fb8588b3ffdd44350c.tar.gz
coinosv3-0c0ba1b0129a140dc540f0fb8588b3ffdd44350c.zip
A new post opens up instead of appearing.
A post let in at the top of an open feed was there on the next paint — one frame nothing, the next a whole row, the page shoved down by that much. Now it opens over a third of a second: height from nothing to its own, fading in as it goes, and a repaint mid-way resumes where it was. The same happens to the posts the pill lets in. That needed the morph to know which row is which. Children were matched by position, so a new first row was patched onto the old first row's node and every row below onto its neighbour's — the node the new post was built as never reached the page. A list whose every child carries a data-key is now reconciled by key: new rows are inserted as themselves, the rest keep their nodes and move. Feed rows and their hairlines carry the post id. Partially keyed lists keep the positional rule. feed-live-test catches the arriving row mid-animation: shorter than it will be, one animation running, and settled clean afterwards. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
Diffstat (limited to 'tools')
-rw-r--r--tools/feed-live-test.js16
1 files changed, 15 insertions, 1 deletions
diff --git a/tools/feed-live-test.js b/tools/feed-live-test.js
index afbbf10..01ec384 100644
--- a/tools/feed-live-test.js
+++ b/tools/feed-live-test.js
@@ -174,9 +174,23 @@ try {
});
const t0 = await page.evaluate(() => performance.now());
await page.evaluate((ev) => window.__inject(ev), signed('PICTURE POST http://localhost:5296/slow.png?' + Date.now(), 0));
- await sleep(3000);
+ await page.waitForFunction(() => !!window.__firstSight, { timeout: 4000 }).catch(() => {});
+ await sleep(120); // a hair in: the animation has been started and not finished
const sight = await page.evaluate(() => window.__firstSight);
check('the post is in the feed', !!sight && sight.img, JSON.stringify(sight));
+ // ...and it opened rather than appeared: caught mid-animation, shorter
+ // than it will be, and full height once the animation is done
+ const mid = await page.evaluate(() => {
+ const row = [...document.querySelectorAll('.notes-feed > .row')].find((n) => /PICTURE POST/.test(n.innerText || ''));
+ return row ? { anims: row.getAnimations().length, h: row.getBoundingClientRect().height } : null;
+ });
+ await sleep(600);
+ const settled = await page.evaluate(() => {
+ const row = [...document.querySelectorAll('.notes-feed > .row')].find((n) => /PICTURE POST/.test(n.innerText || ''));
+ return row ? { anims: row.getAnimations().length, h: row.getBoundingClientRect().height, overflow: row.style.overflow } : null;
+ });
+ check('...and it opened rather than appeared', !!mid && !!settled && mid.anims > 0 && mid.h < settled.h
+ && settled.anims === 0 && settled.h > 0 && !settled.overflow, JSON.stringify({ mid, settled }));
check('...and its picture was already decoded the first time the row existed', !!sight && sight.ready);
check('...having waited for the slow host', !!sight && sight.at - t0 >= 700, sight ? Math.round(sight.at - t0) + 'ms' : '');