diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml new file mode 100644 index 000000000..fb935008c --- /dev/null +++ b/.github/workflows/unit-tests.yaml @@ -0,0 +1,37 @@ +name: Unit Tests + +on: + push: + branches: [main, 'v[0-9]+.[0-9]+'] + pull_request: + workflow_dispatch: + +jobs: + unit-tests: + name: Unit Tests (Node.js v${{ matrix.node-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [20, 22, 24] + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + submodules: 'recursive' + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: ${{ matrix.node-version }} + package-manager-cache: false + + - name: Install dependencies + run: npm install --ignore-scripts + + - name: Build + run: npm run build || true + + - name: Run unit tests + run: npm run test:unit diff --git a/AGENTS.md b/AGENTS.md index bc5b2a332..9070b7a7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,7 +47,8 @@ npm run lint:fix npm run format:write # prettier npm run lint:required # quiet — for CI -# Tests — only integration here +# Tests +npm run test:unit # mocha unit tests (fast, no server — build first) npm run test:integration npm run test:integration:all # all *.test.ts in integrationTests/ @@ -58,7 +59,7 @@ npm run core:set-branch # pin core to a different branch The `cluster:*` scripts in `package.json` reference `utility/dev/docker-compose.*.yml` files that are not present in the repository — they're likely produced by a private dev tooling step. Don't expect them to work out of the box. -**No `test:unit` exists.** Pro relies on core's unit suite for the substrate it inherits. `test:integration` is slow — run only when the change plausibly affects integration behavior. +`test:unit` runs `unitTests/**/*.test.mjs` via mocha (requires a built `dist/` — run `npm run build` first). `test:integration` is slow — run only when the change plausibly affects integration behavior. --- @@ -97,7 +98,7 @@ When a feature spans both, prefer landing as much as possible in `core/` and glu ### Pro tests - **`integrationTests/`** — end-to-end, runs full Harper instances. `run.mjs` is the custom test harness with shard support. Subdirs mirror source (`analytics/`, `cloneNode/`, `cluster/`, `licensing/`, `security/`). -- **`unitTests/`** — small. `testUtils.js` (mock helpers, db reset) and `setupTestApp.mjs` (in-memory app scaffold). +- **`unitTests/`** — mocha unit tests (`npm run test:unit`). `testUtils.js` (mock helpers, db reset), `setupTestApp.mjs` (in-memory app scaffold), `unitTestSetup.cjs` (env bootstrap required before ESM module load). ### Pro non-source diff --git a/package.json b/package.json index f2238d46f..d32a6687a 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,7 @@ "lint": "oxlint --deny-warnings .", "lint:fix": "npm run lint -- --fix", "lint:required": "oxlint --quiet .", + "test:unit": "mocha --require unitTests/unitTestSetup.cjs 'unitTests/**/*.test.mjs'", "test:integration": "HARPER_INTEGRATION_TEST_INSTALL_SCRIPT=dist/bin/harper.js harper-integration-test-run", "test:integration:all": "npm run test:integration -- integrationTests/**/*.test.*s", "cluster:ip:local": "pushd utility/dev && docker compose -f docker-compose.ip.yml --project-directory ../.. build && docker compose -f docker-compose.ip.yml --project-directory ../.. up; popd", diff --git a/renovate.json b/renovate.json index 8c541fd2f..fd1281b7d 100644 --- a/renovate.json +++ b/renovate.json @@ -18,13 +18,15 @@ "groupName": "pin digests", "groupSlug": "all-digests", "matchDepTypes": ["action"], - "pinDigests": true + "pinDigests": true, + "automerge": true }, { "groupName": "all non-major dependencies", "groupSlug": "all-minor-patch", "matchUpdateTypes": ["minor", "patch"], - "matchCurrentVersion": "!/^0/" + "matchCurrentVersion": "!/^0/", + "automerge": true } ] } diff --git a/unitTests/unitTestSetup.cjs b/unitTests/unitTestSetup.cjs new file mode 100644 index 000000000..d732c09dc --- /dev/null +++ b/unitTests/unitTestSetup.cjs @@ -0,0 +1,16 @@ +'use strict'; +const os = require('os'); +const path = require('path'); +const fs = require('fs'); + +// Minimal environment setup required before Harper modules are loaded. +// Harper's auth and database modules initialize storage at import time, +// so these env vars must be set before the ESM test files are evaluated. +const testDir = path.join(os.tmpdir(), `harper-unit-tests-${process.pid}`); +fs.mkdirSync(testDir, { recursive: true }); + +process.env.STORAGE_PATH = testDir; +process.env._DISABLE_NATS = 'true'; +process.env.LOGGING_STDSTREAMS = 'false'; + +process.on('exit', () => fs.rmSync(testDir, { recursive: true, force: true }));