Skip to content

Commit efd7bbc

Browse files
feat(ci): split test job into unit/integration/e2e matrix + Codecov flags (#3559)
* feat(ci): split test job into unit/integration/e2e matrix + Codecov flags Axis B parallelization: the monolithic test job is split into a 3-way matrix (unit / integration / e2e) so each category runs on its own runner concurrently. Per-job heap drops 6144 → 4096 MB since each job handles ~half the suites. e2e runs as a pure pass/fail gate without coverage upload (product-flow paths, not coverage drivers). Unit and integration each upload a Codecov flag; Codecov merges them server-side so the combined % reflects lines covered by at least one job. - package.json: add test:unit:coverage + test:integration:coverage; legacy test:coverage kept as local dev convenience alias - jest.config.js: remove coverageThreshold — gating moves to Codecov status checks (per-job thresholds fail since each covers only a slice) - codecov.yml: add unit/integration flags, after_n_builds: 2, comment layout with flags panel; preserve existing project/patch auto targets - CI.yml: matrix strategy with fail-fast: false, lint once on unit job, conditional coverage upload skipped for e2e - README: document the new per-category scripts and CI matrix * ci: pin codecov/codecov-action to full SHA (v5.5.4) * fix(ci): guard coverage upload with !cancelled() + token env check - !cancelled() prevents Codecov from hanging on after_n_builds: 2 when a test job fails and skips its upload step - env.CODECOV_TOKEN != '' restores fork-PR guard from original CI; on forks secrets.* are empty so the step would fail without this guard
1 parent b257c87 commit efd7bbc

5 files changed

Lines changed: 69 additions & 22 deletions

File tree

.github/workflows/CI.yml

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ concurrency:
2020

2121
jobs:
2222
test:
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
suite: [unit, integration, e2e]
2327
runs-on: ${{ vars.RUNNER || 'ubuntu-latest' }}
2428
timeout-minutes: 30
2529

@@ -49,16 +53,29 @@ jobs:
4953

5054
- run: npm ci
5155

52-
- run: npm run lint
53-
54-
- run: npm run test:coverage
55-
56-
- uses: codecov/codecov-action@v5
57-
if: env.CODECOV_TOKEN != ''
56+
- name: Lint (once on the unit job)
57+
if: matrix.suite == 'unit'
58+
run: npm run lint
59+
60+
- name: Run tests
61+
run: |
62+
case "${{ matrix.suite }}" in
63+
unit|integration)
64+
npm run test:${{ matrix.suite }}:coverage
65+
;;
66+
e2e)
67+
npm run test:e2e
68+
;;
69+
esac
70+
71+
- name: Upload coverage
72+
if: "!cancelled() && matrix.suite != 'e2e' && env.CODECOV_TOKEN != ''"
73+
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
5874
env:
5975
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
6076
with:
6177
token: ${{ secrets.CODECOV_TOKEN }}
78+
flags: ${{ matrix.suite }}
6279
slug: ${{ github.repository }}
6380

6481
parallel-smoke:

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,18 @@ npm run prod
8383
### Testing
8484

8585
```bash
86-
npm test # Run all tests (one-shot)
87-
npm run test:unit # Run unit tests once (alias of npm test)
88-
npm run test:watch # Run tests in watch mode
89-
npm run test:coverage # Generate coverage report
90-
npm run test:parallel-smoke # Regression gate for per-pid test DB isolation (#3515)
86+
npm test # Run unit tests (one-shot)
87+
npm run test:unit # Run unit tests once (alias of npm test)
88+
npm run test:integration # Run integration tests once
89+
npm run test:e2e # Run e2e tests once (pass/fail gate, no coverage)
90+
npm run test:watch # Run tests in watch mode
91+
npm run test:unit:coverage # Unit tests + coverage report (CI: unit matrix job)
92+
npm run test:integration:coverage # Integration tests + coverage report (CI: integration matrix job)
93+
npm run test:coverage # Legacy alias: all suites + coverage (local dev convenience)
94+
npm run test:parallel-smoke # Regression gate for per-pid test DB isolation (#3515)
9195
```
9296

