const { test } = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); const path = require('node:path'); const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8'); function extractFunc(src, name, asyncFn) { const re = new RegExp('function\\s+' + name + '\\s*\\([^)]*\\)\\s*\\{'); const m = re.exec(src); if (!m) throw new Error('function ' + name + ' not found'); let i = m.index + m[0].length - 1; let depth = 0; for (; i < src.length; i++) { if (src[i] === '{') depth++; else if (src[i] === '}') { depth--; if (depth === 0) break; } } return (asyncFn ? 'async ' : '') + src.slice(m.index, i + 1); } const ASYNC_FNS = ['ramBatchFetch', 'ramBatchStart', 'ramBatchStop', 'ramBatchClear']; let code = ''; for (const fn of ['ramBatchPanelVisible', 'ramBatchAttemptsHtml', 'ramBatchRender', 'ramBatchApplyStatus', 'ramBatchFetch', 'ramBatchStart', 'ramBatchStop', 'ramBatchClear', 'esc']) { code += extractFunc(html, fn, ASYNC_FNS.indexOf(fn) >= 0) + '\n'; } const RAM_BATCH_FETCH_STALE_MS = parseInt( /const RAM_BATCH_FETCH_STALE_MS = (\d+);/.exec(html)[1], 10); const els = {}; function setEl(id, value) { els[id] = { id: id, value: value === undefined ? '' : value, textContent: '', innerHTML: '', disabled: false, classes: {}, classList: { add(c) { els[id].classes[c] = true; }, remove(c) { delete els[id].classes[c]; }, toggle(c, on) { if (on) els[id].classes[c] = true; else delete els[id].classes[c]; }, contains(c) { return !!els[id].classes[c]; }, }, }; return els[id]; } function clearEls() { for (const k of Object.keys(els)) delete els[k]; } const app = new Function('els', ` var sandbox = { fetched: [], replies: {}, fetchError: null, alerts: [], visibility: true }; var document = { getElementById: id => els[id] || null }; var t = k => k; var isViewVisible = () => sandbox.visibility; var alert = m => sandbox.alerts.push(String(m)); var pysimFetch = async (p) => { sandbox.fetched.push(p); if (sandbox.hangs) return new Promise(() => {}); // a stalled connection return sandbox.replies[p] || null; }; var pysimFetchOk = async (p, body) => { sandbox.fetched.push(p); sandbox.bodies = sandbox.bodies || {}; sandbox.bodies[p] = body; if (sandbox.fetchError) throw new Error(sandbox.fetchError); return sandbox.replies[p] || { ok: true }; }; var capGateOk = () => sandbox.capGate !== false; var ramReadFileHex = async () => 'AABB'; var ramInstallCapFields = () => ({ sd_aid: '', install_params: '', ram_format: 'auto' }); var pysimApplyAvailability = () => {}; var _ramBatchLast = null; var _ramBatchFetching = false; var _ramBatchFetchAt = 0; var _ramBatchSummary = null; var _ramBatchProgress = null; var RAM_BATCH_FETCH_STALE_MS = ${RAM_BATCH_FETCH_STALE_MS}; ${code} sandbox.getLast = () => _ramBatchLast; sandbox.setLast = v => { _ramBatchLast = v; }; sandbox.getSummary = () => _ramBatchSummary; sandbox.isFetching = () => _ramBatchFetching; sandbox.setFetchingStale = ms => { _ramBatchFetching = true; _ramBatchFetchAt = Date.now() - ms; }; sandbox.resetFetching = () => { _ramBatchFetching = false; }; sandbox.getProgress = () => _ramBatchProgress; sandbox.ramBatchPanelVisible = ramBatchPanelVisible; sandbox.ramBatchAttemptsHtml = ramBatchAttemptsHtml; sandbox.ramBatchRender = ramBatchRender; sandbox.ramBatchApplyStatus = ramBatchApplyStatus; sandbox.ramBatchFetch = ramBatchFetch; sandbox.ramBatchStart = ramBatchStart; sandbox.ramBatchStop = ramBatchStop; sandbox.ramBatchClear = ramBatchClear; return sandbox; `)(els); test('the RAM view wires the batch operation and the panel', () => { assert.match(html, /