codex generated updates
This commit is contained in:
1323
index.html
1323
index.html
File diff suppressed because it is too large
Load Diff
6
package.json
Normal file
6
package.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"test": "node --test"
|
||||||
|
},
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
||||||
144
test/dashboard.test.mjs
Normal file
144
test/dashboard.test.mjs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
const html = await readFile(new URL('../index.html', import.meta.url), 'utf8');
|
||||||
|
|
||||||
|
function idsInMarkup() {
|
||||||
|
return [...html.matchAll(/\sid=["']([^"']+)["']/g)].map(match => match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function elementsWithClass(className) {
|
||||||
|
const pattern = new RegExp(`<[^>]*class=["'][^"']*\\b${className}\\b[^"']*["'][^>]*>`, 'g');
|
||||||
|
return [...html.matchAll(pattern)].map(match => match[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('dashboard keeps the required interactive element ids unique', () => {
|
||||||
|
const ids = idsInMarkup();
|
||||||
|
const requiredIds = [
|
||||||
|
'clockDisplay',
|
||||||
|
'dateDisplay',
|
||||||
|
'lastUpdated',
|
||||||
|
'globalStatus',
|
||||||
|
'health',
|
||||||
|
'healthBadge',
|
||||||
|
'serverDot',
|
||||||
|
'webDot',
|
||||||
|
'webStatus',
|
||||||
|
'roamDot',
|
||||||
|
'roamStatus',
|
||||||
|
'uptimeStat',
|
||||||
|
'uptimeDays',
|
||||||
|
'uptimeHours',
|
||||||
|
'uptimeMins',
|
||||||
|
'uptimeStart',
|
||||||
|
'uptimePct',
|
||||||
|
'uptimeFill',
|
||||||
|
'pingHistory',
|
||||||
|
'dailyMessage',
|
||||||
|
'countdownLabel',
|
||||||
|
'countdownDisplay',
|
||||||
|
'cd-days',
|
||||||
|
'cd-hours',
|
||||||
|
'cd-mins',
|
||||||
|
'cd-secs',
|
||||||
|
'buildBtn',
|
||||||
|
'killWebBtn',
|
||||||
|
'buildResult',
|
||||||
|
'webLastRunMeta',
|
||||||
|
'logOutput',
|
||||||
|
'orgRoamBtn',
|
||||||
|
'orgRoamBtn2',
|
||||||
|
'combinedBtn',
|
||||||
|
'killRoamBtn',
|
||||||
|
'pipelineSteps',
|
||||||
|
'pipeStep1',
|
||||||
|
'pipeStep2',
|
||||||
|
'orgRoamResult',
|
||||||
|
'roamLastRunMeta',
|
||||||
|
'orgRoamLogs',
|
||||||
|
'modalOverlay',
|
||||||
|
'modalTitle',
|
||||||
|
'modalBody',
|
||||||
|
'modalCancel',
|
||||||
|
'modalConfirm'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const id of requiredIds) {
|
||||||
|
assert.ok(ids.includes(id), `missing #${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
|
||||||
|
assert.deepEqual(duplicates, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('website and roam logs remain directly accessible from toggle buttons', () => {
|
||||||
|
const ids = new Set(idsInMarkup());
|
||||||
|
const toggleButtons = elementsWithClass('toggleLogs');
|
||||||
|
assert.equal(toggleButtons.length, 2);
|
||||||
|
|
||||||
|
for (const button of toggleButtons) {
|
||||||
|
const target = button.match(/data-target=["']([^"']+)["']/)?.[1];
|
||||||
|
assert.ok(target, `toggle missing data-target: ${button}`);
|
||||||
|
assert.ok(ids.has(target), `toggle target #${target} is missing`);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.match(html, /data-target=["']logOutput["']/);
|
||||||
|
assert.match(html, /data-target=["']orgRoamLogs["']/);
|
||||||
|
assert.match(html, /id=["']logOutput["'][^>]*class=["'][^"']*\blog-box\b[^"']*\bhidden\b/);
|
||||||
|
assert.match(html, /id=["']orgRoamLogs["'][^>]*class=["'][^"']*\blog-box\b[^"']*\bhidden\b/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('build controls use the expected API endpoints and streams', () => {
|
||||||
|
const expectedEndpoints = [
|
||||||
|
'/api/health',
|
||||||
|
'/api/uptime',
|
||||||
|
'/api/last-runs',
|
||||||
|
'/api/build-web',
|
||||||
|
'/api/build-web/logs',
|
||||||
|
'/api/build-web/status',
|
||||||
|
'/api/build-roam',
|
||||||
|
'/api/build-roam/logs',
|
||||||
|
'/api/build-roam/status',
|
||||||
|
'/api/rerun-emacs',
|
||||||
|
'/api/rerun-emacs/logs',
|
||||||
|
'/api/rerun-emacs/status',
|
||||||
|
'/api/run-combined',
|
||||||
|
'/api/run-combined/logs',
|
||||||
|
'/api/run-combined/status'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const endpoint of expectedEndpoints) {
|
||||||
|
assert.ok(html.includes(endpoint), `missing endpoint ${endpoint}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.match(html, /new EventSource\(url\)/);
|
||||||
|
assert.match(html, /addEventListener\(['"]log['"]/);
|
||||||
|
assert.match(html, /addEventListener\(['"]done['"]/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('primary buttons are wired to their handlers', () => {
|
||||||
|
const expectedWiring = [
|
||||||
|
["buildBtn", "runWebBuild"],
|
||||||
|
["orgRoamBtn", "runOrgRoamBuild"],
|
||||||
|
["orgRoamBtn2", "rerunEmacs"],
|
||||||
|
["combinedBtn", "runCombined"]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [id, handler] of expectedWiring) {
|
||||||
|
assert.match(
|
||||||
|
html,
|
||||||
|
new RegExp(`getElementById\\(['"]${id}['"]\\)\\.addEventListener\\(['"]click['"], ${handler}\\)`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('retro layout classes and accessible structure are present', () => {
|
||||||
|
for (const className of ['topbar', 'dashboard-grid', 'rail', 'panel', 'run-grid', 'log-tools']) {
|
||||||
|
assert.match(html, new RegExp(`class=["'][^"']*\\b${className}\\b`), `missing .${className}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.match(html, /<main class=["']page["']/);
|
||||||
|
assert.match(html, /aria-label=["']Build runs["']/);
|
||||||
|
assert.match(html, /role=["']dialog["']/);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user