~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs-socialweb-computer-app

app.socialweb.computer: socialweb.computer in one page, one atlibs composition

0
0
main
105 lines · 6.7 KB Raw History
// node --test test/page.test.mjs  (after scripts/stage.sh: dist/ as served; skips without Chrome)
// index.html in headless Chrome, signed in with a stub session: Running shows a bidder an account you vouch for
// runs (its operator confirmed), Vouches writes and deletes a vouch, the atlibs view lists the instances, and the
// page fits a phone. Stubbed: the PLC directory, the PDS (an in-memory repo), the profiles appview.
// atlibs and the other imports come from their CDNs.
import assert from 'node:assert/strict'
import { existsSync } from 'node:fs'
import { test } from 'node:test'

import { browse, CHROME } from './browser.mjs'

const ME = 'did:plc:alice'
const FRIEND = 'did:plc:friend'
const BID = 'did:plc:bid'
const T = 'com.publicdomainrelay.temp'
const now = new Date().toISOString()
const store = new Map(
	Object.entries({
		[`${ME}/sh.tangled.graph.vouch/${FRIEND}`]: { kind: 'vouch', reason: 'runs a bidder', createdAt: now },
		[`${FRIEND}/computer.socialweb.bidders/self`]: { bidders: [BID] },
		[`${BID}/${T}.market.offering/self`]: { appliesTo: [`${T}.compute.vm`], endpoints: [{ kind: 'webrtc', address: 'x' }], createdAt: now },
		[`${BID}/${T}.market.heartbeat/self`]: { offering: `at://${BID}/${T}.market.offering/self`, createdAt: now },
		[`${BID}/${T}.badgeBlueKeys/association`]: { challenge: FRIEND, keyId: BID, service: 'bidder_associate' },
		[`${FRIEND}/${T}.market.association/bidder_associate-did-plc-bid`]: { subject: BID, service: 'bidder_associate', createdAt: now },
	}),
)

function pds(url, method, body) {
	const p = Object.fromEntries(url.searchParams)
	const nsid = url.pathname.split('/').pop()
	const key = (b) => `${b.repo}/${b.collection}/${b.rkey}`
	if (nsid === 'com.atproto.repo.getRecord') {
		const value = store.get(key(p))
		return value ? [200, { uri: `at://${key(p)}`, cid: 'bafy', value }] : [400, { error: 'RecordNotFound', message: 'Could not locate record' }]
	}
	if (nsid === 'com.atproto.repo.listRecords') {
		const prefix = `${p.repo}/${p.collection}/`
		return [200, { records: [...store].filter(([k]) => k.startsWith(prefix)).map(([k, value]) => ({ uri: `at://${k}`, cid: 'bafy', value })) }]
	}
	if (nsid === 'com.atproto.repo.putRecord' || nsid === 'com.atproto.repo.createRecord') {
		store.set(key(body), body.record)
		return [200, { uri: `at://${key(body)}`, cid: 'bafy' }]
	}
	if (nsid === 'com.atproto.repo.deleteRecord') return store.delete(key(body)), [200, {}]
	if (nsid === 'com.atproto.repo.describeRepo') return [200, { handle: 'alice.test', did: p.repo, collections: [] }]
	if (nsid === 'com.atproto.identity.resolveHandle') return [200, { did: `did:plc:${p.handle.split('.')[0]}` }]
	return [400, { error: 'MethodNotImplemented' }]
}

const SESSION = `globalThis.__ATLIBS_SESSION__ = { did: ${JSON.stringify(ME)}, fetchHandler: (path, init = {}) => fetch('https://pds.test' + path, init) }`
const CORS = [{ name: 'access-control-allow-origin', value: '*' }, { name: 'access-control-allow-headers', value: '*' }, { name: 'access-control-allow-methods', value: '*' }]
const skip = (!CHROME && 'no Chrome: set CHROME') || (!existsSync(new URL('../dist/stage.json', import.meta.url)) && 'no dist/: scripts/stage.sh')

