diff --git a/.gitignore b/.gitignore index b7896912..dedb4046 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ data-lincomatic/ config-lincomatic.json theme.json firmware/ +coverage/ diff --git a/AGENTS.md b/AGENTS.md index df0af409..6eea5b64 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -141,12 +141,16 @@ node tools/e2e-test.js # 44 tests — E2E: spins up temp server, inje node tools/frontend-test.js # 66 tests — frontend smoke: HTML, JS refs, API shapes ``` -**ALL existing tests must pass before pushing.** Run at minimum: +**ALL existing tests must pass before pushing.** Run: ```bash -node test-packet-filter.js && node test-aging.js && node test-regional-filter.js && node tools/e2e-test.js && node tools/frontend-test.js +npm test # all tests + coverage summary +npm run test:unit # fast: unit tests only (no server needed) +npm run test:coverage # all tests + HTML coverage report in coverage/ ``` If any test fails, fix it before pushing. No exceptions. No "known failures." +**Coverage baseline:** 37% statements, 42% branches, 54% functions. Coverage should only go up. + **Every new feature must add tests.** If you add logic, add tests. If you fix a bug, add a regression test. Test count should only go up, never down. Tests that hit live data can use `https://analyzer.00id.net` — all API endpoints are public, no auth required. diff --git a/package.json b/package.json index eaae7421..04fabee8 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "description": "Community-run alternative to the closed-source `analyzer.letsmesh.net`. MQTT packet collection + open-source web analyzer for the Bay Area MeshCore mesh.", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "npx c8 --reporter=text --reporter=text-summary sh test-all.sh", + "test:unit": "node test-packet-filter.js && node test-aging.js && node test-regional-filter.js", + "test:coverage": "npx c8 --reporter=text --reporter=html sh test-all.sh" }, "keywords": [], "author": "", @@ -16,4 +18,4 @@ "mqtt": "^5.15.0", "ws": "^8.19.0" } -} +} \ No newline at end of file diff --git a/test-all.sh b/test-all.sh new file mode 100755 index 00000000..ed2c167d --- /dev/null +++ b/test-all.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Run all tests with coverage +set -e + +echo "═══════════════════════════════════════" +echo " MeshCore Analyzer — Test Suite" +echo "═══════════════════════════════════════" +echo "" + +# Unit tests (deterministic, fast) +echo "── Unit Tests ──" +node test-packet-filter.js +node test-aging.js +node test-regional-filter.js + +# Integration tests (spin up temp servers) +echo "" +echo "── Integration Tests ──" +node tools/e2e-test.js +node tools/frontend-test.js + +echo "" +echo "═══════════════════════════════════════" +echo " All tests passed" +echo "═══════════════════════════════════════" diff --git a/tools/e2e-test.js b/tools/e2e-test.js index 88146847..8d007d64 100644 --- a/tools/e2e-test.js +++ b/tools/e2e-test.js @@ -370,9 +370,10 @@ async function main() { // 5e. Channels console.log('── Channels ──'); const chResp = (await get('/api/channels')).data; - assert(Array.isArray(chResp.channels), 'channels response is array'); - if (chResp.channels.length > 0) { - const someCh = chResp.channels[0]; + const chList = chResp.channels || []; + assert(Array.isArray(chList), 'channels response is array'); + if (chList.length > 0) { + const someCh = chList[0]; assert(someCh.messageCount > 0, `channel has messages (${someCh.messageCount})`); const msgResp = (await get(`/api/channels/${someCh.hash}/messages`)).data; assert(msgResp.messages.length > 0, 'channel has message list');