vitest 0.0.10 → 0.0.14

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
@@ -37,6 +37,55 @@ describe('suite name', () => {
37
37
  $ npx vitest
38
38
  ```
39
39
 
40
+ ## Configuration
41
+
42
+ `vitest` will read your root `vite.config.ts` when it present to match with the plugins and setup as your Vite app. If you want to it to have a different configuration for testing, you could either:
43
+
44
+ - Create `vitest.config.ts`, which will have the higher priority
45
+ - Pass `--config` option to CLI, e.g. `vitest --config ./path/to/vitest.config.ts`
46
+ - Use `process.env.VITEST` to conditionally apply differnet configuration in `vite.config.ts`
47
+
48
+ To configure `vitest` itself, add `test` property in your Vite config
49
+
50
+ ```ts
51
+ // vite.config.ts
52
+ import { defineConfig } from 'vite'
53
+
54
+ export default defineConfig({
55
+ test: {
56
+ // ...
57
+ }
58
+ })
59
+ ```
60
+
61
+ ## Global APIs
62
+
63
+ By default, `vitest` does not provide global APIs for explicitness. If you prefer to use the APIs globally like Jest, you can pass the `--global` option to CLI or add `global: true` in the config.
64
+
65
+ ```ts
66
+ // vite.config.ts
67
+ import { defineConfig } from 'vite'
68
+
69
+ export default defineConfig({
70
+ test: {
71
+ global: true
72
+ }
73
+ })
74
+ ```
75
+
76
+ To get TypeScript working with the global APIs, add `vitest/global` to the `types` filed in your `tsconfig.json`
77
+
78
+ ```json
79
+ // tsconfig.json
80
+ {
81
+ "compilerOptions": {
82
+ "types": [
83
+ "vitest/global"
84
+ ]
85
+ }
86
+ }
87
+ ```
88
+
40
89
  ## Filtering
41
90
 
42
91
  ### Skipping suites and tasks
@@ -103,10 +152,12 @@ describe('suite', () => {
103
152
  - [x] Reporter & Better output
104
153
  - [x] Task filter
105
154
  - [x] Mock
155
+ - [x] Global Mode & Types
106
156
  - [ ] Parallel Executing
107
157
  - [ ] CLI Help
108
158
  - [ ] JSDom
109
159
  - [ ] Watch
160
+ - [ ] Source Map
110
161
  - [ ] Coverage
111
162
 
112
163
  ## Sponsors
package/bin/vitest.mjs CHANGED
@@ -1,42 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict'
3
3
 
4
- import { fileURLToPath } from 'url'
5
- import { resolve, dirname } from 'path'
6
- import { run } from 'vite-node'
7
- import minimist from 'minimist'
8
- import { findUp } from 'find-up'
9
-
10
- const argv = minimist(process.argv.slice(2), {
11
- alias: {
12
- c: 'config',
13
- },
14
- string: ['root', 'config'],
15
- boolean: ['dev'],
16
- })
17
-
18
- const __dirname = dirname(fileURLToPath(import.meta.url))
19
- const root = resolve(argv.root || process.cwd())
20
-
21
- const configPath = argv.config ? resolve(root, argv.config) : await findUp(['vitest.config.ts', 'vitest.config.js', 'vitest.config.mjs', 'vite.config.ts', 'vite.config.js', 'vite.config.mjs'], { cwd: root })
22
-
23
- await run({
24
- root,
25
- files: [
26
- resolve(__dirname, argv.dev ? '../src/cli.ts' : '../dist/cli.js'),
27
- ],
28
- config: configPath,
29
- defaultConfig: {
30
- optimizeDeps: {
31
- exclude: [
32
- 'vitest',
33
- ],
34
- },
35
- },
36
- shouldExternalize(id) {
37
- if (id.includes('/node_modules/vitest/'))
38
- return false
39
- else
40
- return id.includes('/node_modules/')
41
- },
42
- })
4
+ import '../dist/cli.js'
package/dist/chai.d.ts CHANGED
@@ -1,9 +1,21 @@
1
+ import { Config } from 'vitest';
2
+ export declare function setupChai(config: Config): Promise<void>;
1
3
  export { assert, should, expect } from 'chai';
2
4
  declare global {
3
5
  namespace Chai {
4
6
  interface Assertion {
5
7
  toMatchSnapshot(message?: string): Assertion;
6
8
  matchSnapshot(message?: string): Assertion;
9
+ toEqual(expected: any): void;
10
+ toStrictEqual(expected: any): void;
11
+ toBe(expected: any): void;
12
+ toContain(item: any): void;
13
+ toBeTruthy(): void;
14
+ toBeFalsy(): void;
15
+ toBeNaN(): void;
16
+ toBeUndefined(): void;
17
+ toBeNull(): void;
18
+ toBeDefined(): void;
7
19
  }
8
20
  interface ExpectStatic {
9
21
  addSnapshotSerializer: import('pretty-format').Plugin;
package/dist/chai.js CHANGED
@@ -1 +1,48 @@
1
+ import chai from 'chai';
2
+ import SinonChai from 'sinon-chai';
3
+ import { SnapshotPlugin } from './snapshot';
4
+ export async function setupChai(config) {
5
+ chai.use(SinonChai);
6
+ chai.use(await SnapshotPlugin({
7
+ rootDir: config.rootDir || process.cwd(),
8
+ update: config.updateSnapshot,
9
+ }));
10
+ // Jest Compact
11
+ // TODO: add more https://jestjs.io/docs/expect
12
+ chai.use((chai, utils) => {
13
+ const proto = chai.Assertion.prototype;
14
+ utils.addMethod(proto, 'toEqual', function (expected) {
15
+ return this.eql(expected);
16
+ });
17
+ utils.addMethod(proto, 'toStrictEqual', function (expected) {
18
+ return this.equal(expected);
19
+ });
20
+ utils.addMethod(proto, 'toBe', function (expected) {
21
+ return this.be(expected);
22
+ });
23
+ utils.addMethod(proto, 'toContain', function (item) {
24
+ return this.contain(item);
25
+ });
26
+ utils.addMethod(proto, 'toBeTruthy', function () {
27
+ const obj = utils.flag(this, 'object');
28
+ this.assert(Boolean(obj), 'expected #{this} to be truthy', 'expected #{this} to not be truthy', obj);
29
+ });
30
+ utils.addMethod(proto, 'toFalsy', function () {
31
+ const obj = utils.flag(this, 'object');
32
+ this.assert(!obj, 'expected #{this} to be falsy', 'expected #{this} to not be falsy', obj);
33
+ });
34
+ utils.addMethod(proto, 'toBeNaN', function () {
35
+ return this.be.NaN;
36
+ });
37
+ utils.addMethod(proto, 'toBeUndefined', function () {
38
+ return this.be.undefined;
39
+ });
40
+ utils.addMethod(proto, 'toBeNull', function () {
41
+ return this.be.null;
42
+ });
43
+ utils.addMethod(proto, 'toBeDefined', function () {
44
+ return this.not.be.undefined;
45
+ });
46
+ });
47
+ }
1
48
  export { assert, should, expect } from 'chai';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ var _a;
2
+ import minimist from 'minimist';
3
+ import c from 'picocolors';
4
+ import { run } from './run';
5
+ const { log } = console;
6
+ const argv = minimist(process.argv.slice(2), {
7
+ alias: {
8
+ u: 'update',
9
+ },
10
+ string: ['root', 'config'],
11
+ boolean: ['update', 'dev', 'global'],
12
+ unknown(name) {
13
+ if (name[0] === '-') {
14
+ console.error(c.red(`Unknown argument: ${name}`));
15
+ help();
16
+ process.exit(1);
17
+ }
18
+ return true;
19
+ },
20
+ });
21
+ // @ts-expect-error
22
+ const server = (_a = process === null || process === void 0 ? void 0 : process.__vite_node__) === null || _a === void 0 ? void 0 : _a.server;
23
+ const viteConfig = (server === null || server === void 0 ? void 0 : server.config) || {};
24
+ const testOptions = viteConfig.test || {};
25
+ await run(Object.assign(Object.assign({}, testOptions), { server, global: argv.global, updateSnapshot: argv.update, rootDir: argv.root || process.cwd(), nameFilters: argv._ }));
26
+ function help() {
27
+ log('Help: finish help');
28
+ }
package/dist/cli.js CHANGED
@@ -1,28 +1,36 @@
1
- var _a;
1
+ import { fileURLToPath } from 'url';
2
+ import { resolve, dirname } from 'path';
2
3
  import minimist from 'minimist';
3
- import c from 'picocolors';
4
- import { run } from './run';
5
- const { log } = console;
4
+ import { findUp } from 'find-up';
5
+ import { run } from './node.js';
6
+ process.env.VITEST = 'true';
6
7
  const argv = minimist(process.argv.slice(2), {
7
8
  alias: {
8
- u: 'update',
9
+ c: 'config',
9
10
  },
10
11
  string: ['root', 'config'],
11
- boolean: ['update', 'dev'],
12
- unknown(name) {
13
- if (name[0] === '-') {
14
- console.error(c.red(`Unknown argument: ${name}`));
15
- help();
16
- process.exit(1);
17
- }
18
- return true;
12
+ boolean: ['dev'],
13
+ });
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const root = resolve(argv.root || process.cwd());
16
+ const configPath = argv.config ? resolve(root, argv.config) : await findUp(['vitest.config.ts', 'vitest.config.js', 'vitest.config.mjs', 'vite.config.ts', 'vite.config.js', 'vite.config.mjs'], { cwd: root });
17
+ await run({
18
+ root,
19
+ files: [
20
+ resolve(__dirname, argv.dev ? '../src/cli-entry.ts' : './cli-entry.js'),
21
+ ],
22
+ config: configPath,
23
+ defaultConfig: {
24
+ optimizeDeps: {
25
+ exclude: [
26
+ 'vitest',
27
+ ],
28
+ },
29
+ },
30
+ shouldExternalize(id) {
31
+ if (id.includes('/node_modules/vitest/'))
32
+ return false;
33
+ else
34
+ return id.includes('/node_modules/');
19
35
  },
20
36
  });
21
- // @ts-expect-error
22
- const server = (_a = process === null || process === void 0 ? void 0 : process.__vite_node__) === null || _a === void 0 ? void 0 : _a.server;
23
- const viteConfig = (server === null || server === void 0 ? void 0 : server.config) || {};
24
- const testOptions = viteConfig.test || {};
25
- await run(Object.assign(Object.assign({}, testOptions), { updateSnapshot: argv.update, rootDir: argv.root || process.cwd() }));
26
- function help() {
27
- log('Help: finish help');
28
- }
@@ -1,2 +1,3 @@
1
1
  export declare const defaultIncludes: string[];
2
2
  export declare const defaultExcludes: string[];
3
+ export declare const globalApis: string[];
package/dist/constants.js CHANGED
@@ -1,2 +1,22 @@
1
1
  export const defaultIncludes = ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'];
2
2
  export const defaultExcludes = ['**/node_modules/**', '**/dist/**'];
3
+ export const globalApis = [
4
+ 'suite',
5
+ 'test',
6
+ 'describe',
7
+ 'it',
8
+ 'expect',
9
+ 'assert',
10
+ 'spy',
11
+ 'mock',
12
+ 'stub',
13
+ 'sinon',
14
+ 'beforeAll',
15
+ 'afterAll',
16
+ 'beforeEach',
17
+ 'afterEach',
18
+ 'beforeFile',
19
+ 'afterFile',
20
+ 'beforeSuite',
21
+ 'afterSuite',
22
+ ];
@@ -0,0 +1 @@
1
+ export declare function registerApiGlobally(): void;
package/dist/global.js ADDED
@@ -0,0 +1,8 @@
1
+ import { globalApis } from './constants';
2
+ import * as index from './index';
3
+ export function registerApiGlobally() {
4
+ globalApis.forEach((api) => {
5
+ // @ts-expect-error
6
+ globalThis[api] = index[api];
7
+ });
8
+ }
package/dist/index.d.ts CHANGED
@@ -5,4 +5,4 @@ export * from './config';
5
5
  export * from './chai';
6
6
  export { beforeAll, afterAll, beforeEach, afterEach, beforeFile, afterFile, beforeSuite, afterSuite } from './hooks';
7
7
  export { sinon };
8
- export declare const mock: sinon.SinonMockStatic, spy: sinon.SinonSpyStatic;
8
+ export declare const mock: sinon.SinonMockStatic, spy: sinon.SinonSpyStatic, stub: sinon.SinonStubStatic;
package/dist/index.js CHANGED
@@ -5,4 +5,4 @@ export * from './config';
5
5
  export * from './chai';
6
6
  export { beforeAll, afterAll, beforeEach, afterEach, beforeFile, afterFile, beforeSuite, afterSuite } from './hooks';
7
7
  export { sinon };
8
- export const { mock, spy } = sinon;
8
+ export const { mock, spy, stub } = sinon;
package/dist/node.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { InlineConfig } from 'vite';
2
+ export interface ViteNodeOptions {
3
+ silent?: boolean;
4
+ root: string;
5
+ files: string[];
6
+ _?: string[];
7
+ shouldExternalize?: (file: string) => boolean;
8
+ config?: string;
9
+ defaultConfig?: InlineConfig;
10
+ }
11
+ export declare function run(argv: ViteNodeOptions): Promise<void>;
package/dist/node.js ADDED
@@ -0,0 +1,126 @@
1
+ import { builtinModules, createRequire } from 'module';
2
+ import { pathToFileURL } from 'url';
3
+ import { dirname, resolve, relative } from 'path';
4
+ import vm from 'vm';
5
+ import { createServer, mergeConfig } from 'vite';
6
+ import c from 'picocolors';
7
+ const { red, dim, yellow } = c;
8
+ export async function run(argv) {
9
+ process.exitCode = 0;
10
+ const root = argv.root || process.cwd();
11
+ process.chdir(root);
12
+ const files = argv.files || argv._;
13
+ argv.shouldExternalize = argv.shouldExternalize || (id => id.includes('/node_modules/'));
14
+ const server = await createServer(mergeConfig(argv.defaultConfig || {}, {
15
+ logLevel: 'error',
16
+ clearScreen: false,
17
+ configFile: argv.config,
18
+ root,
19
+ resolve: {},
20
+ }));
21
+ await server.pluginContainer.buildStart({});
22
+ // @ts-expect-error
23
+ process.__vite_node__ = {
24
+ server,
25
+ };
26
+ try {
27
+ await execute(files, server, argv);
28
+ }
29
+ catch (e) {
30
+ process.exitCode = 1;
31
+ throw e;
32
+ }
33
+ finally {
34
+ await server.close();
35
+ }
36
+ }
37
+ function normalizeId(id) {
38
+ // Virtual modules start with `\0`
39
+ if (id && id.startsWith('/@id/__x00__'))
40
+ id = `\0${id.slice('/@id/__x00__'.length)}`;
41
+ if (id && id.startsWith('/@id/'))
42
+ id = id.slice('/@id/'.length);
43
+ return id;
44
+ }
45
+ function toFilePath(id, server) {
46
+ let absolute = id.startsWith('/@fs/')
47
+ ? id.slice(4)
48
+ : id.startsWith(dirname(server.config.root))
49
+ ? id
50
+ : slash(resolve(server.config.root, id.slice(1)));
51
+ if (absolute.startsWith('//'))
52
+ absolute = absolute.slice(1);
53
+ if (!absolute.startsWith('/'))
54
+ absolute = `/${absolute}`;
55
+ return absolute;
56
+ }
57
+ async function execute(files, server, options) {
58
+ const __pendingModules__ = new Map();
59
+ const result = [];
60
+ for (const file of files)
61
+ result.push(await cachedRequest(`/@fs/${slash(resolve(file))}`, []));
62
+ return result;
63
+ async function directRequest(rawId, callstack) {
64
+ if (builtinModules.includes(rawId))
65
+ return import(rawId);
66
+ callstack = [...callstack, rawId];
67
+ const request = async (dep) => {
68
+ if (callstack.includes(dep)) {
69
+ throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => {
70
+ const path = relative(server.config.root, toFilePath(normalizeId(i), server));
71
+ return dim(' -> ') + (i === dep ? yellow(path) : path);
72
+ }).join('\n')}\n`);
73
+ }
74
+ return cachedRequest(dep, callstack);
75
+ };
76
+ const id = normalizeId(rawId);
77
+ const absolute = toFilePath(id, server);
78
+ if (options.shouldExternalize(absolute))
79
+ return import(absolute);
80
+ const result = await server.transformRequest(id, { ssr: true });
81
+ if (!result)
82
+ throw new Error(`failed to load ${id}`);
83
+ const url = pathToFileURL(absolute);
84
+ const exports = {};
85
+ const context = {
86
+ require: createRequire(url),
87
+ __filename: absolute,
88
+ __dirname: dirname(absolute),
89
+ __vite_ssr_import__: request,
90
+ __vite_ssr_dynamic_import__: request,
91
+ __vite_ssr_exports__: exports,
92
+ __vite_ssr_exportAll__: (obj) => exportAll(exports, obj),
93
+ __vite_ssr_import_meta__: { url },
94
+ };
95
+ const fn = vm.runInThisContext(`async (${Object.keys(context).join(',')}) => { ${result.code} }`, {
96
+ filename: absolute,
97
+ lineOffset: 0,
98
+ });
99
+ await fn(...Object.values(context));
100
+ return exports;
101
+ }
102
+ async function cachedRequest(id, callstack) {
103
+ if (__pendingModules__.has(id))
104
+ return __pendingModules__.get(id);
105
+ __pendingModules__.set(id, directRequest(id, callstack));
106
+ return await __pendingModules__.get(id);
107
+ }
108
+ function exportAll(exports, sourceModule) {
109
+ // eslint-disable-next-line no-restricted-syntax
110
+ for (const key in sourceModule) {
111
+ if (key !== 'default') {
112
+ try {
113
+ Object.defineProperty(exports, key, {
114
+ enumerable: true,
115
+ configurable: true,
116
+ get() { return sourceModule[key]; },
117
+ });
118
+ }
119
+ catch (_err) { }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ function slash(path) {
125
+ return path.replace(/\\/g, '/');
126
+ }
@@ -5,13 +5,13 @@ export declare class DefaultReporter implements Reporter {
5
5
  end: number;
6
6
  onStart(): void;
7
7
  onCollected(): void;
8
- onFinished({ files }: RunnerContext): void;
9
8
  onSuiteBegin(suite: Suite): void;
10
9
  onSuiteEnd(suite: Suite): void;
11
10
  onFileBegin(file: File): void;
12
11
  onFileEnd(): void;
13
12
  onTaskBegin(task: Task): void;
14
13
  onTaskEnd(task: Task): void;
14
+ onFinished({ files }: RunnerContext): void;
15
15
  private getIndent;
16
16
  private log;
17
17
  private error;
@@ -3,6 +3,8 @@ import { performance } from 'perf_hooks';
3
3
  import c from 'picocolors';
4
4
  import ora from 'ora';
5
5
  const DOT = '· ';
6
+ const CHECK = '✔ ';
7
+ const CROSS = '⤫ ';
6
8
  export class DefaultReporter {
7
9
  constructor() {
8
10
  this.indent = 0;
@@ -15,23 +17,6 @@ export class DefaultReporter {
15
17
  onCollected() {
16
18
  this.start = performance.now();
17
19
  }
18
- onFinished({ files }) {
19
- this.end = performance.now();
20
- const tasks = files.reduce((acc, file) => acc.concat(file.suites.flatMap(i => i.tasks)), []);
21
- const passed = tasks.filter(i => i.status === 'pass');
22
- const failed = tasks.filter(i => i.status === 'fail');
23
- const skipped = tasks.filter(i => i.status === 'skip');
24
- const todo = tasks.filter(i => i.status === 'todo');
25
- this.indent = 0;
26
- this.log(c.green(`Passed ${passed.length} / ${tasks.length}`));
27
- if (skipped.length)
28
- this.log(c.yellow(`Skipped ${skipped.length}`));
29
- if (todo.length)
30
- this.log(c.dim(`Todo ${todo.length}`));
31
- if (failed.length)
32
- this.log(c.red(`Failed ${failed.length} / ${tasks.length}`));
33
- this.log(`Time ${(this.end - this.start).toFixed(2)}ms`);
34
- }
35
20
  onSuiteBegin(suite) {
36
21
  if (suite.name) {
37
22
  this.indent += 1;
@@ -63,22 +48,57 @@ export class DefaultReporter {
63
48
  var _a;
64
49
  // @ts-expect-error
65
50
  (_a = task.__ora) === null || _a === void 0 ? void 0 : _a.stop();
66
- if (task.status === 'pass') {
67
- this.log(`${c.green(`✔ ${task.name}`)}`);
51
+ if (task.state === 'pass') {
52
+ this.log(`${c.green(CHECK + task.name)}`);
68
53
  }
69
- else if (task.status === 'skip') {
54
+ else if (task.state === 'skip') {
70
55
  this.log(c.dim(c.yellow(`${DOT + task.name} (skipped)`)));
71
56
  }
72
- else if (task.status === 'todo') {
57
+ else if (task.state === 'todo') {
73
58
  this.log(c.dim(`${DOT + task.name} (todo)`));
74
59
  }
75
60
  else {
76
- this.error(`${c.red(`⤫ ${c.inverse(c.red(' FAIL '))} ${task.name}`)}`);
77
- this.error(String(task.error), 1);
61
+ this.error(`${c.red(`${CROSS}${task.name}`)}`);
78
62
  process.exitCode = 1;
79
63
  }
80
64
  this.indent -= 1;
81
65
  }
66
+ onFinished({ files }) {
67
+ this.end = performance.now();
68
+ const failedFiles = files.filter(i => i.error);
69
+ const tasks = files.reduce((acc, file) => acc.concat(file.suites.flatMap(i => i.tasks)), []);
70
+ const runable = tasks.filter(i => i.state === 'pass' || i.state === 'fail');
71
+ const passed = tasks.filter(i => i.state === 'pass');
72
+ const failed = tasks.filter(i => i.state === 'fail');
73
+ const skipped = tasks.filter(i => i.state === 'skip');
74
+ const todo = tasks.filter(i => i.state === 'todo');
75
+ this.indent = 0;
76
+ if (failedFiles.length) {
77
+ this.error(c.bold(`\nFailed to parse ${failedFiles.length} files:`));
78
+ failedFiles.forEach((i) => {
79
+ this.error(`\n- ${i.filepath}`);
80
+ console.error(i.error || 'Unknown error');
81
+ this.log();
82
+ });
83
+ }
84
+ if (failed.length) {
85
+ this.error(c.bold(`\nFailed Tests (${failed.length})`));
86
+ failed.forEach((task) => {
87
+ var _a;
88
+ this.error(`\n${CROSS + c.inverse(c.red(' FAIL '))} ${[task.suite.name, task.name].filter(Boolean).join(' > ')} ${c.gray(`${(_a = task.file) === null || _a === void 0 ? void 0 : _a.filepath}`)}`);
89
+ console.error(task.error || 'Unknown error');
90
+ this.log();
91
+ });
92
+ }
93
+ this.log(c.green(`Passed ${passed.length} / ${runable.length}`));
94
+ if (failed.length)
95
+ this.log(c.red(`Failed ${failed.length} / ${runable.length}`));
96
+ if (skipped.length)
97
+ this.log(c.yellow(`Skipped ${skipped.length}`));
98
+ if (todo.length)
99
+ this.log(c.dim(`Todo ${todo.length}`));
100
+ this.log(`Time ${(this.end - this.start).toFixed(2)}ms`);
101
+ }
82
102
  getIndent(offest = 0) {
83
103
  return ' '.repeat((this.indent + offest) * 2);
84
104
  }
package/dist/run.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { File, Options, Task, RunnerContext } from './types';
1
+ import { File, Config, Task, RunnerContext } from './types';
2
2
  export declare function runTask(task: Task, ctx: RunnerContext): Promise<void>;
3
- export declare function collectFiles(files: string[]): Promise<File[]>;
3
+ export declare function collectFiles(paths: string[]): Promise<File[]>;
4
4
  export declare function runFile(file: File, ctx: RunnerContext): Promise<void>;
5
- export declare function run(options?: Options): Promise<void>;
5
+ export declare function run(config: Config): Promise<void>;
package/dist/run.js CHANGED
@@ -1,59 +1,82 @@
1
- import chai from 'chai';
2
1
  import fg from 'fast-glob';
3
- import SinonChai from 'sinon-chai';
2
+ import { setupChai } from './chai';
4
3
  import { clearContext, defaultSuite } from './suite';
5
4
  import { context } from './context';
6
5
  import { afterEachHook, afterFileHook, afterAllHook, afterSuiteHook, beforeEachHook, beforeFileHook, beforeAllHook, beforeSuiteHook } from './hooks';
7
- import { SnapshotPlugin } from './snapshot';
8
6
  import { DefaultReporter } from './reporters/default';
9
7
  import { defaultIncludes, defaultExcludes } from './constants';
10
8
  export async function runTask(task, ctx) {
11
9
  var _a, _b;
12
10
  const { reporter } = ctx;
13
11
  await ((_a = reporter.onTaskBegin) === null || _a === void 0 ? void 0 : _a.call(reporter, task, ctx));
14
- await beforeEachHook.fire(task);
15
- if (task.suite.mode === 'skip' || task.mode === 'skip') {
16
- task.status = 'skip';
17
- }
18
- else if (task.suite.mode === 'todo' || task.mode === 'todo') {
19
- task.status = 'todo';
20
- }
21
- else {
12
+ if (task.mode === 'run') {
13
+ await beforeEachHook.fire(task);
22
14
  try {
23
15
  await task.fn();
24
- task.status = 'pass';
16
+ task.state = 'pass';
25
17
  }
26
18
  catch (e) {
27
- task.status = 'fail';
19
+ task.state = 'fail';
28
20
  task.error = e;
29
21
  }
22
+ await afterEachHook.fire(task);
30
23
  }
31
- await afterEachHook.fire(task);
32
24
  await ((_b = reporter.onTaskEnd) === null || _b === void 0 ? void 0 : _b.call(reporter, task, ctx));
33
25
  }
34
- export async function collectFiles(files) {
35
- const result = [];
36
- for (const filepath of files) {
37
- clearContext();
38
- await import(filepath);
39
- const collectors = [defaultSuite, ...context.suites];
40
- const suites = [];
26
+ export async function collectFiles(paths) {
27
+ const files = [];
28
+ for (const filepath of paths) {
41
29
  const file = {
42
30
  filepath,
43
31
  suites: [],
32
+ collected: false,
44
33
  };
45
- for (const c of collectors) {
46
- context.currentSuite = c;
47
- suites.push(await c.collect(file));
34
+ clearContext();
35
+ try {
36
+ await import(filepath);
37
+ const collectors = [defaultSuite, ...context.suites];
38
+ for (const c of collectors) {
39
+ context.currentSuite = c;
40
+ file.suites.push(await c.collect(file));
41
+ }
42
+ file.collected = true;
43
+ }
44
+ catch (e) {
45
+ file.error = e;
46
+ file.collected = false;
47
+ process.exitCode = 1;
48
48
  }
49
- file.suites = suites;
50
- result.push(file);
49
+ files.push(file);
50
+ }
51
+ const allSuites = files.reduce((suites, file) => suites.concat(file.suites), []);
52
+ interpretOnlyMode(allSuites);
53
+ allSuites.forEach((i) => {
54
+ if (i.mode === 'skip')
55
+ i.tasks.forEach(t => t.mode === 'run' && (t.state = 'skip'));
56
+ else
57
+ interpretOnlyMode(i.tasks);
58
+ });
59
+ return files;
60
+ }
61
+ /**
62
+ * If any items been marked as `only`, mark all other items as `skip`.
63
+ */
64
+ function interpretOnlyMode(items) {
65
+ if (items.some(i => i.mode === 'only')) {
66
+ items.forEach((i) => {
67
+ if (i.mode === 'run')
68
+ i.mode = 'skip';
69
+ else if (i.mode === 'only')
70
+ i.mode = 'run';
71
+ });
51
72
  }
52
- return result;
53
73
  }
54
74
  export async function runFile(file, ctx) {
55
75
  var _a, _b, _c, _d;
56
76
  const { reporter } = ctx;
77
+ const runableSuites = file.suites.filter(i => i.mode === 'run');
78
+ if (runableSuites.length === 0)
79
+ return;
57
80
  await ((_a = reporter.onFileBegin) === null || _a === void 0 ? void 0 : _a.call(reporter, file, ctx));
58
81
  await beforeFileHook.fire(file);
59
82
  for (const suite of file.suites) {
@@ -67,42 +90,37 @@ export async function runFile(file, ctx) {
67
90
  await afterFileHook.fire(file);
68
91
  await ((_d = reporter.onFileEnd) === null || _d === void 0 ? void 0 : _d.call(reporter, file, ctx));
69
92
  }
70
- export async function run(options = {}) {
71
- var _a, _b, _c;
72
- const { rootDir = process.cwd() } = options;
93
+ export async function run(config) {
94
+ var _a, _b, _c, _d;
73
95
  // setup chai
74
- chai.use(await SnapshotPlugin({
75
- rootDir,
76
- update: options.updateSnapshot,
77
- }));
78
- chai.use(SinonChai);
96
+ await setupChai(config);
79
97
  // collect files
80
- const paths = await fg(options.includes || defaultIncludes, {
98
+ let paths = await fg(config.includes || defaultIncludes, {
81
99
  absolute: true,
82
- cwd: options.rootDir,
83
- ignore: options.excludes || defaultExcludes,
100
+ cwd: config.rootDir,
101
+ ignore: config.excludes || defaultExcludes,
84
102
  });
103
+ if ((_a = config.nameFilters) === null || _a === void 0 ? void 0 : _a.length)
104
+ paths = paths.filter(i => config.nameFilters.some(f => i.includes(f)));
85
105
  if (!paths.length) {
86
106
  console.error('No test files found');
87
107
  process.exitCode = 1;
88
108
  return;
89
109
  }
90
110
  const reporter = new DefaultReporter();
91
- await ((_a = reporter.onStart) === null || _a === void 0 ? void 0 : _a.call(reporter, options));
111
+ await ((_b = reporter.onStart) === null || _b === void 0 ? void 0 : _b.call(reporter, config));
112
+ if (config.global)
113
+ (await import('./global')).registerApiGlobally();
92
114
  const files = await collectFiles(paths);
93
115
  const ctx = {
94
116
  files,
95
- mode: isOnlyMode(files) ? 'only' : 'all',
96
- userOptions: options,
117
+ config,
97
118
  reporter,
98
119
  };
99
- await ((_b = reporter.onCollected) === null || _b === void 0 ? void 0 : _b.call(reporter, ctx));
120
+ await ((_c = reporter.onCollected) === null || _c === void 0 ? void 0 : _c.call(reporter, ctx));
100
121
  await beforeAllHook.fire();
101
122
  for (const file of files)
102
123
  await runFile(file, ctx);
103
124
  await afterAllHook.fire();
104
- await ((_c = reporter.onFinished) === null || _c === void 0 ? void 0 : _c.call(reporter, ctx));
105
- }
106
- function isOnlyMode(files) {
107
- return !!files.find(file => file.suites.find(suite => suite.mode === 'only' || suite.tasks.find(t => t.mode === 'only')));
125
+ await ((_d = reporter.onFinished) === null || _d === void 0 ? void 0 : _d.call(reporter, ctx));
108
126
  }
@@ -4,6 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
+ // @ts-ignore
7
8
  import Test from '@jest/test-result';
8
9
  const { makeEmptyAggregatedTestResult, } = Test;
9
10
  export const makeEmptySnapshotSummary = (options) => {
package/dist/suite.js CHANGED
@@ -22,7 +22,7 @@ function createSuiteCollector(mode, suiteName, factory) {
22
22
  name,
23
23
  mode,
24
24
  suite: {},
25
- status: 'init',
25
+ state: mode !== 'run' ? mode : undefined,
26
26
  fn,
27
27
  });
28
28
  }
package/dist/types.d.ts CHANGED
@@ -1,21 +1,31 @@
1
+ import { ViteDevServer } from 'vite';
1
2
  export declare type Awaitable<T> = Promise<T> | T;
2
3
  export interface UserOptions {
3
4
  includes?: string[];
4
5
  excludes?: string[];
6
+ /**
7
+ * Register apis globally
8
+ *
9
+ * @default false
10
+ */
11
+ global?: string;
5
12
  }
6
- export interface Options extends UserOptions {
13
+ export interface Config extends UserOptions {
7
14
  rootDir?: string;
8
15
  updateSnapshot?: boolean;
16
+ nameFilters?: string[];
17
+ server: ViteDevServer;
18
+ watch?: boolean;
9
19
  }
10
20
  export declare type RunMode = 'run' | 'skip' | 'only' | 'todo';
11
- export declare type TaskStatus = 'init' | 'pass' | 'fail' | 'skip' | 'todo';
21
+ export declare type TaskState = RunMode | 'pass' | 'fail';
12
22
  export interface Task {
13
23
  name: string;
14
24
  mode: RunMode;
15
25
  suite: Suite;
16
26
  fn: () => Awaitable<void>;
17
27
  file?: File;
18
- status: TaskStatus;
28
+ state?: TaskState;
19
29
  error?: unknown;
20
30
  }
21
31
  export declare type TestFunction = () => Awaitable<void>;
@@ -42,11 +52,12 @@ export declare type TestFactory = (test: (name: string, fn: TestFunction) => voi
42
52
  export interface File {
43
53
  filepath: string;
44
54
  suites: Suite[];
55
+ collected: boolean;
56
+ error?: unknown;
45
57
  }
46
58
  export interface RunnerContext {
47
59
  files: File[];
48
- mode: 'all' | 'only';
49
- userOptions: Options;
60
+ config: Config;
50
61
  reporter: Reporter;
51
62
  }
52
63
  export interface GlobalContext {
@@ -54,7 +65,7 @@ export interface GlobalContext {
54
65
  currentSuite: SuiteCollector | null;
55
66
  }
56
67
  export interface Reporter {
57
- onStart: (userOptions: Options) => Awaitable<void>;
68
+ onStart: (userOptions: Config) => Awaitable<void>;
58
69
  onCollected: (ctx: RunnerContext) => Awaitable<void>;
59
70
  onFinished: (ctx: RunnerContext) => Awaitable<void>;
60
71
  onSuiteBegin: (suite: Suite, ctx: RunnerContext) => Awaitable<void>;
package/dist/types.js CHANGED
@@ -1,2 +1 @@
1
- /* eslint-disable no-use-before-define */
2
1
  export {};
package/global.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ declare global {
2
+ const suite: typeof import('vitest')['suite']
3
+ const test: typeof import('vitest')['test']
4
+ const describe: typeof import('vitest')['describe']
5
+ const it: typeof import('vitest')['it']
6
+ const expect: typeof import('vitest')['expect']
7
+ const assert: typeof import('vitest')['assert']
8
+ const spy: typeof import('vitest')['spy']
9
+ const mock: typeof import('vitest')['mock']
10
+ const stub: typeof import('vitest')['stub']
11
+ const sinon: typeof import('vitest')['sinon']
12
+ const beforeAll: typeof import('vitest')['beforeAll']
13
+ const afterAll: typeof import('vitest')['afterAll']
14
+ const beforeEach: typeof import('vitest')['beforeEach']
15
+ const afterEach: typeof import('vitest')['afterEach']
16
+ const beforeFile: typeof import('vitest')['beforeFile']
17
+ const afterFile: typeof import('vitest')['afterFile']
18
+ const beforeSuite: typeof import('vitest')['beforeSuite']
19
+ const afterSuite: typeof import('vitest')['afterSuite']
20
+ }
21
+ export {}
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "vitest",
3
- "version": "0.0.10",
4
- "type": "module",
3
+ "version": "0.0.14",
5
4
  "description": "",
6
5
  "keywords": [],
7
6
  "homepage": "https://github.com/antfu/vitest#readme",
@@ -15,6 +14,7 @@
15
14
  "funding": "https://github.com/sponsors/antfu",
16
15
  "license": "MIT",
17
16
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
17
+ "type": "module",
18
18
  "exports": {
19
19
  ".": {
20
20
  "import": "./dist/index.js",
@@ -25,25 +25,14 @@
25
25
  "main": "./dist/index.js",
26
26
  "module": "./dist/index.js",
27
27
  "types": "./dist/index.d.ts",
28
- "files": [
29
- "dist",
30
- "bin"
31
- ],
32
28
  "bin": {
33
29
  "vitest": "./bin/vitest.mjs"
34
30
  },
35
- "devDependencies": {
36
- "@antfu/eslint-config": "^0.11.1",
37
- "@antfu/ni": "^0.11.0",
38
- "@types/minimist": "^1.2.2",
39
- "@types/node": "^16.11.11",
40
- "@types/sinon": "^10.0.6",
41
- "bumpp": "^7.1.1",
42
- "eslint": "^8.3.0",
43
- "esno": "^0.12.1",
44
- "typescript": "^4.5.2",
45
- "vite": "^2.6.14"
46
- },
31
+ "files": [
32
+ "dist",
33
+ "bin",
34
+ "*.d.ts"
35
+ ],
47
36
  "dependencies": {
48
37
  "@jest/test-result": "^27.4.2",
49
38
  "@types/chai": "^4.2.22",
@@ -57,15 +46,27 @@
57
46
  "ora": "^6.0.1",
58
47
  "picocolors": "^1.0.0",
59
48
  "sinon": "^12.0.1",
60
- "sinon-chai": "^3.7.0",
61
- "vite-node": "^0.1.10"
49
+ "sinon-chai": "^3.7.0"
50
+ },
51
+ "devDependencies": {
52
+ "@antfu/eslint-config": "^0.11.1",
53
+ "@antfu/ni": "^0.11.0",
54
+ "@types/minimist": "^1.2.2",
55
+ "@types/node": "^16.11.11",
56
+ "@types/sinon": "^10.0.6",
57
+ "bumpp": "^7.1.1",
58
+ "eslint": "^8.3.0",
59
+ "esno": "^0.12.1",
60
+ "rimraf": "^3.0.2",
61
+ "typescript": "^4.5.2",
62
+ "vite": "^2.6.14"
62
63
  },
63
64
  "scripts": {
64
- "build": "tsc",
65
- "watch": "tsc --watch",
65
+ "build": "rimraf dist && tsc -p src/tsconfig.json",
66
66
  "lint": "eslint \"{src,test}/**/*.ts\"",
67
67
  "release": "bumpp --commit --push --tag && pnpm publish",
68
68
  "test": "node bin/vitest.mjs --dev",
69
- "test:update": "nr test -u"
69
+ "test:update": "nr test -u",
70
+ "watch": "tsc -p src/tsconfig.json --watch"
70
71
  }
71
72
  }
File without changes
@@ -1 +0,0 @@
1
- "use strict";
File without changes
@@ -1 +0,0 @@
1
- "use strict";
File without changes
@@ -1 +0,0 @@
1
- "use strict";