aboutsummaryrefslogtreecommitdiffstats
path: root/tools/live-stream-test.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/live-stream-test.js')
-rw-r--r--tools/live-stream-test.js26
1 files changed, 22 insertions, 4 deletions
diff --git a/tools/live-stream-test.js b/tools/live-stream-test.js
index 4cd8337..2be6051 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)
@@ -194,6 +197,12 @@ try {
check('the host\'s face on their post wears the live ring', await waitFor((pk) => !!document.querySelector('.notes-feed .note-post .note-avatar.live-ring'), 5000));
await page.evaluate(() => document.querySelector('.notes-feed .note-post .note-avatar.live-ring').click());
check('...and a tap on it opens the stream', await waitFor(() => !!document.querySelector('.live-page'), 5000));
+ const lay = await page.evaluate(() => {
+ const r = (q) => document.querySelector(q)?.getBoundingClientRect();
+ const p = r('.live-page .live-player'), c = r('.live-page .live-chat');
+ return { w: document.body.clientWidth, player: p && [p.left, p.width], chat: c && [c.left, c.width] };
+ });
+ check('on a phone the picture runs edge to edge and the chat is as wide', lay.player && lay.player[0] === 0 && lay.player[1] === lay.w && lay.chat && lay.chat[0] === 0 && lay.chat[1] === lay.w, JSON.stringify(lay));
await page.goBack();
await waitFor(() => !document.querySelector('.live-page') && !!document.querySelector('.media-modes'), 5000);
await page.evaluate(() => document.querySelector('.media-mode[data-mode="live"]').click());
@@ -206,9 +215,15 @@ 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'));
+ check('...drawn plain on a phone, no bubble walls', await page.evaluate((q) => { const b = document.querySelector(q); return b && getComputedStyle(b).borderStyle === 'none' && getComputedStyle(b).display === 'block'; }, rowSel + ' .chat-bubble'));
check('another clientโ€™s e-only reaction arrives on the comment', await waitFor(id => document.querySelector('.live-message[data-key="'+id+'"] .chat-reacts')?.textContent.includes('๐Ÿ‘'), 6000, chat.id));
check('per-comment zap receipts show under the bubble', await waitFor(id => document.querySelector('.live-message[data-key="'+id+'"] .zap-tally')?.textContent.includes('5'), 6000, chat.id));
await page.click(rowSel + ' .chat-bubble');
@@ -253,21 +268,24 @@ 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);
await page.evaluate(() => document.querySelector('.notes-feed .live-card').click());
check('the card in the post opens the stream too', await waitFor(() => !!document.querySelector('.live-page'), 5000) && await waitFor(playing, 20000));
await page.evaluate(() => { const a = [...document.querySelectorAll('.live-page a.quote-name')].find((x) => /Stream Host/.test(x.textContent)); a.click(); });
- check('the host\'s profile lists their past streams', await waitFor(() => [...document.querySelectorAll('.live-past-row .live-tile')].some((t) => /Yesterday on coinos/.test(t.innerText)), 10000));
- await page.evaluate(() => [...document.querySelectorAll('.live-past-row .live-tile')].find((t) => /Zelda on Rumble/.test(t.innerText)).click());
+ check('the host\'s profile has a Streams tab', await waitFor(() => !!document.querySelector('.prof-tabs [data-tab="streams"]'), 10000) && !(await page.$('.live-past')));
+ await page.evaluate(() => document.querySelector('.prof-tabs [data-tab="streams"]').click());
+ check('...listing their past streams', await waitFor(() => [...document.querySelectorAll('.live-past .live-tile')].some((t) => /Yesterday on coinos/.test(t.innerText)), 10000));
+ await page.evaluate(() => [...document.querySelectorAll('.live-past .live-tile')].find((t) => /Zelda on Rumble/.test(t.innerText)).click());
check('a recording kept as a web page: ended, and a link to watch it there, no player', await waitFor(() => !!document.querySelector('.live-page a.live-rec-link[href="https://rumble.com/v7gt2va-zelda.html"]'), 5000)
&& await page.evaluate(() => /This stream has ended/.test(document.body.innerText) && !document.querySelector('.live-page video.live-video')));
await page.goBack();
await waitFor(() => !document.querySelector('.live-page'), 5000);
check('the host\'s profile says they\'re on', await waitFor(() => !!document.querySelector('.live-banner'), 10000) && await waitText('Building coinos live', 2000));
check('...the player stopped when the page went', await page.evaluate(() => [...document.querySelectorAll('video')].every((v) => v.paused || !v.isConnected)));
- await page.evaluate(() => [...document.querySelectorAll('.live-past-row .live-tile')].find((t) => /Yesterday on coinos/.test(t.innerText)).click());
+ await page.evaluate(() => [...document.querySelectorAll('.live-past .live-tile')].find((t) => /Yesterday on coinos/.test(t.innerText)).click());
check('a past stream opens on its recording, playing', await waitFor(() => !!document.querySelector('.live-page'), 5000) && await waitFor(playing, 20000)
&& await page.evaluate(() => !document.body.innerText.includes('This stream has ended')));
check('no page errors', !page.errs.length, page.errs.join(' | '));