Merge pull request #948 from therickfactr/fix/root-test-script-scope

Scope the root test script to tests/ so npm test runs from a clean install
This commit is contained in:
Resham Joshi 2026-08-10 04:02:42 -07:00 committed by GitHub
commit a6446d94d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 50 additions and 23 deletions

View file

@ -24,17 +24,24 @@ There is no separate build step required to run the dev CLI. `npm run dev` runs
| Command | What it does |
|---|---|
| `npm test` | Runs the vitest suite (42 test files, 568 tests). |
| `npm test` | Runs the vitest suite under `tests/` (189 of the 192 files, 2,494 tests). |
| `npm run test:locks` | Runs the three parallelism-sensitive `cache-refresh-lock` suites serially. |
| `npm run test:watch` | Same scope as `npm test`, in watch mode. |
| `npm run dev -- status` | Runs the CLI in dev mode against your real data. |
| `npm run build` | Bundles the litellm pricing snapshot, then runs `tsup` to produce `dist/cli.js`. |
| `npm run bundle-litellm` | Refreshes `src/data/litellm-snapshot.json` from the upstream litellm repo. |
To test a specific suite, pass a path:
To test a specific suite, run vitest directly with a path:
```bash
npm test -- tests/providers/codex.test.ts
npx vitest run tests/providers/codex.test.ts
```
`npm test` is scoped to `tests/` on purpose. The Electron app under `app/` carries its
own vitest config and its own `jsdom` dependency in `app/node_modules`; letting vitest's
default glob reach those specs from a root install fails with
`ERR_MODULE_NOT_FOUND: jsdom`. To run the app's tests, install and run them from `app/`.
## What to Read Before Editing
- `docs/architecture.md` for the high-level codebase map.
@ -65,9 +72,14 @@ See `docs/architecture.md` for a fuller map.
## Tests
- Each new provider should ship with a fixture-based test under `tests/providers/`. The five providers without test files today (claude, gemini, goose, qwen, antigravity) are a known gap; new code should not add to that list.
- Each new provider should ship with a fixture-based test under `tests/providers/`. The three providers without test files today (claude, goose, qwen) are a known gap; new code should not add to that list.
- Each new optimize detector in `src/optimize.ts` needs at least one positive and one negative case in `tests/optimize.test.ts`.
- If your change affects the menubar JSON contract, update `tests/menubar-json.test.ts`.
- A new test that exercises the cross-process refresh lock must be named
`tests/cache-refresh-lock-<what>.test.ts` **and** added to the `test:locks` script in
`package.json`. `npm test` excludes that prefix, so a lock test placed anywhere else
runs under the full worker pool and fails intermittently; one that matches the prefix
but is missing from `test:locks` never runs at all.
## Commit Message Format

View file

@ -14,8 +14,13 @@ Run the test suite to catch any regressions:
```bash
npm test
npm run test:locks
```
`npm test` covers `tests/`. `npm run test:locks` runs the three parallelism-sensitive
`cache-refresh-lock` suites serially; CI treats them as reporting-only, so check them by
hand here.
Verify that the build completes without errors:
```bash

View file

@ -177,13 +177,21 @@ The `prepublishOnly` hook in `package.json` runs `npm run build` so `npm publish
## Tests
`npm test` runs vitest. Forty-two test files live under `tests/`:
`npm test` runs vitest, scoped to `tests/`. 192 test files live there:
- `tests/` root (27 files) covers CLI, parser, optimize, cache, format, models, plans.
- `tests/` root (141 files) covers CLI, parser, optimize, cache, format, models, plans.
- `tests/security/` (1 file) covers prototype-pollution guards.
- `tests/providers/` (15 files) covers per-provider parsing.
- `tests/providers/` (44 files) covers per-provider parsing.
- `tests/sharing/` (6 files) covers the share/export surface.
- `tests/setup/` holds the env-isolation setup file, not specs.
- `tests/fixtures/` holds redacted real-world session data.
Five providers ship without dedicated test files today: `antigravity`, `claude`, `gemini`, `goose`, `qwen`. Closing this gap is a standing good-first-issue.
The scope is deliberate: the Electron app under `app/` has its own vitest config and its
own `jsdom` dependency, so vitest's default glob must not reach it from a root install.
The three `cache-refresh-lock` suites are excluded from `npm test` and run serially via
`npm run test:locks`, because they exercise a cross-process file lock and fail under full
worker pressure.
CI runs Semgrep against `.semgrep/rules/no-bracket-assign-hot-paths.yml` over `src/providers/` and `src/parser.ts` (`.github/workflows/ci.yml`). It does not run vitest in CI today; tests run locally before publish.
Three providers ship without dedicated test files today: `claude`, `goose`, `qwen`. Closing this gap is a standing good-first-issue.
CI runs Semgrep against `.semgrep/rules/no-bracket-assign-hot-paths.yml` over `src/providers/` and `src/parser.ts` (`.github/workflows/ci.yml`). The vitest suite runs in CI too, via `.github/workflows/tests.yml`, on every pull request and every push to `main`.

View file

