From aee7ec648b47cb66eeea7acb8fb2b845a00f6d74 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 19:45:47 +0800 Subject: [PATCH 1/8] feat: support parallel tests --- .github/workflows/nodejs.yml | 3 ++- package.json | 1 + src/commands/test.ts | 17 ++++++++++++++++- test/commands/test.test.ts | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 21c6be1f..47930a99 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,9 +9,10 @@ on: jobs: Job: name: Node.js - uses: node-modules/github-actions/.github/workflows/node-test.yml@master + uses: node-modules/github-actions/.github/workflows/node-test-parallel.yml@test-parallel with: os: 'ubuntu-latest, macos-latest, windows-latest' version: '18.19.0, 18, 20, 22, 23' + parallel: 4 secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/package.json b/package.json index 47c46751..c0a75b5b 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@types/mocha": "^10.0.10", "@types/supertest": "^6.0.2", "c8": "^10.0.0", + "ci-parallel-vars": "^1.0.1", "detect-port": "^2.0.0", "egg-ts-helper": "^3.0.0", "globby": "^11.1.0", diff --git a/src/commands/test.ts b/src/commands/test.ts index 60705acd..88f7e354 100644 --- a/src/commands/test.ts +++ b/src/commands/test.ts @@ -6,6 +6,8 @@ import { Args, Flags } from '@oclif/core'; import globby from 'globby'; import { importResolve, detectType, EggType } from '@eggjs/utils'; import { getChangedFilesForRoots } from 'jest-changed-files'; +// @ts-expect-error no types +import ciParallelVars from 'ci-parallel-vars'; import { BaseCommand } from '../baseCommand.js'; const debug = debuglog('@eggjs/bin/commands/test'); @@ -166,7 +168,7 @@ export default class Test extends BaseCommand { pattern = pattern.concat([ '!test/fixtures', '!test/node_modules' ]); // expand glob and skip node_modules and fixtures - const files = globby.sync(pattern, { cwd: flags.base }); + let files = globby.sync(pattern, { cwd: flags.base }); files.sort(); if (files.length === 0) { @@ -174,6 +176,19 @@ export default class Test extends BaseCommand { return; } + // split up test files in parallel CI jobs + if (ciParallelVars) { + const { index: currentIndex, total: totalRuns } = ciParallelVars as { index: number, total: number }; + const fileCount = files.length; + const each = Math.floor(fileCount / totalRuns); + const remainder = fileCount % totalRuns; + const offset = Math.min(currentIndex, remainder) + (currentIndex * each); + const currentFileCount = each + (currentIndex < remainder ? 1 : 0); + files = files.slice(offset, offset + currentFileCount); + console.log('# Split test files in parallel CI jobs: %d/%d, files: %d/%d', + currentIndex + 1, totalRuns, files.length, fileCount); + } + // auto add setup file as the first test file const setupFile = path.join(flags.base, `test/.setup.${ext}`); try { diff --git a/test/commands/test.test.ts b/test/commands/test.test.ts index c198404f..e0bf2ee7 100644 --- a/test/commands/test.test.ts +++ b/test/commands/test.test.ts @@ -20,6 +20,24 @@ describe('test/commands/test.test.ts', () => { .end(); }); + it('should work on split test files in parallel CI jobs', () => { + return coffee.fork(eggBin, [ 'test' ], { + cwd, + env: { + CI_NODE_INDEX: '2', + CI_NODE_TOTAL: '3', + }, + }) + // .debug() + .expect('stdout', /# Split test files in parallel CI jobs: 3\/3, files: 1\/4/) + .expect('stdout', /should success/) + .expect('stdout', /no-timeouts\.test\.js/) + .notExpect('stdout', /a\.test\.js/) + .expect('stdout', /1 passing \(/) + .expect('code', 0) + .end(); + }); + it('should success with some files', async () => { await coffee.fork(eggBin, [ 'test', 'test/a.test.js' ], { cwd }) // .debug() From c25f207732aafc96a66f3333ff90ee47f9da3f51 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 20:03:21 +0800 Subject: [PATCH 2/8] f --- .github/workflows/nodejs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 47930a99..0dc146f1 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -14,5 +14,6 @@ jobs: os: 'ubuntu-latest, macos-latest, windows-latest' version: '18.19.0, 18, 20, 22, 23' parallel: 4 + action_ref: 'test-parallel' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From ca5cf0380274ffa3c183e13763ba14d4877e654f Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 20:12:12 +0800 Subject: [PATCH 3/8] f --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 0dc146f1..b6638552 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -13,7 +13,7 @@ jobs: with: os: 'ubuntu-latest, macos-latest, windows-latest' version: '18.19.0, 18, 20, 22, 23' - parallel: 4 + parallel: 2 action_ref: 'test-parallel' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 1944f27729165326ed893cb87148837a5c1dfb8e Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 20:22:53 +0800 Subject: [PATCH 4/8] f --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index b6638552..5e2bb373 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -12,7 +12,7 @@ jobs: uses: node-modules/github-actions/.github/workflows/node-test-parallel.yml@test-parallel with: os: 'ubuntu-latest, macos-latest, windows-latest' - version: '18.19.0, 18, 20, 22, 23' + version: '18, 20, 22' parallel: 2 action_ref: 'test-parallel' secrets: From 8263ed5b0ad9be1b01f71ef7fdf5322aa4dbc50a Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 20:47:44 +0800 Subject: [PATCH 5/8] f --- .github/workflows/nodejs.yml | 3 +-- .../example-ts-cluster/test/index.test.ts | 15 +++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 5e2bb373..979fae73 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,11 +9,10 @@ on: jobs: Job: name: Node.js - uses: node-modules/github-actions/.github/workflows/node-test-parallel.yml@test-parallel + uses: node-modules/github-actions/.github/workflows/node-test-parallel.yml@master with: os: 'ubuntu-latest, macos-latest, windows-latest' version: '18, 20, 22' parallel: 2 - action_ref: 'test-parallel' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/test/fixtures/example-ts-cluster/test/index.test.ts b/test/fixtures/example-ts-cluster/test/index.test.ts index 5216e20a..8fd200fe 100644 --- a/test/fixtures/example-ts-cluster/test/index.test.ts +++ b/test/fixtures/example-ts-cluster/test/index.test.ts @@ -1,22 +1,25 @@ +import { scheduler } from 'node:timers/promises'; import mm, { MockOption } from '@eggjs/mock'; import request from 'supertest'; -describe('test/index.test.ts', () => { +describe('example-ts-cluster/test/index.test.ts', () => { let app: any; - before(() => { + before(async () => { app = mm.cluster({ opt: { execArgv: [ '--require', 'ts-node/register' ], }, } as MockOption); - // app.debug(); - return app.ready(); + app.debug(); + await app.ready(); + await scheduler.wait(1000); }); after(() => app.close()); it('should work', async () => { - const req = request(`http://127.0.0.1:${app.port}`); - return req + const url = `http://127.0.0.1:${app.port}`; + console.log('request %s', url); + await request(url) .get('/') .expect('hi, egg') .expect(200); From 9b9644c4eaf5d883fd87e919f69c4645d9a7dbde Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 22:24:55 +0800 Subject: [PATCH 6/8] f --- test/ts.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/ts.test.ts b/test/ts.test.ts index 32e2e4d5..3575a60a 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -74,6 +74,11 @@ describe('test/ts.test.ts', () => { }); it('should cov app in cluster mod', () => { + // TODO(@fengmk2): not work on Node.js 22 + linux + // https://github.com/eggjs/bin/actions/runs/13308042479/job/37164115998 + if (process.platform === 'linux' && process.version.startsWith('v22.')) { + return; + } cwd = getFixtures('example-ts-cluster'); return coffee.fork(eggBin, [ 'cov' ], { cwd }) .debug() From 3fd6ec9359131f491beb025ddef2ca6bce3084be Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 22:29:43 +0800 Subject: [PATCH 7/8] f --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c0a75b5b..800bdf51 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,8 @@ "cpy-cli": "^5.0.0", "cross-env": "^7.0.3", "egg": "^4.0.7", - "esbuild": "^0.17.7", - "esbuild-register": "^3.4.2", + "esbuild": "^0.25.0", + "esbuild-register": "^3.6.0", "eslint": "8", "eslint-config-egg": "14", "npminstall": "^7.12.0", From 3e12a720fe6c191d19c7e918aef5a02342db6d07 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 13 Feb 2025 22:37:42 +0800 Subject: [PATCH 8/8] f --- test/ts.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ts.test.ts b/test/ts.test.ts index 3575a60a..2b32a0bd 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -74,9 +74,9 @@ describe('test/ts.test.ts', () => { }); it('should cov app in cluster mod', () => { - // TODO(@fengmk2): not work on Node.js 22 + linux + // TODO(@fengmk2): not work on Node.js 22 // https://github.com/eggjs/bin/actions/runs/13308042479/job/37164115998 - if (process.platform === 'linux' && process.version.startsWith('v22.')) { + if (process.version.startsWith('v22.')) { return; } cwd = getFixtures('example-ts-cluster');