Files
meshcore-analyzer/tests/unit/test-observers-headings.js
T
Alex B 893773338e chore(tests): move root test-*.js into tests/unit and tests/e2e (#2036)
Moves 290 root test-*.js into tests/unit (177, listed in test-all.sh) and tests/e2e (113, classified in scripts/non-unit-tests.json), per #1981 and PR-D of #1385. Root goes from 348 entries to 48. test-all.sh and test-fixtures/ stay put. The inventory guard now fails if a test reappears in the root or sits in the wrong folder.

Verified independently of the diff: the invoked sets are unchanged (test-all.sh 177 before and after, deploy.yml 96 before and after, both identical as sets), and a full local run of test-all.sh on master and on the branch produced 4702 output lines each whose only differences are absolute paths, stack-trace line numbers shifted by the REPO_ROOT line, the inventory wording and two perf ratios. The guard was mutation-checked: a test back in the root, a unit suite in tests/e2e, and a suite dropped from test-all.sh each make it exit 1. CI run 35246304316 ran 97 suites from tests/e2e and is green.

Follow-up 9335c51d finished the instruction files: no bare root test command is left in AGENTS.md, the squad charters, .github or docs, and every tests/ path they name resolves.

Merged by the interim maintainer without a second human reviewer: CI and the local runs above are the independent checks.

Known and deliberately out of scope: 18 of the 113 files in tests/e2e are invoked by no runner at all, and one of them cannot run anywhere because it requires jsdom, which is not a declared dependency. Tracked separately.
2026-09-17 19:06:07 +02:00

70 lines
2.7 KiB
JavaScript

/* test-observers-headings.js — Issue #1039 regression test.
* Asserts observer table thead column count matches tbody row column count.
*/
'use strict';
const REPO_ROOT = require('path').resolve(__dirname, '..', '..');
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const src = fs.readFileSync(path.join(REPO_ROOT, 'public', 'observers.js'), 'utf8');
let passed = 0, failed = 0;
function test(name, fn) {
try { fn(); passed++; console.log(` ✓ ${name}`); }
catch (e) { failed++; console.log(` ✗ ${name}\n ${e.message}`); }
}
function extractBlock(s, openRe, closeRe) {
const m = s.match(openRe);
if (!m) throw new Error('open marker not found');
const start = m.index + m[0].length;
const rest = s.slice(start);
const cm = rest.match(closeRe);
if (!cm) throw new Error('close marker not found');
return rest.slice(0, cm.index);
}
console.log('── Observers table headings (#1039) ──');
test('thead column count equals tbody row column count', () => {
const thead = extractBlock(src, /<thead><tr>/, /<\/tr><\/thead>/);
const thCount = (thead.match(/<th\b/g) || []).length;
// tbody row template lives inside a backtick-template `<tr ...>...</tr>`.
// Grab from the first `<tr ` after `tbody>` up to the first `</tr>`.
const tbodyStart = src.indexOf('<tbody>');
assert.ok(tbodyStart > 0, '<tbody> not found in observers.js');
const after = src.slice(tbodyStart);
const trOpen = after.search(/`<tr\b/);
assert.ok(trOpen > 0, 'row template `<tr` not found');
const rowStart = trOpen;
const rowEnd = after.indexOf('</tr>', rowStart);
assert.ok(rowEnd > rowStart, '</tr> not found in row template');
const row = after.slice(rowStart, rowEnd);
const tdCount = (row.match(/<td\b/g) || []).length;
assert.strictEqual(
tdCount, thCount,
`Observer table column mismatch: ${thCount} <th> headings vs ${tdCount} <td> cells per row. ` +
`Headings drift after "Last Packet" — see issue #1039.`
);
});
test('expected headings present and ordered', () => {
const thead = extractBlock(src, /<thead><tr>/, /<\/tr><\/thead>/);
const labels = [];
const re = /<th[^>]*>([^<]+)<\/th>/g;
let m;
while ((m = re.exec(thead)) !== null) labels.push(m[1].trim());
const expected = ['Status', 'Name', 'Region', 'Last Status', 'Last Packet',
'Packet Health', 'Total Packets', 'Packets/Hour', 'Clock Offset', 'Uptime',
'Firmware', 'Client'];
assert.deepStrictEqual(labels, expected,
`Headings out of sync.\nGot: ${JSON.stringify(labels)}\nExpected: ${JSON.stringify(expected)}`);
});
console.log(`\n${passed} passed, ${failed} failed`);
process.exit(failed === 0 ? 0 : 1);