diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/profile-stream-test.js | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/tools/profile-stream-test.js b/tools/profile-stream-test.js new file mode 100644 index 0000000..8d15775 --- /dev/null +++ b/tools/profile-stream-test.js @@ -0,0 +1,58 @@ +// A profile visited for the first time, from search: its posts used to land +// all at once after several seconds of blank (the slowest relay, then every +// post's media). Now the page shows post-shaped placeholders while it waits, +// the first posts paint as the quick relays answer, and the top search +// results are fetched before they're tapped. Reads real relays +// (relays: 'read'; nothing is published). +// Run: bun tools/profile-stream-test.js (Q="ben arc" to search someone else) +import puppeteer from './puppeteer.js'; +import { buildHtml } from '../build.js'; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +let ok = true; +const check = (n, c, d = '') => { console.log(` ${c ? '✓' : '✗'} ${n}${d ? ' — ' + d : ''}`); if (!c) ok = false; }; +const Q = process.env.Q || 'fiatjaf'; + +const html = await buildHtml({ minify: true, pwa: false }); +const server = Bun.serve({ port: 0, fetch: () => new Response(html, { headers: { 'content-type': 'text/html' } }) }); +const browser = await puppeteer.launch({ relays: 'read', executablePath: '/usr/bin/google-chrome', headless: 'new', args: ['--no-sandbox'] }); +const page = await browser.newPage(); +const errs = []; +page.on('pageerror', (e) => errs.push(String(e))); +try { + await page.setViewport({ width: 390, height: 844 }); + if (process.env.DARK) await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]); + await page.goto(server.url.href + 'feed', { waitUntil: 'domcontentloaded' }); + await sleep(1500); + await page.evaluate(() => [...document.querySelectorAll('button')].find((b) => b.getAttribute('aria-label') === 'Search')?.click()); + await page.waitForSelector('.user-search-main', { timeout: 10000 }); + await page.type('.user-search-main', Q, { delay: 60 }); + // the result rows: people (not the "posts that say this" or #topic rows) + const rows = () => page.evaluate(() => [...document.querySelectorAll('.list .item')].filter((r) => !/^[\u{1F50D}#]/u.test(r.textContent.trim())).map((r) => r.textContent.trim().slice(0, 40))); + let found = []; + for (let i = 0; i < 60 && !found.length; i++) { found = await rows(); if (!found.length) await sleep(250); } + if (!found.length) console.log(await page.evaluate(() => document.querySelector('.user-search-main')?.closest('.col')?.parentElement?.innerHTML.slice(0, 1500))); + check('search finds people', found.length > 0, found.slice(0, 2).join(' | ')); + const wait = Number(process.env.WAIT || 0); // ms between results and the tap (prefetch's head start) + if (wait) await sleep(wait); + const t0 = Date.now(); + await page.evaluate(() => [...document.querySelectorAll('.list .item')].filter((r) => !/^[\u{1F50D}#]/u.test(r.textContent.trim()))[0].click()); + let ghostAt = 0, firstAt = 0, rowsAt3 = 0; + for (let i = 0; i < 200; i++) { + const s = await page.evaluate(() => ({ + ghost: !!document.querySelector('.note-ghosts'), + rows: document.querySelectorAll('.notes-feed:not(.note-ghosts) > [data-key]').length, + })); + const t = Date.now() - t0; + if (s.ghost && !ghostAt) { ghostAt = t; if (process.env.SHOT) await page.screenshot({ path: process.env.SHOT }); } + if (s.rows && !firstAt) firstAt = t; + if (t >= 3000 && !rowsAt3) rowsAt3 = s.rows || -1; + if (firstAt && t >= 3000) break; + await sleep(50); + } + console.log(` placeholder ${ghostAt ? ghostAt + ' ms' : 'not seen'}, first post ${firstAt || '—'} ms, rows at 3 s ${rowsAt3}`); + check('posts arrive', firstAt > 0); + check('...while waiting, the page says posts are loading', !!ghostAt || firstAt < 300, ghostAt ? 'placeholder shown' : 'posts were already in hand'); + check('no page errors', !errs.length, errs.join(' | ')); +} catch (e) { console.error(e); ok = false; } finally { await browser.close(); server.stop(); } +console.log(ok ? '\nPASS' : '\nFAIL'); +process.exit(ok ? 0 : 1); |