@ -184,7 +184,7 @@ Keep `main.ts:477484` (the `daysSelection`/`customRange`/`daySelection`/`peri
- [ ] **Step 4: Typecheck + parity test**
Run: `npx tsc --noEmit && npm test -- cli-status-menubar`
Run: `npx tsc --noEmit && npx vitest run cli-status-menubar`
Expected: clean typecheck; `tests/cli-status-menubar.test.ts` passes — i.e. `status --format menubar-json` output is unchanged (parity).
- [ ] **Step 5: Add a direct unit test for the aggregator**
@ -207,7 +207,7 @@ describe('buildMenubarPayloadForRange', () => {
})
```
Run: `npm test -- usage-aggregator`
Run: `npx vitest run usage-aggregator`
Expected: PASS (uses the empty real environment; `scanAndDetect` not called because `optimize:false`).
- [ ] **Step 6: Commit**
@ -272,7 +272,7 @@ describe('redact', () => {
- [ ] **Step 2: Run to verify failure**
Run: `npm test -- mcp-redact`
Run: `npx vitest run mcp-redact`
Expected: FAIL ("Cannot find module '../src/mcp/redact.js'").
- [ ] **Step 3: Implement**
@ -302,7 +302,7 @@ export function redactProjectNames(payload: MenubarPayload, includeNames: boolea
- [ ] **Step 4: Run to verify pass**
Run: `npm test -- mcp-redact`
Run: `npx vitest run mcp-redact`
Expected: PASS (3 tests).
- [ ] **Step 5: Commit**
@ -370,7 +370,7 @@ describe('tables', () => {
- [ ] **Step 2: Run to verify failure**
Run: `npm test -- mcp-tables`
Run: `npx vitest run mcp-tables`
Expected: FAIL ("Cannot find module '../src/mcp/tables.js'").
- [ ] **Step 3: Implement**
@ -434,7 +434,7 @@ export function renderSavingsTable(p: MenubarPayload): string {
- [ ] **Step 4: Run to verify pass**
Run: `npm test -- mcp-tables`
Run: `npx vitest run mcp-tables`
Expected: PASS (4 tests).
- [ ] **Step 5: Commit**
@ -521,7 +521,7 @@ describe('mcp server', () => {
- [ ] **Step 2: Run to verify failure**
Run: `npm test -- mcp-server`
Run: `npx vitest run mcp-server`
Expected: FAIL ("Cannot find module '../src/mcp/server.js'").
- [ ] **Step 3: Implement the server**
@ -660,7 +660,7 @@ export async function startStdioServer(version: string): Promise<void> {
- [ ] **Step 4: Run to verify pass**
Run: `npm test -- mcp-server`
Run: `npx vitest run mcp-server`
Expected: PASS (5 tests).
- [ ] **Step 5: Commit**

View file

@ -104,5 +104,5 @@ parser key is `codewhale:<session-id>`.
1. Reproduce with a minimal real-shape saved-session JSON fixture.
2. Verify aggregate tokens and parent-plus-subagent cost before checking UI
totals; do not infer an input/output split CodeWhale does not store.
3. Run `npm test -- tests/providers/codewhale.test.ts --run` and
`npm test -- tests/provider-registry.test.ts tests/session-cache.test.ts --run`.
3. Run `npx vitest run tests/providers/codewhale.test.ts` and
`npx vitest run tests/provider-registry.test.ts tests/session-cache.test.ts`.

View file

@ -62,6 +62,6 @@ The shared session cache fingerprints Hermes state DB files. `HERMES_HOME` is in
## When fixing a bug here
1. Reproduce against a real Hermes `state.db` or a minimal SQLite fixture.
2. Run `npm test -- tests/providers/hermes.test.ts --run`.
2. Run `npx vitest run tests/providers/hermes.test.ts`.
3. For local smoke testing, use an isolated cache directory, for example:
`CODEBURN_CACHE_DIR=/tmp/codeburn-hermes-cache node --import tsx -e "import { parseAllSessions } from './src/parser.ts'; console.log(await parseAllSessions(undefined, 'hermes'))"`.

View file

@ -85,4 +85,4 @@ The ledger is append-only, so line number is stable for normal operation.
1. Prefer a minimal redacted `token_ledger.jsonl` fixture over full `chat_history.jsonl`.
2. Check whether a daemon entry is already mirrored into the parent ledger before adding new discovery paths.
3. Run `npm test -- tests/providers/lingtai-tui.test.ts --run`.
3. Run `npx vitest run tests/providers/lingtai-tui.test.ts`.

View file

@ -57,6 +57,6 @@ Per `<sessionId>:<messageId>`.
## When fixing a bug here
1. The 558-line test suite catches a lot. Run `npm test -- tests/providers/opencode.test.ts` before and after any change.
1. The 558-line test suite catches a lot. Run `npx vitest run tests/providers/opencode.test.ts` before and after any change.
2. If the bug is "missing table" warning, do not catch and silence it. Either upgrade the version expectation in the parser or document the breaking schema change.
3. If the bug is "reasoning tokens off by one", check the parts index ordering.

View file

@ -16,7 +16,9 @@
"build:cli": "tsup && node -e \"const fs=require('fs'); fs.copyFileSync('src/cli.ts','dist/cli.js'); fs.chmodSync('dist/cli.js',0o755)\"",
"build:dash": "cd dash && npm install --no-audit --no-fund --silent && npm run build",
"dev": "NODE_OPTIONS=--no-deprecation tsx src/cli.ts",
"test": "vitest",
"test": "vitest run tests --exclude \"tests/cache-refresh-lock*\"",
"test:locks": "vitest run tests/cache-refresh-lock.test.ts tests/cache-refresh-lock-corrupt-body.test.ts tests/cache-refresh-lock-process.test.ts --poolOptions.forks.singleFork=true",
"test:watch": "vitest tests --exclude \"tests/cache-refresh-lock*\"",
"prepublishOnly": "npm run build"
},
"keywords": [