From 558dea307e45bd5619eaa8b8f8135480b33700d0 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 11:23:01 +0800 Subject: [PATCH 01/16] fix: should support windows and Node.js 14 --- .github/workflows/nodejs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 27d4d854..b6e6ced8 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -14,5 +14,5 @@ jobs: name: Node.js uses: artusjs/github-actions/.github/workflows/node-test.yml@v1 with: - os: 'ubuntu-latest, macos-latest' - version: '16, 18' + os: 'ubuntu-latest, macos-latest, windows-latest' + version: '14, 16, 18' From 717b65a285c02f02b1925c419942238e68213a96 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 13:30:32 +0800 Subject: [PATCH 02/16] f --- scripts/start-cluster.js | 2 +- src/cmd/dev.ts | 3 ++- test/cmd/dev.test.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/start-cluster.js b/scripts/start-cluster.js index 279efc2b..aebbd761 100755 --- a/scripts/start-cluster.js +++ b/scripts/start-cluster.js @@ -1,6 +1,6 @@ const debug = require('util').debuglog('egg-bin:lib:start-cluster'); debug('argv: %o', process.argv); -const options = JSON.parse(process.argv[2]); +const options = JSON.parse(decodeURIComponent(process.argv[2])); debug('start cluster options: %o', options); require(options.framework).startCluster(options); diff --git a/src/cmd/dev.ts b/src/cmd/dev.ts index 4ca7f645..e56d635a 100644 --- a/src/cmd/dev.ts +++ b/src/cmd/dev.ts @@ -44,7 +44,8 @@ export class DevCommand extends BaseCommand { this.ctx.env.EGG_MASTER_CLOSE_TIMEOUT = '1000'; const serverBin = path.join(__dirname, '../../scripts/start-cluster.js'); const args = await this.formatEggStartArgs(); - const serverCmd = `${serverBin} '${JSON.stringify(args)}'`; + // add encodeURIComponent to support Windows cmd args + const serverCmd = `${serverBin} '${encodeURIComponent(JSON.stringify(args))}'`; const requires = await this.formatRequires(); debug('%o, requires: %o', serverCmd, requires); await this.runNodeCmd(serverCmd, requires); diff --git a/test/cmd/dev.test.ts b/test/cmd/dev.test.ts index c681ce3a..366229d8 100644 --- a/test/cmd/dev.test.ts +++ b/test/cmd/dev.test.ts @@ -3,7 +3,7 @@ import net from 'node:net'; import detect from 'detect-port'; import coffee from '../coffee'; -describe('test/cmd/dev.test.ts', () => { +describe.only('test/cmd/dev.test.ts', () => { const eggBin = path.join(__dirname, '../../src/bin/cli.ts'); const fixtures = path.join(__dirname, '../fixtures'); const cwd = path.join(fixtures, 'demo-app'); From 65ce465d06499a7223b3efa2757ba0285e04cb29 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 13:59:05 +0800 Subject: [PATCH 03/16] f --- test/cmd/dev.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cmd/dev.test.ts b/test/cmd/dev.test.ts index 366229d8..03609d57 100644 --- a/test/cmd/dev.test.ts +++ b/test/cmd/dev.test.ts @@ -10,7 +10,7 @@ describe.only('test/cmd/dev.test.ts', () => { it('should startCluster success', () => { return coffee.fork(eggBin, [ 'dev' ], { cwd }) - // .debug() + .debug() .expect('stdout', /"workers":1/) .expect('stdout', /"baseDir":".*?demo-app"/) .expect('stdout', /"framework":".*?aliyun-egg"/) @@ -21,7 +21,7 @@ describe.only('test/cmd/dev.test.ts', () => { it('should dev start with custom NODE_ENV', () => { return coffee.fork(eggBin, [ 'dev' ], { cwd, env: { NODE_ENV: 'prod' } }) - // .debug() + .debug() .expect('stdout', /"workers":1/) .expect('stdout', /"baseDir":".*?demo-app"/) .expect('stdout', /"framework":".*?aliyun-egg"/) From 4255e506c28638ff1c48d297f098f7dcdce84734 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 14:12:27 +0800 Subject: [PATCH 04/16] f --- scripts/start-cluster.js | 2 +- src/cmd/dev.ts | 3 +-- test/cmd/dev.test.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/start-cluster.js b/scripts/start-cluster.js index aebbd761..279efc2b 100755 --- a/scripts/start-cluster.js +++ b/scripts/start-cluster.js @@ -1,6 +1,6 @@ const debug = require('util').debuglog('egg-bin:lib:start-cluster'); debug('argv: %o', process.argv); -const options = JSON.parse(decodeURIComponent(process.argv[2])); +const options = JSON.parse(process.argv[2]); debug('start cluster options: %o', options); require(options.framework).startCluster(options); diff --git a/src/cmd/dev.ts b/src/cmd/dev.ts index e56d635a..4ca7f645 100644 --- a/src/cmd/dev.ts +++ b/src/cmd/dev.ts @@ -44,8 +44,7 @@ export class DevCommand extends BaseCommand { this.ctx.env.EGG_MASTER_CLOSE_TIMEOUT = '1000'; const serverBin = path.join(__dirname, '../../scripts/start-cluster.js'); const args = await this.formatEggStartArgs(); - // add encodeURIComponent to support Windows cmd args - const serverCmd = `${serverBin} '${encodeURIComponent(JSON.stringify(args))}'`; + const serverCmd = `${serverBin} '${JSON.stringify(args)}'`; const requires = await this.formatRequires(); debug('%o, requires: %o', serverCmd, requires); await this.runNodeCmd(serverCmd, requires); diff --git a/test/cmd/dev.test.ts b/test/cmd/dev.test.ts index 03609d57..cc4cfcc3 100644 --- a/test/cmd/dev.test.ts +++ b/test/cmd/dev.test.ts @@ -9,7 +9,7 @@ describe.only('test/cmd/dev.test.ts', () => { const cwd = path.join(fixtures, 'demo-app'); it('should startCluster success', () => { - return coffee.fork(eggBin, [ 'dev' ], { cwd }) + return coffee.fork(eggBin, [ 'dev' ], { cwd, env: { NODE_DEBUG: 'egg-bin*' } }) .debug() .expect('stdout', /"workers":1/) .expect('stdout', /"baseDir":".*?demo-app"/) From aa718876268f2e74221700408f9d69a29f073979 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 14:20:17 +0800 Subject: [PATCH 05/16] f --- scripts/start-cluster.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/start-cluster.js b/scripts/start-cluster.js index 279efc2b..1606decd 100755 --- a/scripts/start-cluster.js +++ b/scripts/start-cluster.js @@ -1,6 +1,11 @@ const debug = require('util').debuglog('egg-bin:lib:start-cluster'); debug('argv: %o', process.argv); -const options = JSON.parse(process.argv[2]); +let optionsJSONString = process.argv[2]; +if (process.platform === 'win32' && optionsJSONString.startsWith('\'')) { + // '{"baseDir":" => {"baseDir": + optionsJSONString = optionsJSONString.startsWith(1, optionsJSONString.length - 1); +} +const options = JSON.parse(optionsJSONString); debug('start cluster options: %o', options); require(options.framework).startCluster(options); From 82250a7580e6e7b9e4a564b14177c0401e6f8f92 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 15:29:50 +0800 Subject: [PATCH 06/16] f --- scripts/start-cluster.js | 7 +--- src/cmd/base.ts | 77 +++++++++++++++++++++++++++++++--------- src/cmd/cov.ts | 11 +++--- src/cmd/dev.ts | 14 +++++--- src/cmd/test.ts | 19 ++++------ 5 files changed, 83 insertions(+), 45 deletions(-) diff --git a/scripts/start-cluster.js b/scripts/start-cluster.js index 1606decd..279efc2b 100755 --- a/scripts/start-cluster.js +++ b/scripts/start-cluster.js @@ -1,11 +1,6 @@ const debug = require('util').debuglog('egg-bin:lib:start-cluster'); debug('argv: %o', process.argv); -let optionsJSONString = process.argv[2]; -if (process.platform === 'win32' && optionsJSONString.startsWith('\'')) { - // '{"baseDir":" => {"baseDir": - optionsJSONString = optionsJSONString.startsWith(1, optionsJSONString.length - 1); -} -const options = JSON.parse(optionsJSONString); +const options = JSON.parse(process.argv[2]); debug('start cluster options: %o', options); require(options.framework).startCluster(options); diff --git a/src/cmd/base.ts b/src/cmd/base.ts index 4e847c18..d1f00050 100644 --- a/src/cmd/base.ts +++ b/src/cmd/base.ts @@ -1,4 +1,5 @@ import { debuglog } from 'node:util'; +import { fork, ForkOptions, ChildProcess } from 'node:child_process'; import { DefineCommand, Options, Option, Command, @@ -6,10 +7,46 @@ import { Inject, Utils, } from '@artus-cli/artus-cli'; -import runscript from 'runscript'; const debug = debuglog('egg-bin:base'); +// only hook once and only when ever start any child. +const childs = new Set(); +let hadHook = false; +function gracefull(proc: ChildProcess) { + // save child ref + childs.add(proc); + + // only hook once + /* c8 ignore else */ + if (!hadHook) { + hadHook = true; + let signal: NodeJS.Signals; + [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ].forEach(event => { + process.once(event, () => { + signal = event as NodeJS.Signals; + process.exit(0); + }); + }); + + process.once('exit', (code: number) => { + // had test at my-helper.test.js, but coffee can't collect coverage info. + for (const child of childs) { + debug('process exit code: %o, kill child %o with %o', code, child.pid, signal); + child.kill(signal); + } + }); + } +} + +class ForkError extends Error { + code: number | null; + constructor(message: string, code: number | null) { + super(message); + this.code = code; + } +} + @DefineCommand() export abstract class BaseCommand extends Command { @Option({ @@ -59,26 +96,34 @@ export abstract class BaseCommand extends Command { return requires; } - protected async runNodeCmd(nodeCmd: string, nodeRequires?: string[]) { - const parts = [ - 'node', - ]; - if (nodeRequires) { - for (const r of nodeRequires) { - parts.push('--require'); - parts.push(`'${r}'`); - } - } - parts.push(nodeCmd); - const cmd = parts.join(' '); - debug('runscript: %o', cmd); + protected async forkNode(modulePath: string, args: string[], options: ForkOptions = {}) { if (this.dryRun) { - console.log('dry run: $ %o', cmd); + console.log('dry run: $ %o', `${process.execPath} ${modulePath} ${args.join(' ')}`); return; } - await runscript(cmd, { + + options = { + stdio: 'inherit', env: this.ctx.env, cwd: this.base, + ...options, + }; + const proc = fork(modulePath, args, options); + debug('Run fork pid: %o, `%s %s %s`', + proc.pid, process.execPath, modulePath, args.join(' ')); + gracefull(proc); + + return new Promise((resolve, reject) => { + proc.once('exit', code => { + debug('fork pid: %o exit code %o', proc.pid, code); + childs.delete(proc); + if (code !== 0) { + const err = new ForkError(modulePath + ' ' + args + ' exit with code ' + code, code); + reject(err); + } else { + resolve(); + } + }); }); } } diff --git a/src/cmd/cov.ts b/src/cmd/cov.ts index adcb42fb..089c205e 100644 --- a/src/cmd/cov.ts +++ b/src/cmd/cov.ts @@ -47,7 +47,7 @@ export class CovCommand extends TestCommand { ]; } - protected async runNodeCmd(nodeCmd: string) { + protected async forkNode(modulePath: string, args: string[]) { if (this.prerequire) { this.ctx.env.EGG_BIN_PREREQUIRE = 'true'; } @@ -60,7 +60,7 @@ export class CovCommand extends TestCommand { ]; if (this.args.typescript) { this.ctx.env.SPAWN_WRAP_SHIM_ROOT = path.join(this.base, 'node_modules'); - c8Args.push('--extension .ts'); + c8Args.push('--extension=.ts'); } const excludes = new Set([ @@ -69,15 +69,14 @@ export class CovCommand extends TestCommand { ...this.x, ]); for (const exclude of excludes) { - c8Args.push(`-x '${exclude}'`); + c8Args.push(`-x='${exclude}'`); } - const c8File = require.resolve('c8/bin/c8.js'); const outputDir = path.join(this.base, 'node_modules/.c8_output'); await fs.rm(outputDir, { force: true, recursive: true }); const coverageDir = path.join(this.base, 'coverage'); await fs.rm(coverageDir, { force: true, recursive: true }); - nodeCmd = `${c8File} ${c8Args.join(' ')} ${nodeCmd}`; - await super.runNodeCmd(nodeCmd); + + await super.forkNode(c8File, [ ...c8Args, modulePath, ...args ]); } } diff --git a/src/cmd/dev.ts b/src/cmd/dev.ts index 4ca7f645..cabee658 100644 --- a/src/cmd/dev.ts +++ b/src/cmd/dev.ts @@ -43,14 +43,18 @@ export class DevCommand extends BaseCommand { this.ctx.env.NODE_ENV = this.ctx.env.NODE_ENV ?? 'development'; this.ctx.env.EGG_MASTER_CLOSE_TIMEOUT = '1000'; const serverBin = path.join(__dirname, '../../scripts/start-cluster.js'); - const args = await this.formatEggStartArgs(); - const serverCmd = `${serverBin} '${JSON.stringify(args)}'`; + const eggStartOptions = await this.formatEggStartOptions(); + const args = [ JSON.stringify(eggStartOptions) ]; const requires = await this.formatRequires(); - debug('%o, requires: %o', serverCmd, requires); - await this.runNodeCmd(serverCmd, requires); + const execArgv: string[] = []; + for (const r of requires) { + execArgv.push('--require'); + execArgv.push(r); + } + await this.forkNode(serverBin, args, { execArgv }); } - protected async formatEggStartArgs() { + protected async formatEggStartOptions() { if (!this.port) { const defaultPort = process.env.EGG_BIN_DEFAULT_PORT ?? 7001; debug('detect available port'); diff --git a/src/cmd/test.ts b/src/cmd/test.ts index 23685b4b..dfe3c07c 100644 --- a/src/cmd/test.ts +++ b/src/cmd/test.ts @@ -107,12 +107,7 @@ export class TestCommand extends BaseCommand { const mochaArgs = await this.formatMochaArgs(); if (!mochaArgs) return; - - const mochaCmd = [ - mochaFile, - ...mochaArgs, - ].filter(argv => argv.trim()).join(' '); - await this.runNodeCmd(mochaCmd); + await this.forkNode(mochaFile, mochaArgs); } protected async formatMochaArgs() { @@ -186,14 +181,14 @@ export class TestCommand extends BaseCommand { // force exit '--exit', this.grep.map(pattern => `--grep='${pattern}'`).join(' '), - this.timeout === false ? '--no-timeout' : `--timeout ${this.timeout}`, + this.timeout === false ? '--no-timeout' : `--timeout=${this.timeout}`, this.parallel ? '--parallel' : '', - this.parallel && this.jobs ? `--jobs ${this.jobs}` : '', - reporter ? `--reporter ${reporter}` : '', - reporterOptions ? `--reporter-options ${reporterOptions}` : '', - ...requires.map(r => `--require ${r}`), + this.parallel && this.jobs ? `--jobs=${this.jobs}` : '', + reporter ? `--reporter=${reporter}` : '', + reporterOptions ? `--reporter-options=${reporterOptions}` : '', + ...requires.map(r => `--require=${r}`), ...files, - ]; + ].filter(a => a.trim()); } protected async getChangedTestFiles(dir: string, ext: string) { From 97f2d573e15067b50791979b6fa6eb2b1ded6a57 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 15:59:06 +0800 Subject: [PATCH 07/16] f --- test/cmd/dev.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/cmd/dev.test.ts b/test/cmd/dev.test.ts index cc4cfcc3..fbe54982 100644 --- a/test/cmd/dev.test.ts +++ b/test/cmd/dev.test.ts @@ -3,13 +3,16 @@ import net from 'node:net'; import detect from 'detect-port'; import coffee from '../coffee'; -describe.only('test/cmd/dev.test.ts', () => { +describe('test/cmd/dev.test.ts', () => { const eggBin = path.join(__dirname, '../../src/bin/cli.ts'); const fixtures = path.join(__dirname, '../fixtures'); const cwd = path.join(fixtures, 'demo-app'); it('should startCluster success', () => { - return coffee.fork(eggBin, [ 'dev' ], { cwd, env: { NODE_DEBUG: 'egg-bin*' } }) + return coffee.fork(eggBin, [ 'dev' ], { + cwd, + // env: { NODE_DEBUG: 'egg-bin*' }, + }) .debug() .expect('stdout', /"workers":1/) .expect('stdout', /"baseDir":".*?demo-app"/) From 8dd8bdf8f0abd49a7ad7e0f9306fba7527c79c01 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 16:00:33 +0800 Subject: [PATCH 08/16] f --- test/cmd/dev.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cmd/dev.test.ts b/test/cmd/dev.test.ts index fbe54982..da2318eb 100644 --- a/test/cmd/dev.test.ts +++ b/test/cmd/dev.test.ts @@ -13,7 +13,7 @@ describe('test/cmd/dev.test.ts', () => { cwd, // env: { NODE_DEBUG: 'egg-bin*' }, }) - .debug() + // .debug() .expect('stdout', /"workers":1/) .expect('stdout', /"baseDir":".*?demo-app"/) .expect('stdout', /"framework":".*?aliyun-egg"/) @@ -24,7 +24,7 @@ describe('test/cmd/dev.test.ts', () => { it('should dev start with custom NODE_ENV', () => { return coffee.fork(eggBin, [ 'dev' ], { cwd, env: { NODE_ENV: 'prod' } }) - .debug() + // .debug() .expect('stdout', /"workers":1/) .expect('stdout', /"baseDir":".*?demo-app"/) .expect('stdout', /"framework":".*?aliyun-egg"/) From 675646d8ba62b5b1604240e282c86b4ea8426d43 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 22:07:18 +0800 Subject: [PATCH 09/16] f --- src/cmd/base.ts | 3 +-- src/cmd/cov.ts | 8 +++++--- src/cmd/test.ts | 9 +++++++++ src/middleware/handle_error.ts | 30 ++++++++++++++++++++++++++++++ test/cmd/cov.test.ts | 8 +++----- test/cmd/test.test.ts | 13 ++++++++++++- 6 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 src/middleware/handle_error.ts diff --git a/src/cmd/base.ts b/src/cmd/base.ts index d1f00050..78b3bc9e 100644 --- a/src/cmd/base.ts +++ b/src/cmd/base.ts @@ -30,7 +30,6 @@ function gracefull(proc: ChildProcess) { }); process.once('exit', (code: number) => { - // had test at my-helper.test.js, but coffee can't collect coverage info. for (const child of childs) { debug('process exit code: %o, kill child %o with %o', code, child.pid, signal); child.kill(signal); @@ -118,7 +117,7 @@ export abstract class BaseCommand extends Command { debug('fork pid: %o exit code %o', proc.pid, code); childs.delete(proc); if (code !== 0) { - const err = new ForkError(modulePath + ' ' + args + ' exit with code ' + code, code); + const err = new ForkError(modulePath + ' ' + args.join(' ') + ' exit with code ' + code, code); reject(err); } else { resolve(); diff --git a/src/cmd/cov.ts b/src/cmd/cov.ts index 089c205e..afca135e 100644 --- a/src/cmd/cov.ts +++ b/src/cmd/cov.ts @@ -56,11 +56,12 @@ export class CovCommand extends TestCommand { // https://github.com/eggjs/egg/issues/3930 const c8Args = [ // '--show-process-tree', - this.c8, + ...this.c8.split(' ').filter(a => a.trim()), ]; if (this.args.typescript) { this.ctx.env.SPAWN_WRAP_SHIM_ROOT = path.join(this.base, 'node_modules'); - c8Args.push('--extension=.ts'); + c8Args.push('--extension'); + c8Args.push('.ts'); } const excludes = new Set([ @@ -69,7 +70,8 @@ export class CovCommand extends TestCommand { ...this.x, ]); for (const exclude of excludes) { - c8Args.push(`-x='${exclude}'`); + c8Args.push('-x'); + c8Args.push(`'${exclude}'`); } const c8File = require.resolve('c8/bin/c8.js'); const outputDir = path.join(this.base, 'node_modules/.c8_output'); diff --git a/src/cmd/test.ts b/src/cmd/test.ts index dfe3c07c..49f50eb8 100644 --- a/src/cmd/test.ts +++ b/src/cmd/test.ts @@ -79,6 +79,14 @@ export class TestCommand extends BaseCommand { }) mochawesome: boolean; + @Option({ + description: 'bbort ("bail") after first test failure', + alias: 'b', + type: 'boolean', + default: false, + }) + bail: boolean; + @Options() args: any; @@ -180,6 +188,7 @@ export class TestCommand extends BaseCommand { this.dryRun ? '--dry-run' : '', // force exit '--exit', + this.bail ? '--bail' : '', this.grep.map(pattern => `--grep='${pattern}'`).join(' '), this.timeout === false ? '--no-timeout' : `--timeout=${this.timeout}`, this.parallel ? '--parallel' : '', diff --git a/src/middleware/handle_error.ts b/src/middleware/handle_error.ts new file mode 100644 index 00000000..c34574cd --- /dev/null +++ b/src/middleware/handle_error.ts @@ -0,0 +1,30 @@ +import { debuglog } from 'node:util'; +import { + Inject, ApplicationLifecycle, LifecycleHook, LifecycleHookUnit, Program, + ArtusCliError, +} from '@artus-cli/artus-cli'; + +const debug = debuglog('egg-bin:midddleware:handle_error'); + +@LifecycleHookUnit() +export default class implements ApplicationLifecycle { + @Inject() + private readonly program: Program; + + @LifecycleHook() + async configDidLoad() { + this.program.use(async (_, next) => { + debug('enter next'); + try { + await next(); + debug('after next'); + } catch (err: any) { + debug('next error: %o', err); + // let artus cli to handle it + if (err instanceof ArtusCliError) throw err; + console.error(err); + process.exit(typeof err.code === 'number' ? err.code : 1); + } + }); + } +} diff --git a/test/cmd/cov.test.ts b/test/cmd/cov.test.ts index 5aa8778e..b75a414d 100644 --- a/test/cmd/cov.test.ts +++ b/test/cmd/cov.test.ts @@ -125,11 +125,9 @@ describe('test/cmd/cov.test.ts', () => { // .debug() .expect('stdout', /1\) should fail/) .expect('stdout', /1 failing/) - .end((err, { stdout, code }) => { - assert(err); - assert(stdout.match(/AssertionError/)); - assert(code === 1); - }); + .expect('stderr', /exit with code 1/) + .expect('code', 1) + .end(); }); it('should run cov when no test files', () => { diff --git a/test/cmd/test.test.ts b/test/cmd/test.test.ts index bea3c0f7..767a28d5 100644 --- a/test/cmd/test.test.ts +++ b/test/cmd/test.test.ts @@ -41,6 +41,17 @@ describe('test/cmd/test.test.ts', () => { .end(); }); + it('should success with --bail', () => { + return coffee.fork(eggBin, [ 'test', '--bail' ], { cwd }) + // .debug() + .expect('stdout', /should success/) + .expect('stdout', /a\.test\.js/) + .expect('stdout', /b\/b\.test\.js/) + .notExpect('stdout', /\ba\.js/) + .expect('code', 0) + .end(); + }); + it('should ignore node_modules and fixtures', () => { return coffee.fork(eggBin, [ 'test' ], { cwd: path.join(fixtures, 'test-files-glob') }) // .debug() @@ -149,7 +160,7 @@ describe('test/cmd/test.test.ts', () => { }) // .debug() .expect('stdout', /_mocha /) - .expect('stdout', / --timeout 12345 /) + .expect('stdout', / --timeout=12345 /) .expect('stdout', / --exit /) .expect('stdout', /foo\.test\.js/) .expect('stdout', /--dry-run/) From 0be1a94caf584b8a49a74fbc3139514bba6a0ecb Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 22:54:01 +0800 Subject: [PATCH 10/16] f --- package.json | 1 + test/ts.test.ts | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 87fb126e..d0fafa09 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@types/node": "^18.11.19", "assert-file": "^1.0.0", "coffee": "^5.4.0", + "cpy": "^8.1.2", "egg": "^3.9.1", "egg-mock": "^5.10.2", "esbuild": "^0.17.7", diff --git a/test/ts.test.ts b/test/ts.test.ts index fb27583a..ebc2882d 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -1,11 +1,16 @@ import assert from 'node:assert'; import path from 'node:path'; import fs from 'node:fs/promises'; +import _cpy from 'cpy'; import runscript from 'runscript'; import coffee from './coffee'; async function cpy(src: string, target: string) { - await fs.cp(src, target, { force: true, recursive: true }); + if (fs.cp) { + await fs.cp(src, target, { force: true, recursive: true }); + return; + } + await _cpy(src, target); } describe('test/ts.test.ts', () => { @@ -28,11 +33,9 @@ describe('test/ts.test.ts', () => { return coffee.fork(eggBin, [ 'test', '--typescript' ], { cwd, env: { NODE_ENV: 'development' } }) // .debug() .expect('stdout', /'egg from ts' == 'wrong assert ts'/) - .end((err, { stdout, code }) => { - assert(err); - assert(stdout.match(/AssertionError/)); - assert(code === 1); - }); + .expect('stdout', /AssertionError/) + .expect('code', 1) + .end(); }); describe('real application', () => { @@ -94,6 +97,7 @@ describe('test/ts.test.ts', () => { // .debug() .expect('stderr', /Error: throw error/) .expect('stderr', /at \w+ \(.+app\.ts:7:11\)/) + .expect('code', 1) .end(); }); @@ -104,6 +108,7 @@ describe('test/ts.test.ts', () => { .expect('stdout', /2 failing/) .expect('stdout', /test[\/\\]index\.test\.ts:\d+:\d+\)/) .expect('stdout', /AssertionError \[ERR_ASSERTION]: '111' == '222'/) + .expect('code', 1) .end(); }); @@ -114,6 +119,7 @@ describe('test/ts.test.ts', () => { .expect('stdout', /2 failing/) .expect('stdout', /test[\/\\]index\.test\.ts:\d+:\d+\)/) .expect('stdout', /AssertionError \[ERR_ASSERTION]: '111' == '222'/) + .expect('code', 1) .end(); }); @@ -124,6 +130,7 @@ describe('test/ts.test.ts', () => { .expect('stdout', /2 failing/) .expect('stdout', /test[\/\\]index\.test\.ts:\d+:\d+\)/) .expect('stdout', /AssertionError \[ERR_ASSERTION]: '111' == '222'/) + .expect('code', 1) .end(); }); @@ -140,11 +147,8 @@ describe('test/ts.test.ts', () => { .expect('stdout', /2 failing/) .expect('stdout', /test[\/\\]index\.test\.ts:\d+:\d+\)/) .expect('stdout', /AssertionError \[ERR_ASSERTION]: '111' == '222'/) - .end((err, { stdout, code }) => { - assert(err); - assert(stdout.match(/AssertionError/)); - assert(code === 1); - }); + .expect('code', 1) + .end(); }); it('should correct error stack line number in covering app', () => { From 779598479095678157cb73599a44580ce72a5638 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 22:58:31 +0800 Subject: [PATCH 11/16] f --- test/cmd/cov.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cmd/cov.test.ts b/test/cmd/cov.test.ts index b75a414d..9921da54 100644 --- a/test/cmd/cov.test.ts +++ b/test/cmd/cov.test.ts @@ -156,6 +156,7 @@ describe('test/cmd/cov.test.ts', () => { }); it('test parallel', () => { + if (process.platform === 'win32') return; return coffee.fork(eggBin, [ 'cov', '--parallel', '--ts=false' ], { cwd: path.join(fixtures, 'test-demo-app'), env: { TESTS: 'test/**/*.test.js' }, From 26ee473211aa677383180d131fda1727a9beaad6 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 23:24:52 +0800 Subject: [PATCH 12/16] f --- test/ts.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/ts.test.ts b/test/ts.test.ts index ebc2882d..1b3ab169 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -94,7 +94,7 @@ describe('test/ts.test.ts', () => { it('should correct error stack line number in starting app', () => { return coffee.fork(eggBin, [ 'dev' ], { cwd, env: { THROW_ERROR: 'true' } }) - // .debug() + .debug() .expect('stderr', /Error: throw error/) .expect('stderr', /at \w+ \(.+app\.ts:7:11\)/) .expect('code', 1) @@ -163,8 +163,7 @@ describe('test/ts.test.ts', () => { it('should correct error stack line number in mixed app', () => { const cwd = path.join(fixtures, 'example-ts-error-stack-mixed'); - const testFile = path.resolve(cwd, 'test/index.test.js'); - return coffee.fork(eggBin, [ 'test', testFile ], { cwd }) + return coffee.fork(eggBin, [ 'test', '--ts', 'false' ], { cwd }) // .debug() .expect('stdout', /error/) .expect('stdout', /2 failing/) From f03e27d2336066fb6c1f4ed17e7e7553a215114b Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 23:41:41 +0800 Subject: [PATCH 13/16] f --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index d0fafa09..8706e95e 100644 --- a/package.json +++ b/package.json @@ -75,8 +75,7 @@ "test-local-with-esbuild": "node -r esbuild-register src/bin/cli.ts test", "test-tsc": "npm run clean && npm run tsc && node dist/bin/cli.js && node dist/bin/cli.js test --base test/fixtures/example-ts && node dist/bin/cli.js dev --base test/fixtures/example-ts", "cov": "c8 -r lcov -r text-summary -x 'test/**' npm run test-local -- --timeout 120000", - "ci-test-only": "npm run test-local -- test/cmd/cov.test.ts", - "ci": "npm run lint && npm run cov && npm run test-tsc", + "ci": "npm run lint && npm run test-local && npm run test-tsc", "prepublishOnly": "npm run clean && npm run tsc", "tsc": "tsc", "clean": "rm -rf dist" From db468b34ef45f65be00810ae38189fd65d581592 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 23:42:37 +0800 Subject: [PATCH 14/16] f --- test/ts.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/ts.test.ts b/test/ts.test.ts index 1b3ab169..1fffa1e5 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -97,7 +97,6 @@ describe('test/ts.test.ts', () => { .debug() .expect('stderr', /Error: throw error/) .expect('stderr', /at \w+ \(.+app\.ts:7:11\)/) - .expect('code', 1) .end(); }); From b8192fc48f0442bdbbba9aeb697d9afeeaab3c5b Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 23:55:49 +0800 Subject: [PATCH 15/16] f --- test/ts.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/ts.test.ts b/test/ts.test.ts index 1fffa1e5..aa38cdd8 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -219,6 +219,7 @@ describe('test/ts.test.ts', () => { }); it('should load custom ts compiler', async () => { + if (process.platform === 'win32') return; const cwd = path.join(fixtures, 'example-ts-custom-compiler'); // install custom ts-node @@ -249,6 +250,7 @@ describe('test/ts.test.ts', () => { }); it('should load custom ts compiler with tscompiler args', async () => { + if (process.platform === 'win32') return; const cwd = path.join(fixtures, 'example-ts-custom-compiler-2'); // install custom ts-node From 9a3c1df465f7c4aebf4f4c70333c6bcf9dfa844b Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 16 Feb 2023 23:57:49 +0800 Subject: [PATCH 16/16] f --- package.json | 1 + test/ts.test.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 8706e95e..63eb9add 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "eslint": "^8.16.0", "eslint-config-egg": "^12.0.0", "git-contributor": "2", + "npminstall": "^7.5.0", "typescript": "^4.9.5" }, "repository": { diff --git a/test/ts.test.ts b/test/ts.test.ts index aa38cdd8..2cdfc6a5 100644 --- a/test/ts.test.ts +++ b/test/ts.test.ts @@ -228,7 +228,7 @@ describe('test/ts.test.ts', () => { // dont use npmmirror.com on CI await runscript('npx npminstall', { cwd }); } else { - await runscript('npx cnpm install', { cwd }); + await runscript('npx npminstall -c', { cwd }); } // copy egg to node_modules @@ -259,7 +259,7 @@ describe('test/ts.test.ts', () => { // dont use npmmirror.com on CI await runscript('npx npminstall ts-node@10.9.0 --no-save', { cwd }); } else { - await runscript('npx cnpm install ts-node@10.9.0 --no-save', { cwd }); + await runscript('npx npminstall -c ts-node@10.9.0 --no-save', { cwd }); } // copy egg to node_modules @@ -291,7 +291,7 @@ describe('test/ts.test.ts', () => { // dont use npmmirror.com on CI await runscript('npx npminstall ts-node@10.9.0 --no-save', { cwd }); } else { - await runscript('npx cnpm install ts-node@10.9.0 --no-save', { cwd }); + await runscript('npx npminstall -c ts-node@10.9.0 --no-save', { cwd }); } // copy egg to node_modules @@ -388,7 +388,7 @@ describe('test/ts.test.ts', () => { // dont use npmmirror.com on CI await runscript('npx npminstall', { cwd }); } else { - await runscript('npx cnpm install', { cwd }); + await runscript('npx npminstall -c', { cwd }); } // copy egg to node_modules