vitest 0.0.33 → 0.0.34
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.gh.md +50 -7
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/node/node.js +2 -0
- package/dist/run/index.js +28 -2
- package/dist/suite.d.ts +36 -6
- package/dist/suite.js +70 -19
- package/dist/types.d.ts +27 -3
- package/package.json +1 -1
package/README.gh.md
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://user-images.githubusercontent.com/11247099/145112184-a9ff6727-661c-439d-9ada-963124a281f7.png" height="200">
|
|
3
|
+
</p>
|
|
4
4
|
|
|
5
|
+
<h1 align="center">
|
|
6
|
+
Vitest
|
|
7
|
+
</h1>
|
|
8
|
+
<p align="center">
|
|
5
9
|
A blazing fast unit test framework powered by Vite.
|
|
10
|
+
<p>
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/vitest"><img src="https://img.shields.io/npm/v/vitest?color=a1b858&label="></a>
|
|
13
|
+
<p>
|
|
6
14
|
|
|
7
|
-
> **This project is currently in closed beta exclusively for Sponsors.**<br>
|
|
15
|
+
> 💖 **This project is currently in closed beta exclusively for Sponsors.**<br>
|
|
8
16
|
> Become a Sponsor of [@patak-js](https://github.com/sponsors/patak-js) or [@antfu](https://github.com/sponsors/antfu) to access the source code and issues tracker.
|
|
9
17
|
|
|
10
18
|
> ⚠️ **DISCLAIMER**: Vitest is still in development and not stable yet. It's not recommended to use it in production.
|
|
@@ -15,17 +23,19 @@ A blazing fast unit test framework powered by Vite.
|
|
|
15
23
|
|
|
16
24
|
## Features
|
|
17
25
|
|
|
18
|
-
- [Vite](https://vitejs.dev/)'s config, transformers, resolvers, and plugins.
|
|
26
|
+
- [Vite](https://vitejs.dev/)'s config, transformers, resolvers, and plugins. Use the same setup from your app!
|
|
19
27
|
- [Jest Snapshot](https://jestjs.io/docs/snapshot-testing)
|
|
20
28
|
- [Chai](https://www.chaijs.com/) built-in for assertions, with [jest-expect](https://jestjs.io/docs/expect) compatible APIs.
|
|
29
|
+
- [Smart watch mode](#watch-mode), just like HMR for tests!
|
|
30
|
+
- [Code coverage](#coverage)
|
|
21
31
|
- [Sinon](https://sinonjs.org/) built-in for mocking
|
|
22
|
-
- [JSDOM](https://github.com/jsdom/jsdom) built-in
|
|
32
|
+
- [JSDOM](https://github.com/jsdom/jsdom) built-in for DOM and browser API mocking
|
|
23
33
|
- Components testing ([Vue example](./test/vue), [React example](./test/react))
|
|
24
34
|
- Async suite / test, top level await
|
|
25
35
|
- ESM friendly
|
|
26
36
|
- Out-of-box TypeScript / JSX support
|
|
27
37
|
- Suite and Test filtering (skip, only, todo)
|
|
28
|
-
-
|
|
38
|
+
- Concurrent Tests
|
|
29
39
|
|
|
30
40
|
```ts
|
|
31
41
|
import { it, describe, expect, assert } from 'vitest'
|
|
@@ -229,6 +239,39 @@ describe('suite', () => {
|
|
|
229
239
|
})
|
|
230
240
|
```
|
|
231
241
|
|
|
242
|
+
### Running tests concurrently
|
|
243
|
+
|
|
244
|
+
Use `.concurrent` in consecutive tests to run them in parallel
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
// The two tasks marked with concurrent will be run in parallel
|
|
248
|
+
describe('suite', () => {
|
|
249
|
+
it('serial task', () => {
|
|
250
|
+
assert.equal(Math.sqrt(4), 3)
|
|
251
|
+
})
|
|
252
|
+
it.concurrent('concurrent task 1', () => {
|
|
253
|
+
assert.equal(Math.sqrt(4), 3)
|
|
254
|
+
})
|
|
255
|
+
it.concurrent('concurrent task 2', () => {
|
|
256
|
+
assert.equal(Math.sqrt(4), 3)
|
|
257
|
+
})
|
|
258
|
+
})
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
You can also use `.skip`, `.only`, and `.todo` with concurrent tasks. All the following combinations are valid:
|
|
262
|
+
```js
|
|
263
|
+
it.concurrent(...)
|
|
264
|
+
|
|
265
|
+
it.skip.concurrent(...)
|
|
266
|
+
it.concurrent.skip(...)
|
|
267
|
+
|
|
268
|
+
it.only.concurrent(...)
|
|
269
|
+
it.concurrent.only(...)
|
|
270
|
+
|
|
271
|
+
it.todo.concurrent(...)
|
|
272
|
+
it.concurrent.todo(...)
|
|
273
|
+
```
|
|
274
|
+
|
|
232
275
|
## Sponsors
|
|
233
276
|
|
|
234
277
|
<p align="center">
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
package/dist/node/node.js
CHANGED
package/dist/run/index.js
CHANGED
|
@@ -98,8 +98,15 @@ export async function runSuite(suite, ctx) {
|
|
|
98
98
|
else {
|
|
99
99
|
try {
|
|
100
100
|
await callHook(suite, 'beforeAll', [suite]);
|
|
101
|
-
for (const
|
|
102
|
-
|
|
101
|
+
for (const taskGroup of partitionTasks(suite.tasks)) {
|
|
102
|
+
if (taskGroup[0].concurrent) {
|
|
103
|
+
await Promise.all(taskGroup.map(t => runTask(t, ctx)));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
for (const t of taskGroup)
|
|
107
|
+
await runTask(t, ctx);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
103
110
|
await callHook(suite, 'afterAll', [suite]);
|
|
104
111
|
}
|
|
105
112
|
catch (e) {
|
|
@@ -110,6 +117,25 @@ export async function runSuite(suite, ctx) {
|
|
|
110
117
|
}
|
|
111
118
|
await ((_b = reporter.onSuiteEnd) === null || _b === void 0 ? void 0 : _b.call(reporter, suite, ctx));
|
|
112
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Partition consecutive serial and concurrent tasks in groups
|
|
122
|
+
*/
|
|
123
|
+
function partitionTasks(tasks) {
|
|
124
|
+
let taskGroup = [];
|
|
125
|
+
const groupedTasks = [];
|
|
126
|
+
for (const task of tasks) {
|
|
127
|
+
if (taskGroup.length === 0 || !!task.concurrent === !!taskGroup[0].concurrent) {
|
|
128
|
+
taskGroup.push(task);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
groupedTasks.push(taskGroup);
|
|
132
|
+
taskGroup = [task];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (taskGroup.length > 0)
|
|
136
|
+
groupedTasks.push(taskGroup);
|
|
137
|
+
return groupedTasks;
|
|
138
|
+
}
|
|
113
139
|
export async function runFile(file, ctx) {
|
|
114
140
|
var _a, _b;
|
|
115
141
|
const { reporter } = ctx;
|
package/dist/suite.d.ts
CHANGED
|
@@ -2,9 +2,24 @@ import { SuiteCollector, TestFactory, TestFunction, Suite } from './types';
|
|
|
2
2
|
export declare const defaultSuite: SuiteCollector;
|
|
3
3
|
export declare const test: {
|
|
4
4
|
(name: string, fn: TestFunction): void;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
concurrent: {
|
|
6
|
+
(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
7
|
+
skip(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
8
|
+
only(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
9
|
+
todo(name: string): void;
|
|
10
|
+
};
|
|
11
|
+
skip: {
|
|
12
|
+
(name: string, fn: TestFunction): void;
|
|
13
|
+
concurrent(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
14
|
+
};
|
|
15
|
+
only: {
|
|
16
|
+
(name: string, fn: TestFunction): void;
|
|
17
|
+
concurrent(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
18
|
+
};
|
|
19
|
+
todo: {
|
|
20
|
+
(name: string): void;
|
|
21
|
+
concurrent(name: string): void;
|
|
22
|
+
};
|
|
8
23
|
};
|
|
9
24
|
export declare function suite(suiteName: string, factory?: TestFactory): SuiteCollector;
|
|
10
25
|
export declare namespace suite {
|
|
@@ -15,9 +30,24 @@ export declare namespace suite {
|
|
|
15
30
|
export declare const describe: typeof suite;
|
|
16
31
|
export declare const it: {
|
|
17
32
|
(name: string, fn: TestFunction): void;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
33
|
+
concurrent: {
|
|
34
|
+
(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
35
|
+
skip(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
36
|
+
only(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
37
|
+
todo(name: string): void;
|
|
38
|
+
};
|
|
39
|
+
skip: {
|
|
40
|
+
(name: string, fn: TestFunction): void;
|
|
41
|
+
concurrent(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
42
|
+
};
|
|
43
|
+
only: {
|
|
44
|
+
(name: string, fn: TestFunction): void;
|
|
45
|
+
concurrent(name: string, fn: TestFunction, timeout?: number | undefined): void;
|
|
46
|
+
};
|
|
47
|
+
todo: {
|
|
48
|
+
(name: string): void;
|
|
49
|
+
concurrent(name: string): void;
|
|
50
|
+
};
|
|
21
51
|
};
|
|
22
52
|
export declare const beforeAll: (fn: Suite['hooks']['beforeAll'][0]) => void;
|
|
23
53
|
export declare const afterAll: (fn: Suite['hooks']['afterAll'][0]) => void;
|
package/dist/suite.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { context } from './context';
|
|
2
|
+
import { defaultConcurrentTimeout } from './constants';
|
|
2
3
|
export const defaultSuite = suite('');
|
|
3
4
|
function getCurrentSuite() {
|
|
4
5
|
return context.currentSuite || defaultSuite;
|
|
@@ -16,6 +17,16 @@ function createSuiteCollector(name, factory = () => { }, mode) {
|
|
|
16
17
|
afterEach: [],
|
|
17
18
|
},
|
|
18
19
|
};
|
|
20
|
+
const test = createTestCollector((name, fn, mode, concurrent) => {
|
|
21
|
+
queue.push({
|
|
22
|
+
name,
|
|
23
|
+
mode,
|
|
24
|
+
concurrent,
|
|
25
|
+
suite: {},
|
|
26
|
+
state: (mode !== 'run' && mode !== 'only') ? mode : undefined,
|
|
27
|
+
fn,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
19
30
|
const collector = {
|
|
20
31
|
name,
|
|
21
32
|
mode,
|
|
@@ -27,21 +38,6 @@ function createSuiteCollector(name, factory = () => { }, mode) {
|
|
|
27
38
|
function addHook(name, ...fn) {
|
|
28
39
|
suiteBase.hooks[name].push(...fn);
|
|
29
40
|
}
|
|
30
|
-
function collectTask(name, fn, mode) {
|
|
31
|
-
queue.push({
|
|
32
|
-
name,
|
|
33
|
-
mode,
|
|
34
|
-
suite: {},
|
|
35
|
-
state: (mode !== 'run' && mode !== 'only') ? mode : undefined,
|
|
36
|
-
fn,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function test(name, fn) {
|
|
40
|
-
collectTask(name, fn, 'run');
|
|
41
|
-
}
|
|
42
|
-
test.skip = (name, fn) => collectTask(name, fn, 'skip');
|
|
43
|
-
test.only = (name, fn) => collectTask(name, fn, 'only');
|
|
44
|
-
test.todo = (name) => collectTask(name, () => { }, 'todo');
|
|
45
41
|
function clear() {
|
|
46
42
|
queue.length = 0;
|
|
47
43
|
factoryQueue.length = 0;
|
|
@@ -64,11 +60,66 @@ function createSuiteCollector(name, factory = () => { }, mode) {
|
|
|
64
60
|
context.suites.push(collector);
|
|
65
61
|
return collector;
|
|
66
62
|
}
|
|
63
|
+
function createConcurrentOptions(timeout) {
|
|
64
|
+
return { timeout: timeout !== null && timeout !== void 0 ? timeout : defaultConcurrentTimeout };
|
|
65
|
+
}
|
|
66
|
+
function createTestCollector(collectTask) {
|
|
67
|
+
function test(name, fn) {
|
|
68
|
+
collectTask(name, fn, 'run');
|
|
69
|
+
}
|
|
70
|
+
test.concurrent = concurrent;
|
|
71
|
+
test.skip = skip;
|
|
72
|
+
test.only = only;
|
|
73
|
+
test.todo = todo;
|
|
74
|
+
function concurrent(name, fn, timeout) {
|
|
75
|
+
collectTask(name, fn, 'run', createConcurrentOptions(timeout));
|
|
76
|
+
}
|
|
77
|
+
concurrent.skip = (name, fn, timeout) => collectTask(name, fn, 'skip', createConcurrentOptions(timeout));
|
|
78
|
+
concurrent.only = (name, fn, timeout) => collectTask(name, fn, 'only', createConcurrentOptions(timeout));
|
|
79
|
+
concurrent.todo = todo;
|
|
80
|
+
function skip(name, fn) {
|
|
81
|
+
collectTask(name, fn, 'skip');
|
|
82
|
+
}
|
|
83
|
+
skip.concurrent = concurrent.skip;
|
|
84
|
+
function only(name, fn) {
|
|
85
|
+
collectTask(name, fn, 'only');
|
|
86
|
+
}
|
|
87
|
+
only.concurrent = concurrent.only;
|
|
88
|
+
function todo(name) {
|
|
89
|
+
collectTask(name, () => { }, 'todo');
|
|
90
|
+
}
|
|
91
|
+
todo.concurrent = todo;
|
|
92
|
+
return test;
|
|
93
|
+
}
|
|
67
94
|
// apis
|
|
68
|
-
export const test = (
|
|
69
|
-
test
|
|
70
|
-
|
|
71
|
-
|
|
95
|
+
export const test = (function () {
|
|
96
|
+
function test(name, fn) {
|
|
97
|
+
return getCurrentSuite().test(name, fn);
|
|
98
|
+
}
|
|
99
|
+
function concurrent(name, fn, timeout) {
|
|
100
|
+
return getCurrentSuite().test.concurrent(name, fn, timeout);
|
|
101
|
+
}
|
|
102
|
+
concurrent.skip = (name, fn, timeout) => getCurrentSuite().test.concurrent.skip(name, fn, timeout);
|
|
103
|
+
concurrent.only = (name, fn, timeout) => getCurrentSuite().test.concurrent.only(name, fn, timeout);
|
|
104
|
+
concurrent.todo = (name) => getCurrentSuite().test.concurrent.todo(name);
|
|
105
|
+
function skip(name, fn) {
|
|
106
|
+
return getCurrentSuite().test.skip(name, fn);
|
|
107
|
+
}
|
|
108
|
+
skip.concurrent = (name, fn, timeout) => getCurrentSuite().test.skip.concurrent(name, fn, timeout);
|
|
109
|
+
function only(name, fn) {
|
|
110
|
+
return getCurrentSuite().test.only(name, fn);
|
|
111
|
+
}
|
|
112
|
+
only.concurrent = (name, fn, timeout) => getCurrentSuite().test.only.concurrent(name, fn, timeout);
|
|
113
|
+
function todo(name) {
|
|
114
|
+
return getCurrentSuite().test.todo(name);
|
|
115
|
+
}
|
|
116
|
+
todo.concurrent = (name) => getCurrentSuite().test.todo.concurrent(name);
|
|
117
|
+
test.concurrent = concurrent;
|
|
118
|
+
test.skip = skip;
|
|
119
|
+
test.only = only;
|
|
120
|
+
test.todo = todo;
|
|
121
|
+
return test;
|
|
122
|
+
})();
|
|
72
123
|
export function suite(suiteName, factory) {
|
|
73
124
|
return createSuiteCollector(suiteName, factory, 'run');
|
|
74
125
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -64,9 +64,13 @@ export interface ResolvedConfig extends Required<UserOptions> {
|
|
|
64
64
|
}
|
|
65
65
|
export declare type RunMode = 'run' | 'skip' | 'only' | 'todo';
|
|
66
66
|
export declare type TaskState = RunMode | 'pass' | 'fail';
|
|
67
|
+
export interface ConcurrentOptions {
|
|
68
|
+
timeout: number;
|
|
69
|
+
}
|
|
67
70
|
export interface Task {
|
|
68
71
|
name: string;
|
|
69
72
|
mode: RunMode;
|
|
73
|
+
concurrent?: ConcurrentOptions;
|
|
70
74
|
suite: Suite;
|
|
71
75
|
fn: () => Awaitable<void>;
|
|
72
76
|
file?: File;
|
|
@@ -74,11 +78,30 @@ export interface Task {
|
|
|
74
78
|
error?: unknown;
|
|
75
79
|
}
|
|
76
80
|
export declare type TestFunction = () => Awaitable<void>;
|
|
81
|
+
interface ConcurrentCollector {
|
|
82
|
+
(name: string, fn: TestFunction, timeout?: number): void;
|
|
83
|
+
only: (name: string, fn: TestFunction, timeout?: number) => void;
|
|
84
|
+
skip: (name: string, fn: TestFunction, timeout?: number) => void;
|
|
85
|
+
todo: (name: string) => void;
|
|
86
|
+
}
|
|
87
|
+
interface OnlyCollector {
|
|
88
|
+
(name: string, fn: TestFunction): void;
|
|
89
|
+
concurrent: (name: string, fn: TestFunction, timeout?: number) => void;
|
|
90
|
+
}
|
|
91
|
+
interface SkipCollector {
|
|
92
|
+
(name: string, fn: TestFunction): void;
|
|
93
|
+
concurrent: (name: string, fn: TestFunction, timeout?: number) => void;
|
|
94
|
+
}
|
|
95
|
+
interface TodoCollector {
|
|
96
|
+
(name: string): void;
|
|
97
|
+
concurrent: (name: string) => void;
|
|
98
|
+
}
|
|
77
99
|
export interface TestCollector {
|
|
78
100
|
(name: string, fn: TestFunction): void;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
101
|
+
concurrent: ConcurrentCollector;
|
|
102
|
+
only: OnlyCollector;
|
|
103
|
+
skip: SkipCollector;
|
|
104
|
+
todo: TodoCollector;
|
|
82
105
|
}
|
|
83
106
|
export declare type HookListener<T extends any[]> = (...args: T) => Awaitable<void>;
|
|
84
107
|
export interface Suite {
|
|
@@ -136,3 +159,4 @@ export interface Reporter {
|
|
|
136
159
|
onWatcherStart?: (ctx: RunnerContext) => Awaitable<void>;
|
|
137
160
|
onWatcherRerun?: (files: string[], trigger: string, ctx: RunnerContext) => Awaitable<void>;
|
|
138
161
|
}
|
|
162
|
+
export {};
|