// Shared test helpers: unsigned JWTs, real PocketBase cookie envelopes, and // throwaway http servers for fake upstreams. import http from 'node:http'; import PocketBase from 'pocketbase'; export function b64url(obj) { return Buffer.from(JSON.stringify(obj)).toString('base64url'); } /** Structurally valid (unsigned) JWT with a controllable exp. */ export function makeJwt({ expiresInSec = 3600 } = {}) { const payload = { exp: Math.floor(Date.now() / 1000) + expiresInSec, id: 'u1', collectionId: 'c1', collectionName: 'users', }; return `${b64url({ alg: 'HS256', typ: 'JWT' })}.${b64url(payload)}.sig`; } export const TEST_RECORD = { id: 'u1', collectionId: 'c1', collectionName: 'users', phone: '+2348068287222', }; /** Build the real PocketBase cookie envelope (value only) via the actual SDK. */ export function makePbCookie(token, record = TEST_RECORD) { const pb = new PocketBase('http://127.0.0.1:9'); // never contacted for this pb.authStore.save(token, record); const setCookie = pb.authStore.exportToCookie({}, 'pb_auth'); const m = /pb_auth=([^;]+)/.exec(setCookie); if (!m) throw new Error('could not build pb cookie envelope'); return m[1]; } export function startServer(handler) { return new Promise((resolve) => { const server = http.createServer(handler); server.listen(0, '127.0.0.1', () => resolve(server)); }); } export const urlOf = (server) => `http://127.0.0.1:${server.address().port}`; export function stopServer(server) { return new Promise((resolve) => server.close(resolve)); } /** Read the `name=value` pair out of a Set-Cookie response header list. */ export function cookieValue(res, name) { for (const c of res.headers.getSetCookie()) { const m = new RegExp(`(?:^|;\\s*)${name}=([^;]*)`).exec(c); if (m) return m[1]; } return undefined; } /** Scriptable fetch double that records every call. */ export function fakeFetch(script) { const calls = []; const fn = async (url, init) => { const body = init?.body ? JSON.parse(init.body) : undefined; const out = await script({ url, body, init }); calls.push({ url, body }); if (out instanceof Error) throw out; return { status: out.status ?? 200, json: async () => out.body, text: async () => JSON.stringify(out.body ?? {}) }; }; fn.calls = calls; return fn; }