93-
Tests are organized per module in `modules/*/tests/`. The `test:parallel-smoke` script spawns N concurrent jest children against the same mongod and asserts none of them trample each other — gates against accidental regression of the per-pid `NodeTest_${pid}` default in `config/defaults/test.config.js`. Off the critical path in CI (own job), so it never blocks merges.
97+
Tests are organized per module in `modules/*/tests/`. In CI the test job runs as a 3-way matrix (`unit` / `integration` / `e2e`) in parallel: `unit` and `integration` each upload a Codecov flag, and Codecov merges them server-side to compute combined coverage. e2e tests run as a pure pass/fail gate without coverage upload — they verify product-critical flows, not coverage. The `test:parallel-smoke` script spawns N concurrent jest children against the same mongod and asserts none of them trample each other — gates against accidental regression of the per-pid `NodeTest_${pid}` default in `config/defaults/test.config.js`. Off the critical path in CI (own job), so it never blocks merges.
9498

9599
### Code Quality
96100

codecov.yml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,36 @@ coverage:
33
project:
44
default:
55
target: auto
6+
threshold: 0.5%
7+
flags:
8+
- unit
9+
- integration
610
patch:
711
default:
8-
target: 80%
12+
target: auto
13+
threshold: 0%
14+
flags:
15+
- unit
16+
- integration
17+
18+
flags:
19+
unit:
20+
paths:
21+
- lib
22+
- modules
23+
- config
24+
integration:
25+
paths:
26+
- lib
27+
- modules
28+
- config
29+
30+
comment:
31+
layout: "header, diff, flags, components, footer"
32+
behavior: default
33+
require_changes: false
34+
35+
# Wait for both flags to upload before posting status
36+
codecov:
37+
notify:
38+
after_n_builds: 2

jest.config.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,9 @@ export default {
6464
// A list of reporter names that Jest uses when writing coverage reports
6565
coverageReporters: ['json', 'lcov', 'clover', 'text'],
6666

67-
// An object that configures minimum threshold enforcement for coverage results
68-
coverageThreshold: {
69-
global: {
70-
statements: 80,
71-
branches: 65,
72-
functions: 80,
73-
lines: 80,
74-
},
75-
},
67+
// coverageThreshold removed — coverage gating moved to Codecov status checks
68+
// (unit + integration flags merged server-side; per-job thresholds would fail
69+
// since each job covers only its slice of source paths)
7670

7771
// Make calling deprecated APIs throw helpful error messages
7872
// errorOnDeprecated: false,

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
"test:e2e": "cross-env NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --runInBand --testPathPatterns='e2e'",
3636
"test:watch": "cross-env NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --watchAll",
3737
"test:coverage": "cross-env NODE_ENV=test NODE_OPTIONS=\"--experimental-vm-modules --max-old-space-size=6144 --expose-gc\" jest --coverage --maxWorkers=2",
38+
"test:unit:coverage": "cross-env NODE_ENV=test NODE_OPTIONS=\"--experimental-vm-modules --max-old-space-size=4096 --expose-gc\" jest --coverage --maxWorkers=2 --testPathPatterns='unit'",
39+
"test:integration:coverage": "cross-env NODE_ENV=test NODE_OPTIONS=\"--experimental-vm-modules --max-old-space-size=4096 --expose-gc\" jest --coverage --maxWorkers=2 --testPathPatterns='integration'",
3840
"test:parallel-smoke": "cross-env NODE_ENV=test node scripts/parallel-integration.smoke.js",
3941
"lint": "eslint ./modules ./lib ./config ./scripts",
4042
"seed:dev": "cross-env NODE_ENV=development node scripts/seed.js seed",

0 commit comments

Comments
 (0)