vitest 0.0.21 → 0.0.25

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.
@@ -5,6 +5,7 @@ import vm from 'vm';
5
5
  import { createServer, mergeConfig } from 'vite';
6
6
  import c from 'picocolors';
7
7
  const { red, dim, yellow } = c;
8
+ const __pendingModules__ = new Map();
8
9
  export async function run(argv) {
9
10
  process.exitCode = 0;
10
11
  const root = argv.root || process.cwd();
@@ -19,9 +20,9 @@ export async function run(argv) {
19
20
  resolve: {},
20
21
  }));
21
22
  await server.pluginContainer.buildStart({});
22
- // @ts-expect-error
23
23
  process.__vite_node__ = {
24
24
  server,
25
+ moduleCache: __pendingModules__,
25
26
  };
26
27
  try {
27
28
  await execute(files, server, argv);
@@ -31,7 +32,8 @@ export async function run(argv) {
31
32
  throw e;
32
33
  }
33
34
  finally {
34
- await server.close();
35
+ if (!process.__vite_node__.watch)
36
+ await server.close();
35
37
  }
36
38
  }
37
39
  function normalizeId(id) {
@@ -47,7 +49,9 @@ function toFilePath(id, server) {
47
49
  ? id.slice(4)
48
50
  : id.startsWith(dirname(server.config.root))
49
51
  ? id
50
- : slash(resolve(server.config.root, id.slice(1)));
52
+ : id.startsWith('/')
53
+ ? slash(resolve(server.config.root, id.slice(1)))
54
+ : id;
51
55
  if (absolute.startsWith('//'))
52
56
  absolute = absolute.slice(1);
53
57
  if (!absolute.startsWith('/'))
@@ -55,15 +59,12 @@ function toFilePath(id, server) {
55
59
  return absolute;
56
60
  }
57
61
  async function execute(files, server, options) {
58
- const __pendingModules__ = new Map();
59
62
  const result = [];
60
63
  for (const file of files)
61
64
  result.push(await cachedRequest(`/@fs/${slash(resolve(file))}`, []));
62
65
  return result;
63
- async function directRequest(rawId, callstack) {
64
- if (builtinModules.includes(rawId))
65
- return import(rawId);
66
- callstack = [...callstack, rawId];
66
+ async function directRequest(id, fsPath, callstack) {
67
+ callstack = [...callstack, id];
67
68
  const request = async (dep) => {
68
69
  if (callstack.includes(dep)) {
69
70
  throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => {
@@ -73,19 +74,15 @@ async function execute(files, server, options) {
73
74
  }
74
75
  return cachedRequest(dep, callstack);
75
76
  };
76
- const id = normalizeId(rawId);
77
- const absolute = toFilePath(id, server);
78
- if (options.shouldExternalize(absolute))
79
- return import(absolute);
80
77
  const result = await server.transformRequest(id, { ssr: true });
81
78
  if (!result)
82
79
  throw new Error(`failed to load ${id}`);
83
- const url = pathToFileURL(absolute);
80
+ const url = pathToFileURL(fsPath);
84
81
  const exports = {};
85
82
  const context = {
86
83
  require: createRequire(url),
87
- __filename: absolute,
88
- __dirname: dirname(absolute),
84
+ __filename: fsPath,
85
+ __dirname: dirname(fsPath),
89
86
  __vite_ssr_import__: request,
90
87
  __vite_ssr_dynamic_import__: request,
91
88
  __vite_ssr_exports__: exports,
@@ -93,17 +90,23 @@ async function execute(files, server, options) {
93
90
  __vite_ssr_import_meta__: { url },
94
91
  };
95
92
  const fn = vm.runInThisContext(`async (${Object.keys(context).join(',')}) => { ${result.code} }`, {
96
- filename: absolute,
93
+ filename: fsPath,
97
94
  lineOffset: 0,
98
95
  });
99
96
  await fn(...Object.values(context));
100
97
  return exports;
101
98
  }
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);
99
+ async function cachedRequest(rawId, callstack) {
100
+ if (builtinModules.includes(rawId))
101
+ return import(rawId);
102
+ const id = normalizeId(rawId);
103
+ const fsPath = toFilePath(id, server);
104
+ if (options.shouldExternalize(fsPath))
105
+ return import(fsPath);
106
+ if (__pendingModules__.has(fsPath))
107
+ return __pendingModules__.get(fsPath);
108
+ __pendingModules__.set(fsPath, directRequest(id, fsPath, callstack));
109
+ return await __pendingModules__.get(fsPath);
107
110
  }
108
111
  function exportAll(exports, sourceModule) {
109
112
  // eslint-disable-next-line no-restricted-syntax
@@ -1,24 +1,21 @@
1
1
  import Listr from 'listr';
2
- import { Reporter, RunnerContext, Task } from '../types';
2
+ import { File, Reporter, RunnerContext, Task } from '../types';
3
3
  interface TaskPromise {
4
4
  promise: Promise<void>;
5
5
  resolve: () => void;
6
6
  reject: (e: unknown) => void;
7
7
  }
8
8
  export declare class DefaultReporter implements Reporter {
9
- indent: number;
10
9
  start: number;
11
10
  end: number;
12
11
  listr: Listr | null;
13
12
  listrPromise: Promise<void> | null;
14
13
  taskMap: Map<Task, TaskPromise>;
15
- onStart(): void;
16
- onCollected(ctx: RunnerContext): void;
14
+ onCollected(files: File[]): void;
17
15
  onTaskEnd(task: Task): void;
18
- onFinished({ files }: RunnerContext): Promise<void>;
19
- private getIndent;
20
- private log;
21
- private error;
16
+ onFinished(ctx: RunnerContext): Promise<void>;
17
+ onWatcherStart(ctx: RunnerContext): Promise<void>;
18
+ onWatcherRerun(files: string[], trigger: string): Promise<void>;
22
19
  onSnapshotUpdate(): void;
23
20
  }
24
21
  export {};
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  import { performance } from 'perf_hooks';
2
3
  import { relative } from 'path';
3
4
  import c from 'picocolors';
@@ -5,20 +6,16 @@ import Listr from 'listr';
5
6
  const CROSS = '✖ ';
6
7
  export class DefaultReporter {
7
8
  constructor() {
8
- this.indent = 0;
9
9
  this.start = 0;
10
10
  this.end = 0;
11
11
  this.listr = null;
12
12
  this.listrPromise = null;
13
13
  this.taskMap = new Map();
14
14
  }
15
- onStart() {
16
- this.indent = 0;
17
- }
18
- onCollected(ctx) {
15
+ onCollected(files) {
19
16
  this.start = performance.now();
20
17
  this.taskMap = new Map();
21
- const tasks = ctx.files.reduce((acc, file) => acc.concat(file.suites.flatMap(i => i.tasks)), []);
18
+ const tasks = files.reduce((acc, file) => acc.concat(file.suites.flatMap(i => i.tasks)), []);
22
19
  tasks.forEach((t) => {
23
20
  const obj = {};
24
21
  obj.promise = new Promise((resolve, reject) => {
@@ -42,7 +39,7 @@ export class DefaultReporter {
42
39
  const listrOptions = {
43
40
  exitOnError: false,
44
41
  };
45
- this.listr = new Listr(ctx.files.map((file) => {
42
+ this.listr = new Listr(files.map((file) => {
46
43
  return {
47
44
  title: relative(process.cwd(), file.filepath),
48
45
  task: () => {
@@ -67,66 +64,67 @@ export class DefaultReporter {
67
64
  else
68
65
  (_b = this.taskMap.get(task)) === null || _b === void 0 ? void 0 : _b.resolve();
69
66
  }
70
- async onFinished({ files }) {
67
+ async onFinished(ctx) {
71
68
  await this.listrPromise;
72
- this.log();
73
69
  this.end = performance.now();
74
- const suites = files.reduce((acc, file) => acc.concat(file.suites), []);
75
- const tasks = files.reduce((acc, file) => acc.concat(file.suites.flatMap(i => i.tasks)), []);
70
+ console.log();
71
+ const { tasks, suites, files } = ctx;
76
72
  const failedFiles = files.filter(i => i.error);
77
73
  const failedSuites = suites.filter(i => i.error);
78
- const runable = tasks.filter(i => i.state === 'pass' || i.state === 'fail');
74
+ const runnable = tasks.filter(i => i.state === 'pass' || i.state === 'fail');
79
75
  const passed = tasks.filter(i => i.state === 'pass');
80
76
  const failed = tasks.filter(i => i.state === 'fail');
81
77
  const skipped = tasks.filter(i => i.state === 'skip');
82
78
  const todo = tasks.filter(i => i.state === 'todo');
83
- this.indent = 0;
84
79
  if (failedFiles.length) {
85
- this.error(c.bold(`\nFailed to parse ${failedFiles.length} files:`));
80
+ console.error(c.bold(`\nFailed to parse ${failedFiles.length} files:`));
86
81
  failedFiles.forEach((i) => {
87
- this.error(`\n- ${i.filepath}`);
82
+ console.error(c.red(`\n- ${i.filepath}`));
88
83
  console.error(i.error || 'Unknown error');
89
- this.log();
84
+ console.log();
90
85
  });
91
86
  }
92
87
  if (failedSuites.length) {
93
- this.error(c.bold(`\nFailed to run ${failedSuites.length} suites:`));
88
+ console.error(c.bold(c.red(`\nFailed to run ${failedSuites.length} suites:`)));
94
89
  failedSuites.forEach((i) => {
95
90
  var _a;
96
- this.error(`\n- ${(_a = i.file) === null || _a === void 0 ? void 0 : _a.filepath} > ${i.name}`);
91
+ console.error(c.red(`\n- ${(_a = i.file) === null || _a === void 0 ? void 0 : _a.filepath} > ${i.name}`));
97
92
  console.error(i.error || 'Unknown error');
98
- this.log();
93
+ console.log();
99
94
  });
100
95
  }
101
96
  if (failed.length) {
102
- this.error(c.bold(`\nFailed Tests (${failed.length})`));
97
+ console.error(c.bold(c.red(`\nFailed Tests (${failed.length})`)));
103
98
  failed.forEach((task) => {
104
99
  var _a;
105
- this.error(`\n${CROSS + c.inverse(c.red(' FAIL '))} ${[task.suite.name, task.name].filter(Boolean).join(' > ')} ${c.gray(c.dim(`${(_a = task.file) === null || _a === void 0 ? void 0 : _a.filepath}`))}`);
100
+ console.error(`\n${CROSS + c.inverse(c.red(' FAIL '))} ${[task.suite.name, task.name].filter(Boolean).join(' > ')} ${c.gray(c.dim(`${(_a = task.file) === null || _a === void 0 ? void 0 : _a.filepath}`))}`);
106
101
  console.error(task.error || 'Unknown error');
107
- this.log();
102
+ console.log();
108
103
  });
109
104
  }
110
- this.log(c.bold(c.green(`Passed ${passed.length} / ${runable.length}`)));
105
+ console.log(c.bold(c.green(`Passed ${passed.length} / ${runnable.length}`)));
111
106
  if (failed.length)
112
- this.log(c.bold(c.red(`Failed ${failed.length} / ${runable.length}`)));
107
+ console.log(c.bold(c.red(`Failed ${failed.length} / ${runnable.length}`)));
113
108
  if (skipped.length)
114
- this.log(c.yellow(`Skipped ${skipped.length}`));
109
+ console.log(c.yellow(`Skipped ${skipped.length}`));
115
110
  if (todo.length)
116
- this.log(c.dim(`Todo ${todo.length}`));
117
- this.log(`Time ${(this.end - this.start).toFixed(2)}ms`);
118
- }
119
- getIndent(offest = 0) {
120
- return ' '.repeat((this.indent + offest) * 2);
111
+ console.log(c.dim(`Todo ${todo.length}`));
112
+ console.log(`Time ${(this.end - this.start).toFixed(2)}ms`);
121
113
  }
122
- log(msg = '', indentOffset = 0) {
123
- // eslint-disable-next-line no-console
124
- console.log(`${this.getIndent(indentOffset)}${msg}`);
114
+ async onWatcherStart(ctx) {
115
+ await this.listrPromise;
116
+ const failed = ctx.tasks.filter(i => i.state === 'fail');
117
+ if (failed.length)
118
+ console.log(`\n${c.bold(c.inverse(c.red(' FAIL ')))}${c.red(` ${failed.length} tests failed. Watching for file changes...`)}`);
119
+ else
120
+ console.log(`\n${c.bold(c.inverse(c.green(' PASS ')))}${c.green(' Watching for file changes...')}`);
125
121
  }
126
- error(msg = '', indentOffset = 0) {
127
- // eslint-disable-next-line no-console
128
- console.error(c.red(`${this.getIndent(indentOffset)}${msg}`));
122
+ async onWatcherRerun(files, trigger) {
123
+ await this.listrPromise;
124
+ console.clear();
125
+ console.log(c.blue('Re-running tests...') + c.dim(` [ ${relative(process.cwd(), trigger)} ]\n`));
129
126
  }
127
+ // TODO:
130
128
  onSnapshotUpdate() {
131
129
  }
132
130
  }
@@ -0,0 +1,8 @@
1
+ import { File, ResolvedConfig, Task, RunnerContext, Suite } from '../types';
2
+ export declare function runTask(task: Task, ctx: RunnerContext): Promise<void>;
3
+ export declare function collectFiles(paths: string[]): Promise<Record<string, File>>;
4
+ export declare function runSuite(suite: Suite, ctx: RunnerContext): Promise<void>;
5
+ export declare function runFile(file: File, ctx: RunnerContext): Promise<void>;
6
+ export declare function runFiles(filesMap: Record<string, File>, ctx: RunnerContext): Promise<void>;
7
+ export declare function run(config: ResolvedConfig): Promise<void>;
8
+ export declare function startWatcher(ctx: RunnerContext): Promise<void>;
@@ -0,0 +1,240 @@
1
+ import fg from 'fast-glob';
2
+ import { setupChai } from '../integrations/chai/setup';
3
+ import { clearContext, defaultSuite } from '../suite';
4
+ import { context } from '../context';
5
+ import { DefaultReporter } from '../reporters/default';
6
+ import { defaultIncludes, defaultExcludes } from '../constants';
7
+ import { getSnapshotManager } from '../integrations/chai/snapshot';
8
+ async function callHook(suite, name, args) {
9
+ await Promise.all(suite.hooks[name].map(fn => fn(...args)));
10
+ }
11
+ export async function runTask(task, ctx) {
12
+ var _a, _b, _c;
13
+ const { reporter } = ctx;
14
+ (_a = getSnapshotManager()) === null || _a === void 0 ? void 0 : _a.setTask(task);
15
+ await ((_b = reporter.onTaskBegin) === null || _b === void 0 ? void 0 : _b.call(reporter, task, ctx));
16
+ if (task.mode === 'run') {
17
+ try {
18
+ await callHook(task.suite, 'beforeEach', [task, task.suite]);
19
+ await task.fn();
20
+ task.state = 'pass';
21
+ }
22
+ catch (e) {
23
+ task.state = 'fail';
24
+ task.error = e;
25
+ process.exitCode = 1;
26
+ }
27
+ try {
28
+ await callHook(task.suite, 'afterEach', [task, task.suite]);
29
+ }
30
+ catch (e) {
31
+ task.state = 'fail';
32
+ task.error = e;
33
+ process.exitCode = 1;
34
+ }
35
+ }
36
+ await ((_c = reporter.onTaskEnd) === null || _c === void 0 ? void 0 : _c.call(reporter, task, ctx));
37
+ }
38
+ export async function collectFiles(paths) {
39
+ const files = {};
40
+ for (const filepath of paths) {
41
+ const file = {
42
+ filepath,
43
+ suites: [],
44
+ collected: false,
45
+ };
46
+ clearContext();
47
+ try {
48
+ await import(filepath);
49
+ const collectors = [defaultSuite, ...context.suites];
50
+ for (const c of collectors) {
51
+ context.currentSuite = c;
52
+ file.suites.push(await c.collect(file));
53
+ }
54
+ file.collected = true;
55
+ }
56
+ catch (e) {
57
+ file.error = e;
58
+ file.collected = false;
59
+ process.exitCode = 1;
60
+ }
61
+ files[filepath] = file;
62
+ }
63
+ const allFiles = Object.values(files);
64
+ const allSuites = allFiles.reduce((suites, file) => suites.concat(file.suites), []);
65
+ interpretOnlyMode(allSuites);
66
+ allSuites.forEach((i) => {
67
+ if (i.mode === 'skip')
68
+ i.tasks.forEach(t => t.mode === 'run' && (t.mode = 'skip'));
69
+ else
70
+ interpretOnlyMode(i.tasks);
71
+ i.tasks.forEach(t => t.mode === 'skip' && (t.state = 'skip'));
72
+ });
73
+ return files;
74
+ }
75
+ /**
76
+ * If any items been marked as `only`, mark all other items as `skip`.
77
+ */
78
+ function interpretOnlyMode(items) {
79
+ if (items.some(i => i.mode === 'only')) {
80
+ items.forEach((i) => {
81
+ if (i.mode === 'run')
82
+ i.mode = 'skip';
83
+ else if (i.mode === 'only')
84
+ i.mode = 'run';
85
+ });
86
+ }
87
+ }
88
+ export async function runSuite(suite, ctx) {
89
+ var _a, _b;
90
+ const { reporter } = ctx;
91
+ await ((_a = reporter.onSuiteBegin) === null || _a === void 0 ? void 0 : _a.call(reporter, suite, ctx));
92
+ if (suite.mode === 'skip') {
93
+ suite.status = 'skip';
94
+ }
95
+ else if (suite.mode === 'todo') {
96
+ suite.status = 'todo';
97
+ }
98
+ else {
99
+ try {
100
+ await callHook(suite, 'beforeAll', [suite]);
101
+ await Promise.all(suite.tasks.map(i => runTask(i, ctx)));
102
+ // for (const t of suite.tasks)
103
+ // await runTask(t, ctx)
104
+ await callHook(suite, 'afterAll', [suite]);
105
+ }
106
+ catch (e) {
107
+ suite.error = e;
108
+ suite.status = 'fail';
109
+ process.exitCode = 1;
110
+ }
111
+ }
112
+ await ((_b = reporter.onSuiteEnd) === null || _b === void 0 ? void 0 : _b.call(reporter, suite, ctx));
113
+ }
114
+ export async function runFile(file, ctx) {
115
+ var _a, _b;
116
+ const { reporter } = ctx;
117
+ const runnableSuites = file.suites.filter(i => i.mode === 'run');
118
+ if (runnableSuites.length === 0)
119
+ return;
120
+ await ((_a = reporter.onFileBegin) === null || _a === void 0 ? void 0 : _a.call(reporter, file, ctx));
121
+ if (ctx.config.parallel) {
122
+ await Promise.all(file.suites.map(suite => runSuite(suite, ctx)));
123
+ }
124
+ else {
125
+ for (const suite of file.suites)
126
+ await runSuite(suite, ctx);
127
+ }
128
+ await ((_b = reporter.onFileEnd) === null || _b === void 0 ? void 0 : _b.call(reporter, file, ctx));
129
+ }
130
+ export async function runFiles(filesMap, ctx) {
131
+ var _a;
132
+ const { reporter } = ctx;
133
+ await ((_a = reporter.onCollected) === null || _a === void 0 ? void 0 : _a.call(reporter, Object.values(filesMap), ctx));
134
+ for (const file of Object.values(filesMap))
135
+ await runFile(file, ctx);
136
+ }
137
+ export async function run(config) {
138
+ var _a, _b, _c;
139
+ config.reporter = config.reporter || new DefaultReporter();
140
+ const { reporter } = config;
141
+ // if watch, tell `vite-node` not to end the process
142
+ if (config.watch)
143
+ process.__vite_node__.watch = true;
144
+ // setup chai
145
+ await setupChai(config);
146
+ // collect files
147
+ let testFilepaths = await fg(config.includes || defaultIncludes, {
148
+ absolute: true,
149
+ cwd: config.root,
150
+ ignore: config.excludes || defaultExcludes,
151
+ });
152
+ // if name filters are provided by the CLI
153
+ if ((_a = config.filters) === null || _a === void 0 ? void 0 : _a.length)
154
+ testFilepaths = testFilepaths.filter(i => config.filters.some(f => i.includes(f)));
155
+ if (!testFilepaths.length) {
156
+ console.error('No test files found');
157
+ process.exitCode = 1;
158
+ return;
159
+ }
160
+ // setup envs
161
+ if (config.global)
162
+ (await import('../integrations/global')).registerApiGlobally();
163
+ if (config.jsdom)
164
+ (await import('../integrations/jsdom')).setupJSDOM(globalThis);
165
+ await ((_b = reporter.onStart) === null || _b === void 0 ? void 0 : _b.call(reporter, config));
166
+ const filesMap = await collectFiles(testFilepaths);
167
+ const ctx = {
168
+ filesMap,
169
+ get files() {
170
+ return Object.values(this.filesMap);
171
+ },
172
+ get suites() {
173
+ return Object.values(this.filesMap)
174
+ .reduce((suites, file) => suites.concat(file.suites), []);
175
+ },
176
+ get tasks() {
177
+ return this.suites
178
+ .reduce((tasks, suite) => tasks.concat(suite.tasks), []);
179
+ },
180
+ config,
181
+ reporter: config.reporter,
182
+ };
183
+ await runFiles(filesMap, ctx);
184
+ const snapshot = getSnapshotManager();
185
+ snapshot === null || snapshot === void 0 ? void 0 : snapshot.saveSnap();
186
+ snapshot === null || snapshot === void 0 ? void 0 : snapshot.report();
187
+ await ((_c = reporter.onFinished) === null || _c === void 0 ? void 0 : _c.call(reporter, ctx));
188
+ if (config.watch)
189
+ startWatcher(ctx);
190
+ }
191
+ export async function startWatcher(ctx) {
192
+ var _a, _b;
193
+ await ((_b = (_a = ctx.reporter).onWatcherStart) === null || _b === void 0 ? void 0 : _b.call(_a, ctx));
194
+ let timer;
195
+ const changedTests = new Set();
196
+ const seen = new Set();
197
+ const { server, moduleCache } = process.__vite_node__;
198
+ server.watcher.on('change', async (id) => {
199
+ getDependencyTests(id, ctx, changedTests, seen);
200
+ seen.forEach(i => moduleCache.delete(i));
201
+ seen.clear();
202
+ if (changedTests.size === 0)
203
+ return;
204
+ clearTimeout(timer);
205
+ timer = setTimeout(async () => {
206
+ var _a, _b, _c, _d;
207
+ if (changedTests.size === 0)
208
+ return;
209
+ const snapshot = getSnapshotManager();
210
+ const paths = Array.from(changedTests);
211
+ changedTests.clear();
212
+ await ((_b = (_a = ctx.reporter).onWatcherRerun) === null || _b === void 0 ? void 0 : _b.call(_a, paths, id, ctx));
213
+ paths.forEach(i => moduleCache.delete(i));
214
+ const files = await collectFiles(paths);
215
+ Object.assign(ctx.filesMap, files);
216
+ await runFiles(files, ctx);
217
+ // TODO: clear snapshot state
218
+ snapshot === null || snapshot === void 0 ? void 0 : snapshot.saveSnap();
219
+ snapshot === null || snapshot === void 0 ? void 0 : snapshot.report();
220
+ await ((_d = (_c = ctx.reporter).onWatcherStart) === null || _d === void 0 ? void 0 : _d.call(_c, ctx));
221
+ }, 100);
222
+ });
223
+ }
224
+ function getDependencyTests(id, ctx, set = new Set(), seen = new Set()) {
225
+ if (seen.has(id) || set.has(id))
226
+ return set;
227
+ seen.add(id);
228
+ if (id in ctx.filesMap) {
229
+ set.add(id);
230
+ return set;
231
+ }
232
+ const mod = process.__vite_node__.server.moduleGraph.getModuleById(id);
233
+ if (mod) {
234
+ mod.importers.forEach((i) => {
235
+ if (i.id)
236
+ getDependencyTests(i.id, ctx, set, seen);
237
+ });
238
+ }
239
+ return set;
240
+ }
package/dist/suite.js CHANGED
@@ -32,12 +32,12 @@ function createSuiteCollector(name, factory = () => { }, mode) {
32
32
  name,
33
33
  mode,
34
34
  suite: {},
35
- state: mode !== 'run' ? mode : undefined,
35
+ state: (mode !== 'run' && mode !== 'only') ? mode : undefined,
36
36
  fn,
37
37
  });
38
38
  }
39
39
  function test(name, fn) {
40
- collectTask(name, fn, mode);
40
+ collectTask(name, fn, 'run');
41
41
  }
42
42
  test.skip = (name, fn) => collectTask(name, fn, 'skip');
43
43
  test.only = (name, fn) => collectTask(name, fn, 'only');
package/dist/types.d.ts CHANGED
@@ -1,7 +1,15 @@
1
- import { ViteDevServer } from 'vite';
2
1
  export declare type Awaitable<T> = Promise<T> | T;
3
2
  export interface UserOptions {
3
+ /**
4
+ * Include globs for test files
5
+ *
6
+ * @default ['**\/*.test.ts']
7
+ */
4
8
  includes?: string[];
9
+ /**
10
+ * Exclude globs for test files
11
+ * @default ['**\/node_modules\/**']
12
+ */
5
13
  excludes?: string[];
6
14
  /**
7
15
  * Register apis globally
@@ -21,13 +29,29 @@ export interface UserOptions {
21
29
  * @default false
22
30
  */
23
31
  parallel?: boolean;
24
- }
25
- export interface Config extends UserOptions {
26
- rootDir?: string;
27
- updateSnapshot?: boolean;
28
- nameFilters?: string[];
29
- server: ViteDevServer;
32
+ /**
33
+ * Update snapshot files
34
+ *
35
+ * @default false
36
+ */
37
+ update?: boolean;
38
+ /**
39
+ * Watch mode
40
+ *
41
+ * @default false
42
+ */
30
43
  watch?: boolean;
44
+ /**
45
+ * Project root
46
+ */
47
+ root?: string;
48
+ /**
49
+ * Custom reporter for output
50
+ */
51
+ reporter?: Reporter;
52
+ }
53
+ export interface ResolvedConfig extends Required<UserOptions> {
54
+ filters?: string[];
31
55
  }
32
56
  export declare type RunMode = 'run' | 'skip' | 'only' | 'todo';
33
57
  export declare type TaskState = RunMode | 'pass' | 'fail';
@@ -78,8 +102,11 @@ export interface File {
78
102
  error?: unknown;
79
103
  }
80
104
  export interface RunnerContext {
105
+ filesMap: Record<string, File>;
81
106
  files: File[];
82
- config: Config;
107
+ suites: Suite[];
108
+ tasks: Task[];
109
+ config: ResolvedConfig;
83
110
  reporter: Reporter;
84
111
  }
85
112
  export interface GlobalContext {
@@ -87,8 +114,8 @@ export interface GlobalContext {
87
114
  currentSuite: SuiteCollector | null;
88
115
  }
89
116
  export interface Reporter {
90
- onStart?: (userOptions: Config) => Awaitable<void>;
91
- onCollected?: (ctx: RunnerContext) => Awaitable<void>;
117
+ onStart?: (userOptions: ResolvedConfig) => Awaitable<void>;
118
+ onCollected?: (files: File[], ctx: RunnerContext) => Awaitable<void>;
92
119
  onFinished?: (ctx: RunnerContext) => Awaitable<void>;
93
120
  onSuiteBegin?: (suite: Suite, ctx: RunnerContext) => Awaitable<void>;
94
121
  onSuiteEnd?: (suite: Suite, ctx: RunnerContext) => Awaitable<void>;
@@ -96,5 +123,7 @@ export interface Reporter {
96
123
  onFileEnd?: (file: File, ctx: RunnerContext) => Awaitable<void>;
97
124
  onTaskBegin?: (task: Task, ctx: RunnerContext) => Awaitable<void>;
98
125
  onTaskEnd?: (task: Task, ctx: RunnerContext) => Awaitable<void>;
126
+ onWatcherStart?: (ctx: RunnerContext) => Awaitable<void>;
127
+ onWatcherRerun?: (files: string[], trigger: string, ctx: RunnerContext) => Awaitable<void>;
99
128
  onSnapshotUpdate?: () => Awaitable<void>;
100
129
  }