@eggjs/bin 8.0.0-beta.36 → 8.0.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -108,18 +108,18 @@ Create `.vscode/launch.json` file:
108
108
 
109
109
  ### test
110
110
 
111
- Using [mocha] to run test.
111
+ Using [vitest] to run test.
112
112
 
113
113
  ```bash
114
114
  egg-bin test [...files] [options]
115
115
  ```
116
116
 
117
117
  - `files` is optional, default to `test/**/*.test.ts`
118
- - `test/fixtures`, `test/node_modules` is always exclude.
118
+ - `test/fixtures`, `test/node_modules` is always excluded.
119
119
 
120
- #### auto require `test/.setup.ts`
120
+ #### auto load `test/.setup.ts`
121
121
 
122
- If `test/.setup.ts` file exists, it will be auto require as the first test file.
122
+ If `test/.setup.ts` (or `.setup.js`) exists, it will be auto-added as the first vitest `setupFile`.
123
123
 
124
124
  ```bash
125
125
  test
@@ -127,33 +127,38 @@ test
127
127
  └── foo.test.ts
128
128
  ```
129
129
 
130
- #### test options
130
+ #### auto-inject `@eggjs/mock/setup_vitest`
131
131
 
132
- You can pass any mocha argv.
132
+ For egg applications, `@eggjs/mock/setup_vitest` is automatically registered as a vitest setup file when `@eggjs/mock` is installed, handling app lifecycle (`beforeAll` / `afterEach` / `afterAll`).
133
133
 
134
- - `--timeout` milliseconds, default to 60000
135
- - `--changed` / `-c` only test changed test files(test files means files that match `${pwd}/test/**/*.test.(js|ts)`)
136
- - `--parallel` enable mocha parallel mode, default to `false`.
137
- - `--auto-agent` auto start agent in mocha master agent.
138
- - `--jobs` number of jobs to run in parallel, default to `os.cpus().length - 1`.
134
+ #### auto use `@eggjs/tegg-vitest/runner`
139
135
 
140
- #### test environment
136
+ If `@eggjs/tegg-vitest` is installed in the project, its runner is automatically detected and injected into the vitest config.
141
137
 
142
- Environment is also support, will use it if options not provide.
138
+ #### test options
143
139
 
144
- You can set `TESTS` env to set the tests directory, it support [glob] grammar.
140
+ - `--timeout` / `-t` milliseconds, default to `60000`
141
+ - `--no-timeout` disable timeout
142
+ - `--grep` / `-g` only run tests matching pattern
143
+ - `--bail` / `-b` stop after first test failure
144
+ - `--changed` / `-c` only run tests for changed files (matches `test/**/*.test.(js|ts)`)
145
+ - `--watch` / `-w` run in watch mode
146
+
147
+ #### test environment
148
+
149
+ You can set `TESTS` env to specify test files, supports comma-separated glob patterns.
145
150
 
146
151
  ```bash
147
152
  TESTS=test/a.test.ts egg-bin test
148
153
  ```
149
154
 
150
- And the reporter can set by the `TEST_REPORTER` env, default is `spec`.
155
+ The reporter can be set with `TEST_REPORTER` env (any vitest reporter), default is `default`.
151
156
 
152
157
  ```bash
153
- TEST_REPORTER=doc egg-bin test
158
+ TEST_REPORTER=verbose egg-bin test
154
159
  ```
155
160
 
156
- The test timeout can set by `TEST_TIMEOUT` env, default is `60000` ms.
161
+ The test timeout can be set with `TEST_TIMEOUT` env, default is `60000` ms.
157
162
 
