Skip to content

Commit b3f2b6c

Browse files
authored
feat: support parallel tests (#287)
closes #286 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Chores** - Enhanced the continuous integration pipeline to run tests in parallel for improved efficiency. - **New Features** - Enabled distribution of test files across multiple parallel jobs to optimize the testing process. - Introduced a new dependency to facilitate parallel test execution. - **Tests** - Added a test case to verify the functionality of running tests in parallel across different CI jobs. - Updated test suite for a TypeScript cluster application to improve asynchronous handling and debugging. - Implemented conditional checks to skip specific tests based on platform and Node.js version. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 8ec2d70 commit b3f2b6c

File tree

6 files changed

+54
-11
lines changed

6 files changed

+54
-11
lines changed

.github/workflows/nodejs.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ on:
99
jobs:
1010
Job:
1111
name: Node.js
12-
uses: node-modules/github-actions/.github/workflows/node-test.yml@master
12+
uses: node-modules/github-actions/.github/workflows/node-test-parallel.yml@master
1313
with:
1414
os: 'ubuntu-latest, macos-latest, windows-latest'
15-
version: '18.19.0, 18, 20, 22, 23'
15+
version: '18, 20, 22'
16+
parallel: 2
1617
secrets:
1718
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@types/mocha": "^10.0.10",
2424
"@types/supertest": "^6.0.2",
2525
"c8": "^10.0.0",
26+
"ci-parallel-vars": "^1.0.1",
2627
"detect-port": "^2.0.0",
2728
"egg-ts-helper": "^3.0.0",
2829
"globby": "^11.1.0",
@@ -55,8 +56,8 @@
5556
"cpy-cli": "^5.0.0",
5657
"cross-env": "^7.0.3",
5758
"egg": "^4.0.7",
58-
"esbuild": "^0.17.7",
59-
"esbuild-register": "^3.4.2",
59+
"esbuild": "^0.25.0",
60+
"esbuild-register": "^3.6.0",
6061
"eslint": "8",
6162
"eslint-config-egg": "14",
6263
"npminstall": "^7.12.0",

src/commands/test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { Args, Flags } from '@oclif/core';
66
import globby from 'globby';
77
import { importResolve, detectType, EggType } from '@eggjs/utils';
88
import { getChangedFilesForRoots } from 'jest-changed-files';
9+
// @ts-expect-error no types
10+
import ciParallelVars from 'ci-parallel-vars';
911
import { BaseCommand } from '../baseCommand.js';
1012

1113
const debug = debuglog('@eggjs/bin/commands/test');
@@ -166,14 +168,27 @@ export default class Test<T extends typeof Test> extends BaseCommand<T> {
166168
pattern = pattern.concat([ '!test/fixtures', '!test/node_modules' ]);
167169

168170
// expand glob and skip node_modules and fixtures
169-
const files = globby.sync(pattern, { cwd: flags.base });
171+
let files = globby.sync(pattern, { cwd: flags.base });
170172
files.sort();
171173

172174
if (files.length === 0) {
173175
console.log('No test files found with pattern %o', pattern);
174176
return;
175177
}
176178

179+
// split up test files in parallel CI jobs
180+
if (ciParallelVars) {
181+
const { index: currentIndex, total: totalRuns } = ciParallelVars as { index: number, total: number };
182+
const fileCount = files.length;
183+
const each = Math.floor(fileCount / totalRuns);
184+
const remainder = fileCount % totalRuns;
185+
const offset = Math.min(currentIndex, remainder) + (currentIndex * each);
186+
const currentFileCount = each + (currentIndex < remainder ? 1 : 0);
187+
files = files.slice(offset, offset + currentFileCount);
188+
console.log('# Split test files in parallel CI jobs: %d/%d, files: %d/%d',
189+
currentIndex + 1, totalRuns, files.length, fileCount);
190+
}
191+
177192
// auto add setup file as the first test file
178193
const setupFile = path.join(flags.base, `test/.setup.${ext}`);
179194
try {

test/commands/test.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ describe('test/commands/test.test.ts', () => {
2020
.end();
2121
});
2222

23+
it('should work on split test files in parallel CI jobs', () => {
24+
return coffee.fork(eggBin, [ 'test' ], {
25+
cwd,
26+
env: {
27+
CI_NODE_INDEX: '2',
28+
CI_NODE_TOTAL: '3',
29+
},
30+
})
31+
// .debug()
32+
.expect('stdout', /# Split test files in parallel CI jobs: 3\/3, files: 1\/4/)
33+
.expect('stdout', /should success/)
34+
.expect('stdout', /no-timeouts\.test\.js/)
35+
.notExpect('stdout', /a\.test\.js/)
36+
.expect('stdout', /1 passing \(/)
37+
.expect('code', 0)
38+
.end();
39+
});
40+
2341
it('should success with some files', async () => {
2442
await coffee.fork(eggBin, [ 'test', 'test/a.test.js' ], { cwd })
2543
// .debug()

test/fixtures/example-ts-cluster/test/index.test.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1+
import { scheduler } from 'node:timers/promises';
12
import mm, { MockOption } from '@eggjs/mock';
23
import request from 'supertest';
34

4-
describe('test/index.test.ts', () => {
5+
describe('example-ts-cluster/test/index.test.ts', () => {
56
let app: any;
6-
before(() => {
7+
before(async () => {
78
app = mm.cluster({
89
opt: {
910
execArgv: [ '--require', 'ts-node/register' ],
1011
},
1112
} as MockOption);
12-
// app.debug();
13-
return app.ready();
13+
app.debug();
14+
await app.ready();
15+
await scheduler.wait(1000);
1416
});
1517

1618
after(() => app.close());
1719
it('should work', async () => {
18-
const req = request(`http://127.0.0.1:${app.port}`);
19-
return req
20+
const url = `http://127.0.0.1:${app.port}`;
21+
console.log('request %s', url);
22+
await request(url)
2023
.get('/')
2124
.expect('hi, egg')
2225
.expect(200);

test/ts.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ describe('test/ts.test.ts', () => {
7474
});
7575

7676
it('should cov app in cluster mod', () => {
77+
// TODO(@fengmk2): not work on Node.js 22
78+
// https://github.com/eggjs/bin/actions/runs/13308042479/job/37164115998
79+
if (process.version.startsWith('v22.')) {
80+
return;
81+
}
7782
cwd = getFixtures('example-ts-cluster');
7883
return coffee.fork(eggBin, [ 'cov' ], { cwd })
7984
.debug()

0 commit comments

Comments
 (0)