#!/usr/bin/env node // Simulated status and tab DOM. No Rust process or visual browser is run here. import assert from 'node:assert/strict'; import fs from 'node:fs'; import vm from 'node:vm'; const html = fs.readFileSync('src/admin/web/index.html', 'utf8'); const css = fs.readFileSync('src/admin/web/style.css', 'utf8'); const js = fs.readFileSync('src/admin/web/settings.js', 'utf8'); const core = fs.readFileSync('src/admin/web/app/core.js', 'utf8'); const api = JSON.parse(fs.readFileSync('src/admin/openapi.json', 'utf8')); const has = (haystack, needle) => assert.ok(haystack.includes(needle), `Missing ${needle}`); // The two mini charts share the exact H1/H2/H3 palette as their SVG lines. for (const version of ['h1', 'h2', 'h3']) { assert.match(css, new RegExp(`\\.stat-chart\\s+\\.stat-chart-legend\\s+\\.legend-${version}\\s+i\\s*\\{\\s*background:\\s*var\\(--traffic-${version}\\);`)); assert.match(css, new RegExp(`\\.proto-${version}-line\\s*\\{[^}]*stroke:\\s*var\\(--traffic-${version}\\);`)); has(html, `id="http-protocol-${version}"`); has(html, `id="ws-protocol-${version}"`); } assert.equal((html.match(/class="stat-chart-legend"/g) || []).length, 2); const about = html.split('')[0]; for (const forbidden of ['about-acme-mode', 'about-python-runtime', 'about-python-details', 'runtimeAcmeMode']) { assert.ok(!about.includes(forbidden), `ACME details left in About: ${forbidden}`); } assert.ok(!core.includes('renderAboutRuntime('), 'Obsolete About runtime renderer must be removed'); for (const marker of ['aboutAuthor', 'aboutLicense', 'aboutRepository', 'aboutPackagesRepository']) has(about, marker); has(html, 'data-settings-tab="system-info"'); has(html, 'id="settings-page-system-info"'); const tab = html.split('id="settings-page-system-info"')[1].split('id="settings-page-certificate-api"')[0]; for (const field of ['runtime-operating-system', 'runtime-kernel-version', 'runtime-architecture', 'runtime-logical-cpus', 'runtime-system-memory', 'runtime-process-memory', 'runtime-acme-mode', 'runtime-python', 'runtime-pip', 'runtime-certbot', 'runtime-acme-directory', 'runtime-data-directory', 'runtime-database-path']) has(tab, `id="${field}"`); assert.ok(!tab.includes(' { if (!elements.has(id)) elements.set(id, { textContent: '' }); return elements.get(id); }; const status = { version: '0.32.0', uptime_seconds: 4201, runtime: { platform: 'Linux', operating_system: 'Debian GNU/Linux 13', kernel_version: '6.12.0', architecture: 'x86_64', statistics_source: 'systemstat+sysinfo', data_directory: '/var/lib/rustproxy', database_path: '/var/lib/rustproxy/config.sqlite3', certificate_runtime: { status: 'ready', mode: 'managed', message: 'acme.runtime_ready', python: true, pip: true, certbot: true, python_version: '3.13.5', pip_version: '25.2', certbot_version: '5.8.0', managed_directory: '/var/lib/rustproxy/acme-python' } }, system: { logical_cpus: 8, cpu_percent: 17.2, memory_total_bytes: 16_384, memory_used_bytes: 8_192, process_rss_bytes: 2_048, system_uptime_seconds: 100, process_threads: 9, open_fds: 67 } }; const context = { latestStatus: status, $: dollar, locale: () => 'en-US', t: key => ({ runtimeAvailable: 'Available', runtimeUnavailable: 'Unavailable', certificateRuntimeManaged: 'App-managed Python', 'acme.runtime_ready': 'Ready', unavailable: 'N/A' })[key] || key, bytes: value => `${value} B`, uptime: value => `${value}s`, }; vm.runInNewContext(code, context); assert.equal(dollar('runtime-operating-system').textContent, 'Debian GNU/Linux 13'); assert.equal(dollar('runtime-kernel-version').textContent, '6.12.0'); assert.equal(dollar('runtime-version').textContent, '0.32.0'); assert.equal(dollar('runtime-logical-cpus').textContent, '8'); assert.equal(dollar('runtime-cpu-usage').textContent, '17.2%'); assert.equal(dollar('runtime-python').textContent, 'Available · 3.13.5'); assert.equal(dollar('runtime-pip').textContent, 'Available · 25.2'); assert.equal(dollar('runtime-certbot').textContent, 'Available · 5.8.0'); assert.equal(dollar('runtime-acme-directory').textContent, '/var/lib/rustproxy/acme-python'); // A working ACME runtime can have no trustworthy version metadata on some OSes. elements.clear(); vm.runInNewContext(code, { ...context, latestStatus: { ...status, runtime: { ...status.runtime, certificate_runtime: { ...status.runtime.certificate_runtime, python_version: null, pip_version: null, certbot_version: null } } } }); for (const field of ['runtime-python', 'runtime-pip', 'runtime-certbot']) { assert.equal(dollar(field).textContent, 'Available'); } // Status fields remain safely unavailable rather than displaying fake zeros. elements.clear(); vm.runInNewContext(code, { ...context, latestStatus: { runtime: { certificate_runtime: { status: 'unavailable', mode: 'none', message: 'acme.runtime_python_missing', python: false, pip: false, certbot: false } }, system: {} } }); for (const field of ['runtime-cpu-usage', 'runtime-logical-cpus', 'runtime-system-memory', 'runtime-python']) { assert.ok(!/NaN|0 B/.test(dollar(field).textContent)); } // Exercise real tab switching, deep-linking and search code without a browser. const entry = js.slice(js.indexOf(' const buttons ='), js.indexOf(' const cacheTabs =')); const buttons = ['administration', 'system-info', 'certificate-api'].map(name => ({ dataset: {settingsTab:name}, textContent:name, hidden:false, tabIndex:-1, listeners:{}, setAttribute(name,value){this[name]=value;}, addEventListener(name,fn){this.listeners[name]=fn;}, focus(){} })); const pages = buttons.map(b => ({dataset:{settingsPage:b.dataset.settingsTab}, hidden:true,textContent:b.dataset.settingsTab})); const search={value:'',listeners:{},addEventListener(name,fn){this.listeners[name]=fn;}}; const searchStatus={textContent:''}; const loc = new URL('https://localhost/settings?tab=system-info'); let lastUrl=''; vm.runInNewContext(`(() => { ${entry} return true; })()`, { document: {querySelectorAll: sel => sel === '[data-settings-tab]' ? buttons : pages, querySelector: sel => pages.find(p => sel.includes(p.dataset.settingsPage))}, $: id => id === 'settings-search' ? search : searchStatus, location: loc, history: {state:null,replaceState:(_state,_unused,url) => {lastUrl=url;}}, CSS:{escape:x=>x}, URL, URLSearchParams, t:x=>x, }); buttons[1].listeners.click(); assert.equal(pages[1].hidden,false); assert.equal(pages[0].hidden,true); assert.equal(buttons[1]['aria-selected'],'true'); assert.equal(lastUrl,''); // Already at canonical deep link; no unnecessary history rewrite. buttons[0].listeners.click(); assert.equal(pages[1].hidden,true); assert.equal(lastUrl,'/settings?tab=administration'); const runtimeSchema = api.components.schemas.RuntimeInformation; for (const key of ['operating_system','kernel_version','architecture']) assert.ok(runtimeSchema.properties[key]); for (const key of ['python_version','pip_version','certbot_version']) { assert.ok(runtimeSchema.properties.certificate_runtime.properties[key]); assert.equal(runtimeSchema.properties.certificate_runtime.properties[key].nullable, true); } console.log('PASS: 0.31.9 legend palette, About cleanup, system tab/navigation, read-only API schema and simulated status rendering.');