Skip to content

Commit

Permalink
refactor cov
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Dec 26, 2024
1 parent 07d15fb commit 7255dbd
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 43 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@
"topicSeparator": " ",
"hooks": {
"init": "./dist/esm/hooks/init/options"
}
},
"additionalHelpFlags": [
"-h"
]
}
}
21 changes: 17 additions & 4 deletions src/baseCommand.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { debuglog } from 'node:util';
// import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { fork, ForkOptions, ChildProcess } from 'node:child_process';
import { Command, Flags, Interfaces } from '@oclif/core';
Expand Down Expand Up @@ -92,13 +91,18 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {
helpGroup: 'GLOBAL',
summary: 'TypeScript compiler, like ts-node/register',
}),
// flag with no value (--ts, --typescript)
// flag with no value (--typescript)
typescript: Flags.boolean({
helpGroup: 'GLOBAL',
description: '[default: true] use TypeScript to run the test',
aliases: [ 'ts' ],
allowNo: true,
}),
ts: Flags.string({
helpGroup: 'GLOBAL',
description: 'shortcut for --typescript, e.g.: --ts=false',
options: [ 'true', 'false' ],
}),
javascript: Flags.boolean({
helpGroup: 'GLOBAL',
description: 'use JavaScript to run the test',
Expand Down Expand Up @@ -131,6 +135,7 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {

public async init(): Promise<void> {
await super.init();
debug('raw args: %o', this.argv);
const { args, flags } = await this.parse({
flags: this.ctor.flags,
baseFlags: (super.ctor as typeof BaseCommand).baseFlags,
Expand All @@ -155,7 +160,15 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {
this.pkg = pkg;
this.pkgEgg = pkg.egg ?? {};
flags.tscompiler = flags.tscompiler ?? this.env.TS_COMPILER ?? this.pkgEgg.tscompiler;
let typescript = args.typescript;

let typescript: boolean = args.typescript;
// keep compatible with old ts flag: `--ts=true` or `--ts=false`
if (flags.ts === 'true') {
typescript = true;
} else if (flags.ts === 'false') {
typescript = false;
}

if (typescript === undefined) {
// try to ready EGG_TYPESCRIPT env first, only accept 'true' or 'false' string
if (this.env.EGG_TYPESCRIPT === 'false') {
Expand Down Expand Up @@ -336,7 +349,7 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {
proc.pid,
NODE_OPTIONS,
process.execPath,
modulePath, forkArgs.map(a => `${a}`).join(' '));
modulePath, forkArgs.map(a => `'${a}'`).join(' '));
graceful(proc);

return new Promise<void>((resolve, reject) => {
Expand Down
104 changes: 87 additions & 17 deletions src/commands/cov.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,100 @@
import { Args, Command, Flags } from '@oclif/core';
import path from 'node:path';
import fs from 'node:fs/promises';
import { Flags } from '@oclif/core';
import Test from './test.js';
import { importResolve } from '@eggjs/utils';
import { ForkNodeOptions } from '../baseCommand.js';

export default class Cov extends Command {
static override args = {
file: Args.string({ description: 'file to read' }),
};

static override description = 'describe the command here';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
export default class Cov<T extends typeof Cov> extends Test<T> {
static override description = 'Run the test with coverage';

static override examples = [
'<%= config.bin %> <%= command.id %>',
'<%= config.bin %> <%= command.id %> test/index.test.ts',
];

static override flags = {
// flag with no value (-f, --force)
force: Flags.boolean({ char: 'f' }),
// flag with a value (-n, --name=VALUE)
name: Flags.string({ char: 'n', description: 'name to print' }),
...Test.flags,
// will use on egg-mock https://github.com/eggjs/egg-mock/blob/84a64bd19d0569ec94664c898fb1b28367b95d60/index.js#L7
prerequire: Flags.boolean({
description: 'prerequire files for coverage instrument',
}),
exclude: Flags.string({
description: 'coverage ignore, one or more files patterns`',
multiple: true,
char: 'x',
}),
c8: Flags.string({
description: 'c8 instruments passthrough`',
default: '--temp-directory node_modules/.c8_output -r text-summary -r json-summary -r json -r lcov -r cobertura',
}),
};

public async run(): Promise<void> {
const { args, flags } = await this.parse(Cov);
protected get defaultExcludes() {
return [
'example/',
'examples/',
'mocks**/',
'docs/',
// https://github.com/JaKXz/test-exclude/blob/620a7be412d4fc2070d50f0f63e3228314066fc9/index.js#L73
'test/**',
'test{,-*}.js',
'**/*.test.js',
'**/__tests__/**',
'**/node_modules/**',
'typings',
'**/*.d.ts',
];
}

protected override async forkNode(modulePath: string, forkArgs: string[], options: ForkNodeOptions = {}) {
const { flags } = this;
if (flags.prerequire) {
this.env.EGG_BIN_PREREQUIRE = 'true';
}

const name = flags.name ?? 'world';
this.log(`hello ${name} from /Users/fengmk2/git/github.com/eggjs/bin/src/commands/cov.ts`);
if (args.file && flags.force) {
this.log(`you input --force and --file: ${args.file}`);
// add c8 args
// https://github.com/eggjs/egg/issues/3930
const c8Args = [
// '--show-process-tree',
...flags.c8.split(' ').filter(a => a.trim()),
];
if (flags.typescript) {
this.env.SPAWN_WRAP_SHIM_ROOT = path.join(flags.base, 'node_modules');
c8Args.push('--extension');
c8Args.push('.ts');
}

const excludes = new Set([
...process.env.COV_EXCLUDES?.split(',') ?? [],
...this.defaultExcludes,
...Array.from(flags.exclude ?? []),
]);
for (const exclude of excludes) {
c8Args.push('-x');
c8Args.push(exclude);
}
const c8File = importResolve('c8/bin/c8.js');
const outputDir = path.join(flags.base, 'node_modules/.c8_output');
await fs.rm(outputDir, { force: true, recursive: true });
const coverageDir = path.join(flags.base, 'coverage');
await fs.rm(coverageDir, { force: true, recursive: true });

const execArgv = [
...this.globalExecArgv,
...options.execArgv || [],
];
this.globalExecArgv = [];

// $ c8 node mocha
await super.forkNode(c8File, [
...c8Args,
process.execPath,
...execArgv,
modulePath,
...forkArgs,
]);
}
}
10 changes: 7 additions & 3 deletions src/commands/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { BaseCommand } from '../baseCommand.js';

const debug = debuglog('@eggjs/bin/commands/test');

export default class Test extends BaseCommand<typeof Test> {
export default class Test<T extends typeof Test> extends BaseCommand<T> {
static override args = {
file: Args.string({
description: 'file(s) to test',
Expand Down Expand Up @@ -93,6 +93,10 @@ export default class Test extends BaseCommand<typeof Test> {

const mochaArgs = await this.formatMochaArgs();
if (!mochaArgs) return;
await this.runMocha(mochaFile, mochaArgs);
}

protected async runMocha(mochaFile: string, mochaArgs: string[]) {
await this.forkNode(mochaFile, mochaArgs, {
execArgv: [
...process.execArgv,
Expand Down Expand Up @@ -156,7 +160,7 @@ export default class Test extends BaseCommand<typeof Test> {
files.sort();

if (files.length === 0) {
console.log(`No test files found with ${pattern}`);
console.log('No test files found with pattern %o', pattern);
return;
}

Expand All @@ -172,7 +176,6 @@ export default class Test extends BaseCommand<typeof Test> {
const grep = flags.grep ? flags.grep.split(',') : [];

return [
flags['dry-run'] ? '--dry-run' : '',
// force exit
'--exit',
flags.bail ? '--bail' : '',
Expand All @@ -184,6 +187,7 @@ export default class Test extends BaseCommand<typeof Test> {
reporterOptions ? `--reporter-options=${reporterOptions}` : '',
...requires.map(r => `--require=${r}`),
...files,
flags['dry-run'] ? '--dry-run' : '',
].filter(a => a.trim());
}
}
4 changes: 3 additions & 1 deletion src/hooks/init/options.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// import { Hook } from '@oclif/core';

// const hook: Hook<'init'> = async function(opts) {
// process.stdout.write(`example hook running ${opts.id}\n`);
// if (opts.argv.includes('-h')) {
// this.config.runCommand('help');
// }
// };

// export default hook;
23 changes: 19 additions & 4 deletions test/cmd/cov.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,22 @@ describe('test/cmd/cov.test.ts', () => {
}

describe('egg-bin cov', () => {
it('should success on js', async () => {
it('should success on js with --javascript', async () => {
await coffee.fork(eggBin, [ 'cov', '--javascript' ], { cwd, env: { TESTS: 'test/**/*.test.js' } })
// .debug()
.expect('stdout', /should success/)
.expect('stdout', /a\.test\.js/)
.expect('stdout', /b[\/|\\]b\.test\.js/)
.notExpect('stdout', /\ba\.js/)
.expect('stdout', /Statements {3}:/)
.expect('code', 0)
.end();
assertCoverage(cwd);
const lcov = await fs.readFile(path.join(cwd, 'coverage/lcov.info'), 'utf8');
assert.match(lcov, /ignore[\/|\\]a.js/);
});

it('should success on js with --ts=false', async () => {
await coffee.fork(eggBin, [ 'cov', '--ts=false' ], { cwd, env: { TESTS: 'test/**/*.test.js' } })
// .debug()
.expect('stdout', /should success/)
Expand Down Expand Up @@ -162,7 +177,7 @@ describe('test/cmd/cov.test.ts', () => {
.end();
});

it('test parallel', () => {
it.skip('test parallel', () => {
if (process.platform === 'win32') return;
return coffee.fork(eggBin, [ 'cov', '--parallel', '--ts=false' ], {
cwd: getFixtures('test-demo-app'),
Expand All @@ -180,7 +195,7 @@ describe('test/cmd/cov.test.ts', () => {
return coffee.fork(eggBin, [ 'cov' ], {
cwd,
})
.debug()
// .debug()
.expect('stdout', /should work/)
.expect('stdout', /2 passing/)
.expect('code', 0)
Expand All @@ -193,7 +208,7 @@ describe('test/cmd/cov.test.ts', () => {
return coffee.fork(eggBin, [ 'cov' ], {
cwd: getFixtures('egg-revert'),
})
.debug()
// .debug()
.expect('stdout', /SECURITY WARNING: Reverting CVE-2023-46809: Marvin attack on PKCS#1 padding/)
.expect('stdout', /1 passing/)
.expect('code', 0)
Expand Down
22 changes: 9 additions & 13 deletions test/egg-bin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('test/egg-bin.test.ts', () => {
describe('global options', () => {
it('should show version', () => {
return coffee.fork(eggBin, [ '--version' ], { cwd })
.debug()
// .debug()
.expect('stdout', /\d+\.\d+\.\d+/)
.expect('code', 0)
.end();
Expand All @@ -18,39 +18,35 @@ describe('test/egg-bin.test.ts', () => {
it('should main redirect to help', () => {
return coffee.fork(eggBin, [], { cwd })
// .debug()
.expect('stdout', /Usage: egg-bin/)
.expect('stdout', /Available Commands/)
.expect('stdout', /test \[files\.\.\.]\s+Run the test/)
.expect('stdout', /-ts, --typescript\s+whether enable typescript support/)
.expect('stdout', /USAGE/)
.expect('stdout', /\$ egg-bin \[COMMAND]/)
.expect('code', 0)
.end();
});

it('should show help', () => {
return coffee.fork(eggBin, [ '--help' ], { cwd })
// .debug()
.expect('stdout', /Usage: egg-bin/)
.expect('stdout', /Available Commands/)
.expect('stdout', /test \[files\.\.\.]\s+Run the test/)
.expect('stdout', /-ts, --typescript\s+whether enable typescript support/)
.expect('stdout', /USAGE/)
.expect('stdout', /\$ egg-bin \[COMMAND]/)
.expect('code', 0)
.end();
});

it('should show egg-bin test help', () => {
return coffee.fork(eggBin, [ 'test', '-h', '--base', cwd ])
// .debug()
.expect('stdout', /Usage: egg-bin test \[files\.\.\.]/)
.expect('stdout', /-ts, --typescript\s+whether enable typescript support/)
.expect('stdout', /Run the test/)
.expect('stdout', /--\[no-]typescript {5}\[default: true] use TypeScript to run the test/)
.expect('code', 0)
.end();
});

it('should show help when command not exists', () => {
return coffee.fork(eggBin, [ 'not-exists' ], { cwd })
// .debug()
.expect('stderr', /Command is not found: 'egg-bin not-exists', try 'egg-bin --help' for more information/)
.expect('code', 1)
.expect('stderr', /command not-exists not found/)
.expect('code', 2)
.end();
});
});
Expand Down

0 comments on commit 7255dbd

Please sign in to comment.