aboutsummaryrefslogtreecommitdiffstats
path: root/tools/relay-link-test.js
blob: 52984ad17f5b203d361798b27565cd936845d756 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// A relay named in a post (wss://…) is a link: tapping it opens the raw
// firehose of that relay (/feed/all?r=…), read from that relay alone.
// Run: bun tools/relay-link-test.js
import assert from 'node:assert/strict';
import puppeteer from './puppeteer.js';
import { finalizeEvent, generateSecretKey } from 'nostr-tools/pure';
import { buildHtml, buildVerifyWorker } from '../build.js';

const sk = generateSecretKey(), now = Math.floor(Date.now() / 1000);
const note = finalizeEvent({ kind: 1, created_at: now, tags: [], content: 'I run a good relay to read directly:\n\nwss://theforest.nostr1.com.\n\nAnyone can read from it.' }, sk);
const forest = finalizeEvent({ kind: 1, created_at: now - 5, tags: [], content: 'Hello from the forest relay, one of its own posts.' }, generateSecretKey());
const profile = finalizeEvent({ kind: 0, created_at: now, tags: [], content: JSON.stringify({ name: 'Relay Admin' }) }, sk);
const html = await buildHtml({ minify: true, pwa: false });
const worker = await buildVerifyWorker({ minify: true });
const server = Bun.serve({ port: 0, fetch(req) {
  const path = new URL(req.url).pathname;
  if (path === '/api/feed') return Response.json({ version: 1, generatedAt: Date.now(), popUntil: now - 100, notes: [note], profiles: [profile] });
  if (path === '/verify-worker.js') return new Response(worker, { headers: { 'Content-Type': 'text/javascript' } });
  if (path.startsWith('/punks')) return new Response(null, { status: 404 });
  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 check = (name, ok, detail = '') => { assert(ok, name + (detail ? ' — ' + detail : '')); console.log(' ✓ ' + name); };
try {
  const page = await browser.newPage();
  const errors = [];
  page.on('pageerror', (e) => errors.push(e.message));
  await page.setRequestInterception(true);
  page.on('request', (r) => (r.url().startsWith(server.url.origin) || r.url().startsWith('data:') ? r.continue() : r.abort()));
  await page.evaluateOnNewDocument((forest) => {
    window.asked = [];
    class FakeSocket extends EventTarget {
      static OPEN = 1; static CLOSED = 3;
      readyState = 0;
      constructor(url) { super(); this.url = url; setTimeout(() => { this.readyState = 1; this.onopen?.({}); this.dispatchEvent(new Event('open')); }, 0); }
      emit(m) { const e = new MessageEvent('message', { data: JSON.stringify(m) }); this.onmessage?.(e); this.dispatchEvent(e); }
      send(data) {
        const m = JSON.parse(data);
        if (m[0] !== 'REQ') return;
        window.asked.push({ url: this.url, filter: m[2] });
        setTimeout(() => {
          if (/theforest/.test(this.url) && m[2].kinds?.includes(1) && !m[2].ids && !m[2].authors) this.emit(['EVENT', m[1], forest]);
          this.emit(['EOSE', m[1]]);
        }, 0);
      }
      close() { this.readyState = 3; this.onclose?.({}); }
    }
    window.WebSocket = FakeSocket;
  }, forest);
  await page.goto(server.url.origin + '/feed');
  await page.waitForFunction(() => document.body.innerText.includes('I run a good relay'), { timeout: 5000 });
  const link = await page.$$eval('.notes-feed a', (as) => as.filter((a) => /theforest/.test(a.textContent)).map((a) => ({ text: a.textContent, href: a.getAttribute('href') })));
  check('the relay in the post is a link', link.length === 1, JSON.stringify(link));
  check('...without the full stop after it', link[0].text === 'wss://theforest.nostr1.com' && /theforest\.nostr1\.com\./.test(await page.evaluate(() => document.querySelector('.notes-feed').innerText)));
  check('...to that relay\'s firehose', link[0].href === '/feed/all?r=' + encodeURIComponent('wss://theforest.nostr1.com'), link[0].href);
  await page.evaluate(() => [...document.querySelectorAll('.notes-feed a')].find((a) => /theforest/.test(a.textContent)).click());
  check('tapping it shows the relay\'s own posts', await page.waitForFunction(() => document.body.innerText.includes('Hello from the forest relay'), { timeout: 8000 }).then(() => true, () => false));
  const forestAsks = await page.evaluate(() => window.asked.filter((a) => /theforest/.test(a.url) && a.filter.kinds?.includes(1) && !a.filter.authors && !a.filter.ids));
  check('...asked of that relay, for everything on it', forestAsks.length > 0);
  check('...and the address bar says so', decodeURIComponent(await page.evaluate(() => location.pathname + location.search)) === '/feed/all?r=wss://theforest.nostr1.com', await page.evaluate(() => location.href));
  check('no page errors', !errors.length, errors.join(' | '));
  console.log('\n✅ relay links open the relay');
} finally {
  await browser.close();
  server.stop(true);
}