// Real-DOM (jsdom) test of the two new Tools sections. The HTML is the actual // server-rendered /partials/tools, and the payloads are the real API's, so a // renamed field or a changed shape fails this rather than passing quietly. const http = require('http'); const { JSDOM, VirtualConsole } = require('jsdom'); const BASE = process.env.BASE || 'http://localhost:5000'; const get = p => new Promise((res, rej) => http.get(BASE + p, r => { let d = ''; r.on('data', c => d += c); r.on('end', () => res(d)); }).on('error', rej)); (async () => { const partial = await get('/partials/tools'); const bridge = JSON.parse(await get('/api/v3/integrations/mqtt-bridge')); const apps = JSON.parse(await get('/api/v3/starlark/editor/apps')); // A dev box or CI runner has no Starlark apps and no Pixlet binary, which // leaves the editor section with nothing to render. Keep the real payload's // shape but give it two apps -- one id carrying a quote, which is what the // dataset (not inline onclick) check below exists to catch. if (!(apps.data && apps.data.apps && apps.data.apps.length)) { apps.data = Object.assign({}, apps.data, { pixlet_available: true, apps: [ { id: 'clock-demo', name: 'Clock demo', editable: true }, { id: "it's-quoted", name: 'Quoted id', editable: true }, ], }); } const errs = []; const vc = new VirtualConsole(); vc.on('jsdomError', e => errs.push(String(e.message || e).split('\n')[0])); // Controllable fetch: serve the real payloads, and let tests swap in others. let editorStatus = { status: 'success', data: { running: false } }; let bridgePayload = bridge; let onPut = null; const stubFetch = (url, opts) => { const u = String(url); if (onPut && opts && opts.method === 'PUT') onPut(JSON.parse(opts.body)); let body = { status: 'success', data: {} }; if (u.includes('/integrations/mqtt-bridge')) body = bridgePayload; else if (u.includes('/starlark/editor/status')) body = editorStatus; else if (u.includes('/starlark/editor/apps')) body = apps; return Promise.resolve({ ok: true, status: 200, json: () => Promise.resolve(body) }); }; // runScripts:'dangerously' so the partial's own