aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-14 12:59:57 -0700
committerAdam Soltys <[email protected]>2026-09-14 12:59:57 -0700
commitd730ea49feb389b43362b1044964f5a9e03ae4ff (patch)
tree5f99d011d6c994b57f45d657d3eb8868e1d4ded8 /tools
parentdd1489303f59ccef6b322142f94e08d750c06e79 (diff)
downloadcoinosv3-d730ea49feb389b43362b1044964f5a9e03ae4ff.tar.gz
coinosv3-d730ea49feb389b43362b1044964f5a9e03ae4ff.zip
A post arrives whole.
A feed row painted the moment its event landed and then finished itself over the next second or two: a punk turning into a photograph, a blank gap becoming the picture. Now a post waits at the door until its author's profile has landed and their face and the images in its body are fetched and decoded — bounded by two seconds, so a slow host holds a post briefly rather than the feed forever. This covers the first load, live arrivals (which are counted behind the pill only once whole), paging older posts, and profile pages. The cached page at boot still paints instantly and warms in the background. feed-live-test serves a deliberately slow picture and checks, from the first instant the row exists, that its image is already decoded. 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.js39
1 files changed, 37 insertions, 2 deletions
diff --git a/tools/feed-live-test.js b/tools/feed-live-test.js
index fd50191..afbbf10 100644
--- a/tools/feed-live-test.js
+++ b/tools/feed-live-test.js
@@ -30,7 +30,15 @@ const signed = (content, ago) => finalizeEvent(
const seeded = Array.from({ length: 25 }, (_, i) => signed('post number ' + (i + 1), 600 + i * 60));
const html = await buildHtml({ minify: true, pwa: false });
-const server = Bun.serve({ port: 5296, fetch: () => new Response(html, { headers: { 'content-type': 'text/html' } }) });
+// a picture that takes its time, so a post showing it must have waited
+const PNG = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==', 'base64');
+const server = Bun.serve({ port: 5296, fetch: async (req) => {
+ if (new URL(req.url).pathname === '/slow.png') {
+ await sleep(700);
+ return new Response(PNG, { headers: { 'content-type': 'image/png', 'cache-control': 'no-store' } });
+ }
+ return new Response(html, { headers: { 'content-type': 'text/html' } });
+} });
const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: 'new', args: ['--no-sandbox'] });
const page = await browser.newPage();
await page.evaluateOnNewDocument(() => {
@@ -111,7 +119,10 @@ try {
const fresh = signed('BRAND NEW POST', 0);
const delivered = await page.evaluate((ev) => window.__inject(ev), fresh);
check('...a post really arrives on a live subscription', delivered > 0, delivered + ' socket(s)');
- await sleep(900);
+ // A post waits at the door for its author's face and its pictures (or the
+ // two-second deadline, for a face nobody has) before it is even counted —
+ // so give it that long, and no longer.
+ await sleep(2600);
const after = await page.evaluate(() => ({
y: Math.round(window.scrollY),
pill: (document.querySelector('.feed-new-pill') || {}).textContent || '',
@@ -145,6 +156,30 @@ try {
await page.evaluate(() => /ANOTHER ONE/.test(document.querySelector('.notes-feed')?.innerText || '')
&& !document.querySelector('.feed-new-pill')));
+ console.log('\n[a post arrives whole]');
+ // A row used to paint first and fill in its picture after. Watch the feed
+ // from the instant the post is injected: the first time the row exists,
+ // its image must already be decoded.
+ await page.evaluate(() => {
+ window.__firstSight = null;
+ const feed = document.querySelector('.notes-feed');
+ const look = () => {
+ if (window.__firstSight) return;
+ const row = [...feed.querySelectorAll('.row')].find((n) => /PICTURE POST/.test(n.innerText || ''));
+ if (!row) return;
+ const img = row.querySelector('img.note-img');
+ window.__firstSight = { img: !!img, ready: !!(img && img.complete && img.naturalWidth > 0), at: performance.now() };
+ };
+ new MutationObserver(look).observe(feed, { childList: true, subtree: true });
+ });
+ 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);
+ const sight = await page.evaluate(() => window.__firstSight);
+ check('the post is in the feed', !!sight && sight.img, JSON.stringify(sight));
+ 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' : '');
+
console.log('\n[coming back after being away]');
// the throttle would otherwise swallow a refresh this soon after the last
// the app was hidden for a while, then focused again