158
163
  ```bash
159
164
  TEST_TIMEOUT=2000 egg-bin test
@@ -161,30 +166,56 @@ TEST_TIMEOUT=2000 egg-bin test
161
166
 
162
167
  ### cov
163
168
 
164
- Using [mocha] and [c8] to run code coverage, it support all test params above.
169
+ Using [vitest] with [v8 coverage] to run code coverage. Supports all `test` options above.
165
170
 
166
- Coverage reporter will output text-summary, json and lcov.
171
+ Coverage reports are written to `coverage/` and include: `text-summary`, `json-summary`, `json`, `lcov`, `cobertura`.
167
172
 
168
173
  #### cov options
169
174
 
170
- You can pass any mocha argv.
171
-
172
- - `-x` add dir ignore coverage, support multiple argv
173
- - `--prerequire` prerequire files for coverage instrument, you can use this options if load files slowly when call `mm.app` or `mm.cluster`
174
- - `--typescript` enable typescript support. If `true`, will auto add `.ts` extension and ignore `typings` and `d.ts`.
175
- - `--c8` c8 instruments passthrough. you can use this to overwrite egg-bin's default c8 instruments and add additional ones.
176
- > - egg-bin have some default instruments passed to c8 like `-r` and `--temp-directory`
177
- > - `egg-bin cov --c8="-r teamcity -r text" --c8-report=true`
178
- - also support all test params above.
175
+ - `-x` add a glob pattern to exclude from coverage, supports multiple
176
+ - also supports all test options above.
179
177
 
180
178
  #### cov environment
181
179
 
182
- You can set `COV_EXCLUDES` env to add dir ignore coverage.
180
+ You can set `COV_EXCLUDES` env to add glob patterns to exclude from coverage (comma-separated).
183
181
 
184
182
  ```bash
185
183
  COV_EXCLUDES="app/plugins/c*,app/autocreate/**" egg-bin cov
