OverviewFilesCommitsIssuesDocsReleasesPeers

favela-gateway / test / panel.test.js

50 lines · javascript ref:
// The gateway status page on the admin surface: both bridges' health, alerts first, each with its fix.
import test from 'brittle'
import { renderStatusPage } from '../lib/panel.js'

const NOW = 1e12
const WJ = 'did:plc:wj62ebbusln6gxo5azo6ogzo'
function sample () {
  return {
    version: '0.4.0',
    process: { uptimeS: 7300, rss: 280e6, heapUsed: 60e6, heapTotal: 110e6 },
    roles: { membrane: { up: true }, fediverse: { up: true }, lens: { up: false, error: 'lens config: <bad>' } },
    membrane: { dids: [{ did: WJ, handle: 'p2p.7rnx.net', rev: '3mrhxnkbhv622', fronts: 2, live: 1, lastAppendAt: NOW - 120e3, forkRejected: 0, denied: 0 }], relay: { emitted: 40269, seqBase: 35200 }, guard: { configured: true, lastAt: NOW - 60e3, last: { relayStatus: 'active' }, heals: 1, lastHealAt: NOW - 86400e3 } },
    fediverse: { users: [{ username: 'p2p', primary: true, held: false, followers: 1, delivered: 172 }], queue: { pending: 1, dead: 0, oldestPendingAt: NOW - 600e3, failing: [{ host: 'prsm.space', attempts: 2, lastError: 'HTTP 502' }] }, inbound: { count: 10, lastReceivedAt: NOW - 3600e3 }, registrations: 2 },
    lens: { feeds: [{ id: 'loser-club', communityDid: 'did:plc:wqnwul', curation: 'roster', members: 2, unfronted: [], posts: 299, newest: '2026-09-15T14:05:29Z', perMember: [] }] },
    bsky: { at: NOW - 30e3, hostname: 'pds.7rnx.net', relay: { status: 'active', seq: 40269 }, dids: [{ did: WJ, ourRev: '3mrhxnkbhv622', relayRev: '3mrhxnkbhv622', inSync: true, plcPds: 'https://pds.7rnx.net', handle: 'p2p.7rnx.net', appview: { resolves: true, postsCount: 201, newestIndexedAt: '2026-09-15T14:05:39Z' } }], problems: [] },
    alerts: { lastCheckAt: NOW - 60e3, open: [{ id: 'relay-newer:x', severity: 'critical', title: 'relay holds a NEWER commit', detail: 'relay <z>, ours a', fix: 'favela-gateway emit-sync did=x', since: NOW - 7200e3 }], recentlyResolved: [{ id: 'relay-offline', title: 'relay offline', since: NOW - 90000e3, resolvedAt: NOW - 86000e3 }] }
  }
}

test('★ alerts come first, critical marked, each with its fix', (t) => {
  const p = renderStatusPage(sample(), { now: NOW })
  t.is(p.title, 'Gateway status')
  const a = p.body.indexOf('relay holds a NEWER commit')
  t.ok(a > -1 && a < p.body.indexOf('Served DIDs'), 'before every other section')
  t.ok(p.body.includes('favela-gateway emit-sync did=x'), 'the fix')
  t.ok(/open 2h/.test(p.body), 'how long it has been open')
  t.ok(p.body.includes('relay offline'), 'recently resolved is listed too')
})

test('⛔ everything that came from outside is escaped', (t) => {
  const p = renderStatusPage(sample(), { now: NOW })
  t.absent(p.body.includes('<z>'), 'alert detail escaped')
  t.absent(p.body.includes('<bad>'), 'role error escaped')
  t.ok(p.body.includes('&lt;z&gt;'))
})

test('every section is present: roles, bsky, served DIDs, lens, fediverse, process', (t) => {
  const b = renderStatusPage(sample(), { now: NOW }).body
  for (const s of ['Roles', 'bsky', 'Served DIDs', 'Lens', 'Fediverse', 'p2p.7rnx.net', 'in sync', '1/2 live', '299 posts', '172 delivered', 'prsm.space', 'HTTP 502', '280 MB']) t.ok(b.includes(s), s)
  t.ok(/DOWN/.test(b), 'the down role is visible')
})

test('a gateway with only the membrane still renders (missing sections are omitted, not broken)', (t) => {
  const m = sample(); m.fediverse = null; m.lens = null; m.alerts = null; m.bsky = null
  const b = renderStatusPage(m, { now: NOW }).body
  t.ok(b.includes('Served DIDs'))
  t.absent(b.includes('Fediverse</h2>'))
  t.ok(/alert watcher is not running|no bsky probe/i.test(b), 'says what it could not show')
})