diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/live-stream-test.js | 11 | ||||
| -rw-r--r-- | tools/pager-eager-test.js | 14 |
2 files changed, 19 insertions, 6 deletions
diff --git a/tools/live-stream-test.js b/tools/live-stream-test.js index 46fb7e9..ef76043 100644 --- a/tools/live-stream-test.js +++ b/tools/live-stream-test.js @@ -55,6 +55,9 @@ const pastPage = finalizeEvent({ kind: 30311, created_at: now - 50000, content: ['d', 'stream-p'], ['title', 'Zelda on Rumble'], ['status', 'ended'], ['streaming', STREAM], ['recording', 'https://rumble.com/v7gt2va-zelda.html'], ['ends', String(now - 50000)], ['p', HOST.pk, '', 'Host'], ] }, SERVICE.sk); +// who's watching (NIP-53 presence): the fan, just now; someone two hours ago is gone +const here = finalizeEvent({ kind: 10312, created_at: now - 60, content: '', tags: [['a', A, '', 'root']] }, FAN.sk); +const longGone = finalizeEvent({ kind: 10312, created_at: now - 7200, content: '', tags: [['a', A, '', 'root']] }, STALE.sk); const reaction = finalizeEvent({kind:7,created_at:now-10,content:'👍',tags:[['e',chat.id],['p',FAN.pk],['k','1311']]},HOST.sk); const messageZap = finalizeEvent({kind:9737,created_at:now-9,content:'nice comment',tags:[['e',chat.id],['p',FAN.pk],['P',HOST.pk],['amount','5'],['network','regtest']]},HOST.sk); // and months of older ones, past the first ask's month: the grid pages back through them @@ -62,7 +65,7 @@ const OLD = Array.from({ length: 130 }, (_, i) => finalizeEvent({ kind: 30311, c ['d', 'old-' + i], ['title', 'Old stream ' + i], ['status', 'ended'], ['streaming', STREAM], ['recording', STREAM], ['ends', String(now - 31 * 86400 - i * 3600)], ['p', HOST.pk, '', 'Host'], ] }, SERVICE.sk)); -const FIXTURES = [live, stale, past, pastPage, chat, zap, reaction, messageZap, ...OLD]; +const FIXTURES = [live, stale, past, pastPage, chat, zap, reaction, messageZap, here, longGone, ...OLD]; const ended = finalizeEvent({ ...live, id: undefined, sig: undefined, created_at: now - 5, tags: live.tags.map((x) => (x[0] === 'status' ? ['status', 'ended'] : x)) }, SERVICE.sk); // the site as built (the split build: hls.js arrives as its own chunk) @@ -206,6 +209,11 @@ try { // a stream that's on plays through hls.js (kept near the live edge), not Chrome's own player check('...through hls.js, kept near the live edge', await page.evaluate(() => document.querySelector('video.live-video').currentSrc.startsWith('blob:'))); check('the chat shows what was said', await waitText('hello from the chat', 8000)); + const who = () => page.evaluate(() => { const x = document.querySelector('.live-page .live-watching'); return x && { text: x.textContent, title: x.getAttribute('title') || '' }; }); + check('"watching" names who, on hover: the fan and this viewer, not someone long gone', await waitFor(() => (document.querySelector('.live-page .live-watching')?.getAttribute('title') || '').split(', ').length === 2, 8000), JSON.stringify(await who())); + check('...this viewer said they\'re here (a 10312 for the stream)', await page.evaluate((a) => window.__published.some((e) => e.kind === 10312 && e.tags.some((t) => t[0] === 'a' && t[1] === a)), A)); + await page.evaluate(() => document.querySelector('.live-page .live-watching').click()); + check('...a tap shows their faces', await waitFor(() => document.querySelectorAll('.live-page .live-who .live-who-p').length === 2, 3000)); check('...and the zap, its amount and words', await waitText('zapped 21 sats', 5000) && await waitText('great stream', 1000)); const rowSel = '.live-message[data-key="' + chat.id + '"]'; check('comments use the group-chat bubble and shared composer', await page.$(rowSel + ' .chat-bubble') && await page.$('.live-page coinos-text#msg-draft')); @@ -253,6 +261,7 @@ try { console.log('\n[leaving]'); await page.goBack(); check('Back leaves the stream\'s page', await waitFor(() => !document.querySelector('.live-page'), 5000)); + check('...and takes back this viewer\'s presence (an empty 10312)', await waitFor(() => window.__published.some((e) => e.kind === 10312 && !e.tags.some((t) => t[0] === 'a')), 3000)); check('...and nothing plays on behind it', await page.evaluate(() => [...document.querySelectorAll('video')].every((v) => v.paused || !v.isConnected))); await page.evaluate(() => document.querySelector('.media-mode[data-mode="all"]').click()); await waitFor(() => !!document.querySelector('.notes-feed .live-card'), 5000); diff --git a/tools/pager-eager-test.js b/tools/pager-eager-test.js index 15a5076..01c8dd6 100644 --- a/tools/pager-eager-test.js +++ b/tools/pager-eager-test.js @@ -88,7 +88,7 @@ async function run(saveData, slow = false) { const feedRow = (w) => page.evaluate((x) => { const r = [...document.querySelectorAll('.notes-feed [data-key]')].find((n) => n.textContent.includes(x)); r.querySelector('.note-video-box').scrollIntoView({ block: 'center' }); const v = r.querySelector('video.note-video').getBoundingClientRect(); return { cover: !!r.querySelector('.vid-heavy'), x: v.x + v.width * 0.2, y: v.y + v.height * 0.3 }; }, w); try { await page.setViewport({ width: 390, height: 844 }); - pace = slow ? 375000 : 0; + pace = slow ? 375000 : 12_500_000; // 3 Mbps, or 100 (a loopback's speed is no link: Chrome reads a warm player's whole file before it can stop) await page.goto(server.url.href, { waitUntil: 'domcontentloaded' }); await page.evaluate(() => localStorage.setItem('btc-wallet-network', 'regtest')); await page.reload({ waitUntil: 'domcontentloaded' }); await sleep(400); @@ -123,14 +123,17 @@ async function run(saveData, slow = false) { const c1 = await slide('c1'), c2 = await slide('c2'), c3 = await slide('c3'); let head1 = 0; if (!saveData) { - check('the next clips wait on their pictures, no cover, no player yet', c1 && !c1.src && !c1.cover && c2 && !c2.src, JSON.stringify([c1, c2])); + check('the next clip has a warm player: its file, read to its first frame and paused', c1 && c1.src && c1.preload === 'metadata' && !c1.playing && !c1.cover && await page.evaluate(() => { const s = [...document.querySelectorAll('.mp-slide')].find((x) => x.getAttribute('data-k').endsWith('/c1.webm')); return s.querySelector('video.mp-media').readyState >= 2; }), JSON.stringify(c1)); + check('…the one after waits on its picture, no player yet', c2 && !c2.src && !c2.cover, JSON.stringify(c2)); const hs = heads('c1'), h2 = heads('c2'); head1 = hs.length ? hs[0].end + 1 : 0; const head2 = h2.length ? h2[0].end + 1 : 0; // before any measure of the link: two seconds' worth (the second clip ahead, half) check('the next clip\'s opening is fetched ahead: two seconds of it', hs.length === 1 && hs[0].start === 0 && near(head1, 2 * RATE), `${kb(head1)} (two seconds: ${kb(2 * RATE)})`); check('…and half that of the one after', h2.length === 1 && near(head2, RATE), `${kb(head2)}`); - check('nothing more than that ahead of time', sent('c1') <= head1 && sent('c2') <= head2 && sent('c3') === 0, `c1 ${kb(sent('c1'))}, c2 ${kb(sent('c2'))}, c3 ${kb(sent('c3'))} of ${kb(SIZE)} each`); + // the warm player reads on from the cached opening to its first frame and a little past, then stops + check('ahead of time: the next clip\'s opening and a few MB more for its warm player, the one after its opening only', sent('c1') <= head1 + 4 * 1024 * 1024 && sent('c2') <= head2 && sent('c3') === 0, `c1 ${kb(sent('c1'))}, c2 ${kb(sent('c2'))}, c3 ${kb(sent('c3'))} of ${kb(SIZE)} each`); + check('…the warm player took the opening from the cache, not the host', !log.some((e) => e.clip === 'c1' && e.dest === 'video' && e.start === 0), log.filter((e) => e.clip === 'c1').map((e) => e.dest + ':' + e.start).join(' ')); } else { check('nothing loads ahead of a clip over budget', c1 && !c1.src && sent('c1') === 0, JSON.stringify(c1) + ' ' + kb(sent('c1'))); } @@ -139,8 +142,9 @@ async function run(saveData, slow = false) { const t0 = Date.now(); if (!saveData) { check('swiped to, the next clip plays at once, no cover', await waitFor(() => { const s = [...document.querySelectorAll('.mp-slide')].find((x) => x.getAttribute('data-k').endsWith('/c1.webm')); const v = s.querySelector('video.mp-media'); return !s.querySelector('.vid-heavy') && !v.paused && v.currentTime > 0; }, null, 5000) && (Date.now() - t0) < (slow ? 3000 : 1500), (Date.now() - t0) + ' ms'); - const after = log.slice(before).filter((e) => e.clip === 'c1' && e.dest === 'video'); - check('…its player starting where the head start left off (the opening came from the cache)', after.length >= 1 && after[0].start === head1, 'the player asked for ' + (after.map((e) => e.start + '-').join(', ') || 'nothing') + ', head start ' + head1); + await waitFor(() => coinosPagerStarts().starts.some((x) => /c1\.webm$/.test(x.url)), null, 3000); + const st = await page.evaluate(() => coinosPagerStarts().starts.find((x) => /c1\.webm$/.test(x.url))); + check('…from its warm player, the clock says', st && st.warm && st.ms < 1000, JSON.stringify(st)); await sleep(1500); const h3 = heads('c3'), head3 = h3.length ? h3[0].end + 1 : 0; check('…the next one gets its head start', h3.length === 1); |