186
184
  ```
187
185
 
186
+ ## Breaking Changes (v8)
187
+
188
+ ### Migrated from Mocha to Vitest
189
+
190
+ The `test` and `cov` commands now use [vitest] instead of [Mocha](https://mochajs.org). This brings native TypeScript support, faster execution, and built-in watch mode, but removes some Mocha-specific options:
191
+
192
+ **Removed flags:**
193
+
194
+ | Old flag | Reason |
195
+ | ------------------- | --------------------------------------------------------------- |
196
+ | `--parallel` / `-p` | Vitest handles parallelism natively via worker pools |
197
+ | `--jobs` / `-j` | Replaced by vitest's built-in pool configuration |
198
+ | `--auto-agent` | Mocha-specific, no equivalent needed in vitest |
199
+ | `--prerequire` | Use `test/.setup.ts` setupFile instead |
200
+ | `--c8` | Coverage is now configured inside vitest, use `-x` for excludes |
201
+
202
+ **Removed environment variables:**
203
+
204
+ | Old env var | Reason |
205
+ | ------------ | ---------------------------------------------- |
206
+ | `MOCHA_FILE` | Mocha-specific, vitest runner is auto-detected |
207
+
208
+ **Changed output format:**
209
+
210
+ Test output now follows vitest's format. Assertions in test scripts that match mocha output (e.g. `"N passing"`) should be updated to vitest output (e.g. `"N passed"`).
211
+
212
+ **Migration guide:**
213
+
214
+ 1. Replace `before()` / `after()` hooks with `beforeAll()` / `afterAll()` (vitest naming)
215
+ 2. Import vitest globals explicitly in `.ts` setup files: `import { beforeAll, afterEach } from 'vitest'`
216
+ 3. Plain `.js` test files can use globals directly (vitest `globals: true` is enabled by default)
217
+ 4. Remove `--parallel` / `--jobs` flags from your npm scripts
218
+
188
219
  ## Custom egg-bin for your team
189
220
 
190
221
  See <https://oclif.io/docs/configuring_your_cli/>
@@ -199,5 +230,5 @@ See <https://oclif.io/docs/configuring_your_cli/>
199
230
 
200
231
  Made with [contributors-img](https://contrib.rocks).
201
232
 
202
- [mocha]: https://mochajs.org
203
- [glob]: https://github.com/isaacs/node-glob
233
+ [vitest]: https://vitest.dev
234
+ [v8 coverage]: https://vitest.dev/guide/coverage
@@ -1,5 +1,5 @@
1
- import { ForkNodeOptions } from "../baseCommand.js";
2
1
  import Test from "./test.js";
2
+ import { InlineConfig } from "vitest/node";
3
3
  import * as _oclif_core_interfaces6 from "@oclif/core/interfaces";
4
4
 
5
5
  //#region src/commands/cov.d.ts
@@ -7,20 +7,24 @@ declare class Cov<T extends typeof Cov> extends Test<T> {
7
7
  static description: string;
8
8
  static examples: string[];
9
9
  static flags: {
10
- prerequire: _oclif_core_interfaces6.BooleanFlag<boolean>;
11
10
  exclude: _oclif_core_interfaces6.OptionFlag<string[] | undefined, _oclif_core_interfaces6.CustomOptions>;
12
- c8: _oclif_core_interfaces6.OptionFlag<string, _oclif_core_interfaces6.CustomOptions>;
13
11
  bail: _oclif_core_interfaces6.BooleanFlag<boolean>;
14
12
  timeout: _oclif_core_interfaces6.OptionFlag<number, _oclif_core_interfaces6.CustomOptions>;
15
13
  'no-timeout': _oclif_core_interfaces6.BooleanFlag<boolean>;
16
14
  grep: _oclif_core_interfaces6.OptionFlag<string | undefined, _oclif_core_interfaces6.CustomOptions>;
17
15
  changed: _oclif_core_interfaces6.BooleanFlag<boolean>;
18
- parallel: _oclif_core_interfaces6.BooleanFlag<boolean>;
19
- jobs: _oclif_core_interfaces6.OptionFlag<number, _oclif_core_interfaces6.CustomOptions>;
20
- 'auto-agent': _oclif_core_interfaces6.BooleanFlag<boolean>;
16
+ watch: _oclif_core_interfaces6.BooleanFlag<boolean>;
21
17
  };
22
- protected get defaultExcludes(): string[];
23
- protected forkNode(modulePath: string, forkArgs: string[], options?: ForkNodeOptions): Promise<void>;
18
+ protected get defaultCoverageExcludes(): string[];
19
+ /**
20
+ * Convert a relative exclude pattern to an absolute path pattern.
21
+ * This prevents vitest's picomatch (with contains:true) from matching
22
+ * files in parent directories that happen to share path segments.
23
+ * e.g. 'test/**' should only exclude the project's own test/ dir,
24
+ * not files whose absolute path contains 'test/' from parent dirs.
25
+ */
26
+ protected toAbsoluteExclude(pat: string, base: string): string;
27
+ protected buildVitestConfig(files: string[]): Promise<InlineConfig>;
24
28
  }
25
29
  //#endregion
26
30
  export { Cov as default };
@@ -1,9 +1,6 @@
1
- import "../baseCommand.js";
2
1
  import Test from "./test.js";
3
2
  import path from "node:path";
4
- import { importResolve } from "@eggjs/utils";
5
3
  import { Flags } from "@oclif/core";
6
- import fs from "node:fs/promises";
7
4
 
8
5
  //#region src/commands/cov.ts
9
6
  var Cov = class extends Test {
@@ -15,22 +12,17 @@ var Cov = class extends Test {
15
12
  ];
16
13
  static flags = {
17
14
  ...Test.flags,
18
- prerequire: Flags.boolean({ description: "prerequire files for coverage instrument" }),
19
15
  exclude: Flags.string({
20
- description: "coverage ignore, one or more files patterns`",
16
+ description: "coverage ignore, one or more files patterns",
21
17
  multiple: true,
22
18
  char: "x"
23
- }),
24
- c8: Flags.string({
25
- description: "c8 instruments passthrough`",
26
- default: "--temp-directory node_modules/.c8_output -r text-summary -r json-summary -r json -r lcov -r cobertura"
27
19
  })