test('signed in: running, vouches, atlibs, on a phone', { skip }, async () => {
	await browse(
		async ({ send, on, open, evaluate }) => {
			const errors = []
			on('Runtime.exceptionThrown', (e) => errors.push(e.exceptionDetails.exception?.description ?? e.exceptionDetails.text))
			on('Fetch.requestPaused', async ({ requestId, request }) => {
				const url = new URL(request.url)
				let status = 200
				let body = {}
				if (request.method === 'OPTIONS') body = ''
				else if (url.origin === 'https://plc.directory') body = { id: url.pathname.slice(1), alsoKnownAs: ['at://x.test'], service: [{ id: '#atproto_pds', type: 'AtprotoPersonalDataServer', serviceEndpoint: 'https://pds.test' }] }
				else if (url.origin === 'https://public.api.bsky.app') body = { profiles: [{ did: FRIEND, handle: 'friend.test' }] }
				else [status, body] = pds(url, request.method, request.postData && JSON.parse(request.postData))
				const text = typeof body === 'string' ? body : JSON.stringify(body)
				await send('Fetch.fulfillRequest', { requestId, responseCode: status, responseHeaders: [{ name: 'content-type', value: 'application/json' }, ...CORS], body: Buffer.from(text).toString('base64') })
			})
			await send('Runtime.enable')
			await send('Fetch.enable', { patterns: ['https://plc.directory/*', 'https://pds.test/*', 'https://public.api.bsky.app/*'].map((urlPattern) => ({ urlPattern })) })
			await send('Page.addScriptToEvaluateOnNewDocument', { source: SESSION })
			await send('Emulation.setDeviceMetricsOverride', { width: 390, height: 844, deviceScaleFactor: 1, mobile: true })
			await open('/index.html')
			const until = async (expression, ms = 30_000) => {
				for (const end = Date.now() + ms; Date.now() < end; await new Promise((ok) => setTimeout(ok, 200))) if (await evaluate(expression).catch(() => false)) return
				throw new Error(`timed out: ${expression}\n${errors.join('\n')}\n${await evaluate('document.getElementById("error").textContent')}`)
			}
			await until('document.body.dataset.ready === "true"')

			await until(`document.querySelectorAll('#vouched-bidders .card').length > 0`)
			const card = await evaluate(`document.querySelector('#vouched-bidders .card').textContent`)
			assert.match(card, /did:plc:bid/)
			assert.match(card, /operator friend\.test/)
			assert.match(card, /heartbeat \d+s ago/)
			assert.match(await evaluate(`document.getElementById('my-bidders').textContent`), /No bidders of yours/)
			assert.equal(await evaluate('document.documentElement.scrollWidth <= innerWidth'), true, 'no sideways scroll on a phone')

			await evaluate(`location.hash = '#vouches'`)
			await until(`document.querySelectorAll('#vouch-list .card').length === 1`)
			await evaluate(`(() => { const f = document.getElementById('vouch'); f.subject.value = 'carol.test'; f.reason.value = 'hi'; f.requestSubmit() })()`)
			await until(`document.querySelectorAll('#vouch-list .card').length === 2`)
			assert.deepEqual(store.get(`${ME}/sh.tangled.graph.vouch/did:plc:carol`).subject, 'did:plc:carol')
			await evaluate(`[...document.querySelectorAll('#vouch-list .card')].find((c) => c.textContent.includes('carol')).querySelector('button').click()`)
			await until(`document.querySelectorAll('#vouch-list .card').length === 1`)
			assert.equal(store.has(`${ME}/sh.tangled.graph.vouch/did:plc:carol`), false)

			await evaluate(`location.hash = '#atlibs'`)
			await until(`document.querySelectorAll('#instances .card').length === 10`)
			assert.equal(await evaluate(`document.getElementById('error').textContent`), '')
			assert.deepEqual(errors, [])
		},
		{ root: new URL('../dist/', import.meta.url).pathname },
	)
})