28
20
  };
29
- get defaultExcludes() {
21
+ get defaultCoverageExcludes() {
30
22
  return [
31
23
  "example/",
32
24
  "examples/",
33
- "mocks**/",
25
+ "**/mocks*/**",
34
26
  "docs/",
35
27
  "test/**",
36
28
  "test{,-*}.js",
@@ -41,44 +33,48 @@ var Cov = class extends Test {
41
33
  "**/*.d.ts"
42
34
  ];
43
35
  }
44
- async forkNode(modulePath, forkArgs, options = {}) {
45
- const { flags } = this;
46
- if (flags.prerequire) this.env.EGG_BIN_PREREQUIRE = "true";
47
- const c8Args = flags.c8.split(" ").filter((a) => a.trim());
48
- if (flags.typescript) {
49
- this.env.SPAWN_WRAP_SHIM_ROOT = path.join(flags.base, "node_modules");
50
- c8Args.push("--extension");
51
- c8Args.push(".ts");
52
- }
53
- const excludes = new Set([
54
- ...process.env.COV_EXCLUDES?.split(",") ?? [],
55
- ...this.defaultExcludes,
56
- ...Array.from(flags.exclude ?? [])
57
- ]);
58
- for (const exclude of excludes) {
59
- c8Args.push("-x");
60
- c8Args.push(exclude);
36
+ /**
37
+ * Convert a relative exclude pattern to an absolute path pattern.
38
+ * This prevents vitest's picomatch (with contains:true) from matching
39
+ * files in parent directories that happen to share path segments.
40
+ * e.g. 'test/**' should only exclude the project's own test/ dir,
41
+ * not files whose absolute path contains 'test/' from parent dirs.
42
+ */
43
+ toAbsoluteExclude(pat, base) {
44
+ const isNegated = pat.startsWith("!");
45
+ const rawPattern = isNegated ? pat.slice(1) : pat;
46
+ if (path.isAbsolute(rawPattern) || rawPattern.startsWith("**")) {
47
+ const normalized = rawPattern.replace(/\\/g, "/");
48
+ return isNegated ? `!${normalized}` : normalized;
61
49
  }
62
- const c8File = importResolve("c8/bin/c8.js");
63
- const outputDir = path.join(flags.base, "node_modules/.c8_output");
64
- await fs.rm(outputDir, {
65
- force: true,
66
- recursive: true
67
- });
68
- const coverageDir = path.join(flags.base, "coverage");
69
- await fs.rm(coverageDir, {
70
- force: true,
71
- recursive: true
72
- });
73
- const execArgv = [...this.globalExecArgv, ...options.execArgv || []];
74
- this.globalExecArgv = [];
75
- await super.forkNode(c8File, [
76
- ...c8Args,
77
- process.execPath,
78
- ...execArgv,
79
- modulePath,
80
- ...forkArgs
50
+ const joined = path.join(base, rawPattern).replace(/\\/g, "/");
51
+ return isNegated ? `!${joined}` : joined;
52
+ }
53
+ async buildVitestConfig(files) {
54
+ const { flags } = this;
55
+ const baseConfig = await super.buildVitestConfig(files);
56
+ const base = flags.base.replace(/\\/g, "/");
57
+ const coverageExcludes = new Set([
58
+ ...(process.env.COV_EXCLUDES?.split(",") ?? []).map((p) => this.toAbsoluteExclude(p, base)),
59
+ ...this.defaultCoverageExcludes.map((p) => this.toAbsoluteExclude(p, base)),
60
+ ...Array.from(flags.exclude ?? []).map((p) => this.toAbsoluteExclude(p, base))
81
61
  ]);
62
+ return {
63
+ ...baseConfig,
64
+ coverage: {
65
+ enabled: true,
66
+ provider: "v8",
67
+ reporter: [
68
+ "text-summary",
69
+ "json-summary",
70
+ "json",
71
+ "lcov",
72
+ "cobertura"
73
+ ],
74
+ exclude: Array.from(coverageExcludes),
75
+ reportsDirectory: path.join(base, "coverage")
76
+ }
77
+ };
82
78
  }
83
79
  };
84
80
 
@@ -1,26 +1,24 @@
1
1
  import { BaseCommand } from "../baseCommand.js";
2
- import * as _oclif_core_interfaces22 from "@oclif/core/interfaces";
2
+ import { InlineConfig } from "vitest/node";
3
+ import * as _oclif_core_interfaces16 from "@oclif/core/interfaces";
3
4
 
4
5
  //#region src/commands/test.d.ts
5
6
  declare class Test<T extends typeof Test> extends BaseCommand<T> {
6
7
  static args: {
7
- file: _oclif_core_interfaces22.Arg<string | undefined, Record<string, unknown>>;
8
+ file: _oclif_core_interfaces16.Arg<string | undefined, Record<string, unknown>>;
8
9
  };
9
10
  static description: string;
10
11
  static examples: string[];
11
12
  static flags: {
12
- bail: _oclif_core_interfaces22.BooleanFlag<boolean>;
13
- timeout: _oclif_core_interfaces22.OptionFlag<number, _oclif_core_interfaces22.CustomOptions>;
14
- 'no-timeout': _oclif_core_interfaces22.BooleanFlag<boolean>;
15
- grep: _oclif_core_interfaces22.OptionFlag<string | undefined, _oclif_core_interfaces22.CustomOptions>;
16
- changed: _oclif_core_interfaces22.BooleanFlag<boolean>;
17
- parallel: _oclif_core_interfaces22.BooleanFlag<boolean>;
18
- jobs: _oclif_core_interfaces22.OptionFlag<number, _oclif_core_interfaces22.CustomOptions>;
19
- 'auto-agent': _oclif_core_interfaces22.BooleanFlag<boolean>;
13
+ bail: _oclif_core_interfaces16.BooleanFlag<boolean>;
14
+ timeout: _oclif_core_interfaces16.OptionFlag<number, _oclif_core_interfaces16.CustomOptions>;
15
+ 'no-timeout': _oclif_core_interfaces16.BooleanFlag<boolean>;
16
+ grep: _oclif_core_interfaces16.OptionFlag<string | undefined, _oclif_core_interfaces16.CustomOptions>;
17
+ changed: _oclif_core_interfaces16.BooleanFlag<boolean>;
18
+ watch: _oclif_core_interfaces16.BooleanFlag<boolean>;
20
19
  };
21
20
  run(): Promise<void>;
22
- protected runMocha(mochaFile: string, mochaArgs: string[]): Promise<void>;
23
- protected formatMochaArgs(): Promise<string[] | undefined>;
21
+ protected buildVitestConfig(files: string[]): Promise<InlineConfig>;
24
22
  protected getChangedTestFiles(dir: string, ext: string): Promise<string[]>;
25
23
  }
26
24
  //#endregion
@@ -1,13 +1,13 @@
1
- import { BaseCommand } from "../baseCommand.js";
2
- import os from "node:os";
1
+ import { BaseCommand, ForkError } from "../baseCommand.js";
3
2
  import path from "node:path";
4
3
  import { debuglog } from "node:util";
5
- import { EggType, detectType, importResolve } from "@eggjs/utils";
4
+ import { EggType, ImportResolveError, detectType, importResolve } from "@eggjs/utils";
6
5
  import { Args, Flags } from "@oclif/core";
7
6
  import fs from "node:fs/promises";
8
7
  import ciParallelVars from "ci-parallel-vars";
9
8
  import globby from "globby";
10
9
  import { getChangedFilesForRoots } from "jest-changed-files";
10
+ import { startVitest } from "vitest/node";
11
11
 
12
12
  //#region src/commands/test.ts
13
13
  const debug = debuglog("egg/bin/commands/test");
@@ -23,7 +23,7 @@ var Test = class extends BaseCommand {
23
23
  ];
24
24
  static flags = {
25
25
  bail: Flags.boolean({
26
- description: "bbort (\"bail\") after first test failure",
26
+ description: "abort (\"bail\") after first test failure",
27
27
  default: false,
28
28
  char: "b"
29
29
  }),
@@ -41,20 +41,10 @@ var Test = class extends BaseCommand {
41
41
  description: "only test with changed files and match test/**/*.test.(js|ts)",
42
42
  char: "c"
43
43
  }),
44
- parallel: Flags.boolean({
45
- description: "mocha parallel mode",
44
+ watch: Flags.boolean({
45
+ description: "run tests in watch mode",
46
46
  default: false,
47
- char: "p"
48
- }),
49
- jobs: Flags.integer({
50
- char: "t",
51
- description: "number of jobs to run in parallel",
52
- default: os.cpus().length - 1
53
- }),
54
- "auto-agent": Flags.boolean({
55
- description: "[default: true] auto bootstrap agent in mocha master process",
56
- default: true,
57
- allowNo: true
47
+ char: "w"
58
48
  })
59
49
  };
60
50
  async run() {
@@ -65,35 +55,10 @@ var Test = class extends BaseCommand {
65
55
  console.error("baseDir: %o not exists", flags.base);
66
56
  throw err;
67
57
  }
68
- const mochaFile = process.env.MOCHA_FILE || importResolve("mocha/bin/_mocha");
69
- if (flags.parallel) {
70
- this.env.ENABLE_MOCHA_PARALLEL = "true";
71
- if (flags["auto-agent"]) this.env.AUTO_AGENT = "true";
72
- }
73
- this.env.NODE_ENV = "test";
58
+ process.env.NODE_ENV = "test";
74
59
  if (flags["no-timeout"]) flags.timeout = 0;
75
- debug("run test: %s %o flags: %o", mochaFile, this.args, flags);
76
- const mochaArgs = await this.formatMochaArgs();
77
- if (!mochaArgs) return;
78
- await this.runMocha(mochaFile, mochaArgs);
79
- }
80
- async runMocha(mochaFile, mochaArgs) {
81
- await this.forkNode(mochaFile, mochaArgs, { execArgv: [...process.execArgv, "--unhandled-rejections=strict"] });
82
- }
83
- async formatMochaArgs() {
84
- const { args, flags } = this;
85
- const requires = await this.formatRequires();
86
- const eggType = await detectType(flags.base);
87
- debug("eggType: %s", eggType);
88
- if (eggType === EggType.application) try {
89
- const eggMockRegister = importResolve("@eggjs/mock/register", { paths: [flags.base] });
90
- requires.push(eggMockRegister);
91
- debug("auto register @eggjs/mock/register: %o", eggMockRegister);
92
- } catch (err) {
93
- debug("auto register @eggjs/mock fail, can not require @eggjs/mock on %o, error: %s", flags.base, err.message);
94
- }
95
60
  const ext = flags.typescript ? "ts" : "js";
96
- let pattern = args.file ? args.file.split(",") : [];
61
+ let pattern = this.args.file ? this.args.file.split(",") : [];
97
62
  if (flags.changed) {
98
63
  pattern = await this.getChangedTestFiles(flags.base, ext);
99
64
  if (!pattern.length) {
@@ -104,7 +69,6 @@ var Test = class extends BaseCommand {
104
69
  }
105
70
  if (!pattern.length && process.env.TESTS) pattern = process.env.TESTS.split(",");
106
71
  if (!pattern.length) pattern = [`test/**/*.test.${ext}`];
107
- pattern = pattern.concat(["!test/fixtures", "!test/node_modules"]);
108
72
  let files = globby.sync(pattern, { cwd: flags.base });
109
73
  files.sort();
110
74
  if (files.length === 0) {
@@ -121,24 +85,77 @@ var Test = class extends BaseCommand {
121
85
  files = files.slice(offset, offset + currentFileCount);
122
86
  console.log("# Split test files in parallel CI jobs: %d/%d, files: %d/%d", currentIndex + 1, totalRuns, files.length, fileCount);
123
87
  }
88
+ files = files.map((f) => {
89
+ return (path.isAbsolute(f) ? f : path.join(flags.base, f)).replace(/\\/g, "/");
90
+ });
91
+ process.env.EGG_BIN_TIMEOUT = String(flags.timeout);
92
+ debug("run test with vitest, files: %o, flags: %o", files, flags);
93
+ const config = await this.buildVitestConfig(files);
94
+ if (flags["dry-run"]) {
95
+ console.log("vitest config: %o", config);
96
+ return;
97
+ }
98
+ if (this.env.NODE_OPTIONS) {
99
+ let nodeOptions = this.env.NODE_OPTIONS;
100
+ if (flags.typescript && !nodeOptions.includes("--no-experimental-strip-types")) nodeOptions = `--no-experimental-strip-types ${nodeOptions}`;
101
+ process.env.NODE_OPTIONS = nodeOptions;
102
+ }
103
+ const vitest = await startVitest("test", [], config, { configFile: false });
104
+ if (!vitest) throw new ForkError("vitest failed to start", 1);
105
+ if (flags.watch) return;
106
+ const failed = vitest.state.getCountOfFailedTests() ?? 0;
107
+ await vitest.close();
108
+ if (failed > 0) throw new ForkError("tests failed", 1);
109
+ }
110
+ async buildVitestConfig(files) {
111
+ const { flags } = this;
112
+ const ext = flags.typescript ? "ts" : "js";
113
+ const setupFiles = [];
124
114
  const setupFile = path.join(flags.base, `test/.setup.${ext}`);
125
115
  try {
126
116
  await fs.access(setupFile);
127
- files.unshift(setupFile);
117
+ setupFiles.push(setupFile.replace(/\\/g, "/"));
128
118
  } catch {}
129
- const grep = flags.grep ? flags.grep.split(",") : [];
130
- return [
131
- "--exit",
132
- flags.bail ? "--bail" : "",
133
- grep.map((pattern$1) => `--grep='${pattern$1}'`).join(" "),
134
- flags.timeout ? `--timeout=${flags.timeout}` : "--no-timeout",
135
- flags.parallel ? "--parallel" : "",
136
- flags.parallel && flags.jobs ? `--jobs=${flags.jobs}` : "",
137
- this.env.TEST_REPORTER ? `--reporter=${this.env.TEST_REPORTER}` : "",
138
- ...requires.map((r) => `--require=${r}`),
139
- ...files,
140
- flags["dry-run"] ? "--dry-run" : ""
141
- ].filter((a) => a.trim());
119
+ const requires = await this.formatRequires();
120
+ setupFiles.push(...requires);
121
+ const eggType = await detectType(flags.base);
122
+ debug("eggType: %s", eggType);
123
+ if (eggType === EggType.application) try {
124
+ const mockSetup = importResolve("@eggjs/mock/setup_vitest", { paths: [flags.base] });
125
+ setupFiles.push(mockSetup);
126
+ debug("auto add @eggjs/mock/setup_vitest: %o", mockSetup);
127
+ } catch (err) {
128
+ if (!(err instanceof ImportResolveError)) throw err;
129
+ debug("skip @eggjs/mock/setup_vitest: @eggjs/mock not installed");
130
+ }
131
+ let runner;
132
+ try {
133
+ runner = importResolve("@eggjs/tegg-vitest/runner", { paths: [flags.base] });
134
+ debug("auto use @eggjs/tegg-vitest/runner: %o", runner);
135
+ } catch (err) {
136
+ if (!(err instanceof ImportResolveError)) throw err;
137
+ debug("skip @eggjs/tegg-vitest/runner: @eggjs/tegg-vitest not installed");
138
+ }
139
+ return {
140
+ root: flags.base,
141
+ include: files,
142
+ exclude: [
143
+ "**/test/fixtures/**",
144
+ "**/test/node_modules/**",
145
+ "**/node_modules/**"
146
+ ],
147
+ testTimeout: flags.timeout,
148
+ testNamePattern: flags.grep,
149
+ bail: flags.bail ? 1 : 0,
150
+ setupFiles,
151
+ runner,
152
+ reporters: [process.env.TEST_REPORTER ?? "default"],
153
+ pool: "forks",
154
+ execArgv: [...this.globalExecArgv],
155
+ watch: flags.watch,
156
+ globals: true,
157
+ server: { deps: { inline: [/^(?!.*@vitest)/] } }
158
+ };
142
159
  }
143
160
  async getChangedTestFiles(dir, ext) {
144
161
  const changedFiles = (await getChangedFilesForRoots([path.join(dir, "test")], {})).changedFiles;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eggjs/bin",
3
- "version": "8.0.0-beta.36",
3
+ "version": "8.0.2-beta.0",
4
4
  "description": "egg developer tool",
5
5
  "homepage": "https://github.com/eggjs/egg/tree/next/tools/egg-bin",
6
6
  "bugs": {
@@ -40,21 +40,20 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@oclif/core": "^4.2.0",
43
- "c8": "^10.1.3",
43
+ "@vitest/coverage-v8": "^4.0.15",
44
44
  "ci-parallel-vars": "^1.0.1",
45
45
  "detect-port": "^2.1.0",
46
46
  "globby": "^11.0.2",
47
47
  "jest-changed-files": "^30.0.0",
48
- "mocha": "^11.7.5",
49
48
  "ts-node": "^10.9.2",
50
49
  "tsconfig-paths": "^4.2.0",
51
50
  "utility": "^2.5.0",
52
- "@eggjs/utils": "5.0.0-beta.36"
51
+ "vitest": "^4.0.15",
52
+ "@eggjs/utils": "5.0.2-beta.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@swc-node/register": "^1.11.1",
56
56
  "@swc/core": "^1.15.1",
57
- "@types/mocha": "^10.0.10",
58
57
  "@types/node": "^24.10.2",
59
58
  "assert-file": "1",
60
59
  "coffee": "5",
@@ -65,13 +64,13 @@
65
64
  "rimraf": "^6.1.2",
66
65
  "runscript": "^2.0.1",
67
66
  "typescript": "^5.9.3",
68
- "@eggjs/mock": "7.0.0-beta.36",
69
- "@eggjs/supertest": "9.0.0-beta.36",
70
- "@eggjs/tsconfig": "3.1.0-beta.36",
71
- "egg": "4.1.0-beta.36"
67
+ "@eggjs/mock": "7.0.2-beta.0",
68
+ "@eggjs/supertest": "9.0.2-beta.0",
69
+ "@eggjs/tsconfig": "3.1.2-beta.0",
70
+ "egg": "4.1.2-beta.0"
72
71
  },
73
72
  "peerDependencies": {
74
- "@eggjs/mock": "7.0.0-beta.36"
73
+ "@eggjs/mock": "7.0.2-beta.0"
75
74
  },
76
75
  "peerDependenciesMeta": {
77
76
  "@eggjs/mock": {
@@ -92,8 +91,9 @@
92
91
  },
93
92
  "scripts": {
94
93
  "typecheck": "tsgo --noEmit",
95
- "test": "node bin/run.js test",
96
- "cov": "c8 node bin/run.js test",
94
+ "pretest": "tsdown",
95
+ "test": "vitest run",
96
+ "cov": "vitest run --coverage",
97
97
  "ci": "npm run cov"
98
98
  }
99
99
  }