@japa/runner 2.1.0 → 2.1.3

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/LICENSE.md CHANGED
@@ -1,9 +1,9 @@
1
- # The MIT License
2
-
3
- Copyright 2022 Harminder Virk, contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
-
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
-
9
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ # The MIT License
2
+
3
+ Copyright 2022 Harminder Virk, contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/build/index.d.ts CHANGED
@@ -1,33 +1,33 @@
1
- import { Test, TestContext, Group, Suite, Runner } from './src/Core';
2
- import { TestExecutor, ReporterContract } from '@japa/core';
3
- import { Config, PluginFn, RunnerHooksHandler, RunnerHooksCleanupHandler } from './src/Contracts';
4
- export { Test, Config, Suite, Runner, Group, PluginFn, TestContext, ReporterContract, RunnerHooksHandler, RunnerHooksCleanupHandler, };
5
- /**
6
- * Configure the tests runner
7
- */
8
- export declare function configure(options: Config): void;
9
- /**
10
- * Process CLI arguments into configuration options. The following
11
- * command line arguments are processed.
12
- *
13
- * * --tests=Specify test titles
14
- * * --tags=Specify test tags
15
- * * --groups=Specify group titles
16
- * * --ignore-tags=Specify negated tags
17
- * * --files=Specify files to match and run
18
- * * --force-exit=Enable/disable force exit
19
- * * --timeout=Define timeout for all the tests
20
- * * -h, --help=Show help
21
- */
22
- export declare function processCliArgs(argv: string[]): Partial<Config>;
23
- /**
24
- * Run japa tests
25
- */
26
- export declare function run(): Promise<void>;
27
- /**
28
- * Add a new test
29
- */
30
- export declare function test(title: string, callback?: TestExecutor<TestContext, undefined>): Test<undefined>;
31
- export declare namespace test {
32
- var group: (title: string, callback: (group: Group) => void) => void;
33
- }
1
+ import { Test, TestContext, Group, Suite, Runner } from './src/Core';
2
+ import { TestExecutor, ReporterContract } from '@japa/core';
3
+ import { Config, PluginFn, RunnerHooksHandler, RunnerHooksCleanupHandler } from './src/Contracts';
4
+ export { Test, Config, Suite, Runner, Group, PluginFn, TestContext, ReporterContract, RunnerHooksHandler, RunnerHooksCleanupHandler, };
5
+ /**
6
+ * Configure the tests runner
7
+ */
8
+ export declare function configure(options: Config): void;
9
+ /**
10
+ * Process CLI arguments into configuration options. The following
11
+ * command line arguments are processed.
12
+ *
13
+ * * --tests=Specify test titles
14
+ * * --tags=Specify test tags
15
+ * * --groups=Specify group titles
16
+ * * --ignore-tags=Specify negated tags
17
+ * * --files=Specify files to match and run
18
+ * * --force-exit=Enable/disable force exit
19
+ * * --timeout=Define timeout for all the tests
20
+ * * -h, --help=Show help
21
+ */
22
+ export declare function processCliArgs(argv: string[]): Partial<Config>;
23
+ /**
24
+ * Run japa tests
25
+ */
26
+ export declare function run(): Promise<void>;
27
+ /**
28
+ * Add a new test
29
+ */
30
+ export declare function test(title: string, callback?: TestExecutor<TestContext, undefined>): Test<undefined>;
31
+ export declare namespace test {
32
+ var group: (title: string, callback: (group: Group) => void) => void;
33
+ }
package/build/index.js CHANGED
@@ -1,182 +1,181 @@
1
- "use strict";
2
- /*
3
- * @japa/runner
4
- *
5
- * (c) Harminder Virk <virk@adonisjs.com>
6
- *
7
- * For the full copyright and license information, please view the LICENSE
8
- * file that was distributed with this source code.
9
- */
10
- var __importDefault = (this && this.__importDefault) || function (mod) {
11
- return (mod && mod.__esModule) ? mod : { "default": mod };
12
- };
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.test = exports.run = exports.processCliArgs = exports.configure = exports.TestContext = exports.Group = exports.Runner = exports.Suite = exports.Test = void 0;
15
- const getopts_1 = __importDefault(require("getopts"));
16
- const path_1 = require("path");
17
- const fast_glob_1 = __importDefault(require("fast-glob"));
18
- const inclusion_1 = __importDefault(require("inclusion"));
19
- const url_1 = require("url");
20
- const hooks_1 = require("@poppinss/hooks");
21
- const package_json_1 = require("./package.json");
22
- const cliui_1 = require("@poppinss/cliui");
23
- const errors_printer_1 = require("@japa/errors-printer");
24
- const Core_1 = require("./src/Core");
25
- Object.defineProperty(exports, "Test", { enumerable: true, get: function () { return Core_1.Test; } });
26
- Object.defineProperty(exports, "TestContext", { enumerable: true, get: function () { return Core_1.TestContext; } });
27
- Object.defineProperty(exports, "Group", { enumerable: true, get: function () { return Core_1.Group; } });
28
- Object.defineProperty(exports, "Suite", { enumerable: true, get: function () { return Core_1.Suite; } });
29
- Object.defineProperty(exports, "Runner", { enumerable: true, get: function () { return Core_1.Runner; } });
30
- const core_1 = require("@japa/core");
31
- /**
32
- * Filtering layers allowed by the refiner
33
- */
34
- const refinerFilteringLayers = ['tests', 'groups', 'tags'];
35
- /**
36
- * Reference to the recently imported file. We pass it to the
37
- * test and the group both
38
- */
39
- let recentlyImportedFile;
40
- /**
41
- * Global timeout for tests. Fetched from runner options or suites
42
- * options
43
- */
44
- let globalTimeout;
45
- /**
46
- * Function to create the test context for the test
47
- */
48
- const getContext = (testInstance) => new Core_1.TestContext(testInstance);
49
- /**
50
- * The global reference to the tests emitter
51
- */
52
- const emitter = new core_1.Emitter();
53
- /**
54
- * Active suite for tests
55
- */
56
- let activeSuite;
57
- /**
58
- * Currently active group
59
- */
60
- let activeGroup;
61
- /**
62
- * Configuration options
63
- */
64
- let runnerOptions;
65
- /**
66
- * Ensure the configure method has been called
67
- */
68
- function ensureIsConfigured(message) {
69
- if (!runnerOptions) {
70
- throw new Error(message);
71
- }
72
- }
73
- /**
74
- * Validate suites filter to ensure a wrong suite is not
75
- * mentioned
76
- */
77
- function validateSuitesFilter() {
78
- if (!('suites' in runnerOptions)) {
79
- return;
80
- }
81
- if (!runnerOptions.filters.suites || !runnerOptions.filters.suites.length) {
82
- return;
83
- }
84
- const suites = runnerOptions.suites.map(({ name }) => name);
85
- const invalidSuites = runnerOptions.filters.suites.filter((suite) => !suites.includes(suite));
86
- if (invalidSuites.length) {
87
- throw new Error(`Unrecognized suite "${invalidSuites[0]}". Make sure to define it in the config first`);
88
- }
89
- }
90
- /**
91
- * Process command line argument into a string value
92
- */
93
- function processAsString(argv, flagName, onMatch) {
94
- const flag = argv[flagName];
95
- if (flag) {
96
- onMatch((Array.isArray(flag) ? flag : flag.split(',')).map((tag) => tag.trim()));
97
- }
98
- }
99
- /**
100
- * Find if the file path matches the files filter array.
101
- * The ending of the file is matched
102
- */
103
- function isFileAllowed(filePath, filters) {
104
- if (!filters.files || !filters.files.length) {
105
- return true;
106
- }
107
- return !!filters.files.find((matcher) => {
108
- if (filePath.endsWith(matcher)) {
109
- return true;
110
- }
111
- return filePath.replace((0, path_1.extname)(filePath), '').endsWith(matcher);
112
- });
113
- }
114
- /**
115
- * Returns "true" when no filters are applied or the name is part
116
- * of the applied filter.
117
- */
118
- function isSuiteAllowed(suite, filters) {
119
- if (!filters.suites || !filters.suites.length) {
120
- return true;
121
- }
122
- return filters.suites.includes(suite.name);
123
- }
124
- /**
125
- * Collect files using the files collector function or by processing
126
- * the glob pattern.
127
- *
128
- * The return value is further filtered against the `--files` filter.
129
- */
130
- async function collectFiles(files) {
131
- if (Array.isArray(files) || typeof files === 'string') {
132
- const collectedFiles = await (0, fast_glob_1.default)(files, {
133
- absolute: true,
134
- onlyFiles: true,
135
- cwd: runnerOptions.cwd,
136
- });
137
- return collectedFiles.filter((file) => isFileAllowed(file, runnerOptions.filters));
138
- }
139
- else if (typeof files === 'function') {
140
- const collectedFiles = await files();
141
- return collectedFiles.filter((file) => isFileAllowed(file, runnerOptions.filters));
142
- }
143
- throw new Error('Invalid value for "files" property. Expected a string, array or a function');
144
- }
145
- /**
146
- * Import test files using the configured importer.
147
- */
148
- async function importFiles(files) {
149
- for (let file of files) {
150
- recentlyImportedFile = file;
151
- await runnerOptions.importer(file);
152
- }
153
- }
154
- /**
155
- * End tests. We wait for the "beforeExit" event when
156
- * forceExit is not set to true
157
- */
158
- async function endTests(runner) {
159
- if (runnerOptions.forceExit) {
160
- await runner.end();
161
- }
162
- else {
163
- return new Promise((resolve) => {
164
- async function beforeExit() {
165
- process.removeListener('beforeExit', beforeExit);
166
- await runner.end();
167
- resolve();
168
- }
169
- process.on('beforeExit', beforeExit);
170
- });
171
- }
172
- }
173
- /**
174
- * Show help output in stdout.
175
- */
176
- function showHelp() {
177
- const green = cliui_1.logger.colors.green.bind(cliui_1.logger.colors);
178
- const grey = cliui_1.logger.colors.grey.bind(cliui_1.logger.colors);
179
- console.log(`@japa/runner v${package_json_1.version}
1
+ "use strict";
2
+ /*
3
+ * @japa/runner
4
+ *
5
+ * (c) Harminder Virk <virk@adonisjs.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.test = exports.run = exports.processCliArgs = exports.configure = exports.TestContext = exports.Group = exports.Runner = exports.Suite = exports.Test = void 0;
15
+ const getopts_1 = __importDefault(require("getopts"));
16
+ const path_1 = require("path");
17
+ const fast_glob_1 = __importDefault(require("fast-glob"));
18
+ const inclusion_1 = __importDefault(require("inclusion"));
19
+ const url_1 = require("url");
20
+ const hooks_1 = require("@poppinss/hooks");
21
+ const cliui_1 = require("@poppinss/cliui");
22
+ const errors_printer_1 = require("@japa/errors-printer");
23
+ const Core_1 = require("./src/Core");
24
+ Object.defineProperty(exports, "Test", { enumerable: true, get: function () { return Core_1.Test; } });
25
+ Object.defineProperty(exports, "TestContext", { enumerable: true, get: function () { return Core_1.TestContext; } });
26
+ Object.defineProperty(exports, "Group", { enumerable: true, get: function () { return Core_1.Group; } });
27
+ Object.defineProperty(exports, "Suite", { enumerable: true, get: function () { return Core_1.Suite; } });
28
+ Object.defineProperty(exports, "Runner", { enumerable: true, get: function () { return Core_1.Runner; } });
29
+ const core_1 = require("@japa/core");
30
+ /**
31
+ * Filtering layers allowed by the refiner
32
+ */
33
+ const refinerFilteringLayers = ['tests', 'groups', 'tags'];
34
+ /**
35
+ * Reference to the recently imported file. We pass it to the
36
+ * test and the group both
37
+ */
38
+ let recentlyImportedFile;
39
+ /**
40
+ * Global timeout for tests. Fetched from runner options or suites
41
+ * options
42
+ */
43
+ let globalTimeout;
44
+ /**
45
+ * Function to create the test context for the test
46
+ */
47
+ const getContext = (testInstance) => new Core_1.TestContext(testInstance);
48
+ /**
49
+ * The global reference to the tests emitter
50
+ */
51
+ const emitter = new core_1.Emitter();
52
+ /**
53
+ * Active suite for tests
54
+ */
55
+ let activeSuite;
56
+ /**
57
+ * Currently active group
58
+ */
59
+ let activeGroup;
60
+ /**
61
+ * Configuration options
62
+ */
63
+ let runnerOptions;
64
+ /**
65
+ * Ensure the configure method has been called
66
+ */
67
+ function ensureIsConfigured(message) {
68
+ if (!runnerOptions) {
69
+ throw new Error(message);
70
+ }
71
+ }
72
+ /**
73
+ * Validate suites filter to ensure a wrong suite is not
74
+ * mentioned
75
+ */
76
+ function validateSuitesFilter() {
77
+ if (!('suites' in runnerOptions)) {
78
+ return;
79
+ }
80
+ if (!runnerOptions.filters.suites || !runnerOptions.filters.suites.length) {
81
+ return;
82
+ }
83
+ const suites = runnerOptions.suites.map(({ name }) => name);
84
+ const invalidSuites = runnerOptions.filters.suites.filter((suite) => !suites.includes(suite));
85
+ if (invalidSuites.length) {
86
+ throw new Error(`Unrecognized suite "${invalidSuites[0]}". Make sure to define it in the config first`);
87
+ }
88
+ }
89
+ /**
90
+ * Process command line argument into a string value
91
+ */
92
+ function processAsString(argv, flagName, onMatch) {
93
+ const flag = argv[flagName];
94
+ if (flag) {
95
+ onMatch((Array.isArray(flag) ? flag : flag.split(',')).map((tag) => tag.trim()));
96
+ }
97
+ }
98
+ /**
99
+ * Find if the file path matches the files filter array.
100
+ * The ending of the file is matched
101
+ */
102
+ function isFileAllowed(filePath, filters) {
103
+ if (!filters.files || !filters.files.length) {
104
+ return true;
105
+ }
106
+ return !!filters.files.find((matcher) => {
107
+ if (filePath.endsWith(matcher)) {
108
+ return true;
109
+ }
110
+ return filePath.replace((0, path_1.extname)(filePath), '').endsWith(matcher);
111
+ });
112
+ }
113
+ /**
114
+ * Returns "true" when no filters are applied or the name is part
115
+ * of the applied filter.
116
+ */
117
+ function isSuiteAllowed(suite, filters) {
118
+ if (!filters.suites || !filters.suites.length) {
119
+ return true;
120
+ }
121
+ return filters.suites.includes(suite.name);
122
+ }
123
+ /**
124
+ * Collect files using the files collector function or by processing
125
+ * the glob pattern.
126
+ *
127
+ * The return value is further filtered against the `--files` filter.
128
+ */
129
+ async function collectFiles(files) {
130
+ if (Array.isArray(files) || typeof files === 'string') {
131
+ const collectedFiles = await (0, fast_glob_1.default)(files, {
132
+ absolute: true,
133
+ onlyFiles: true,
134
+ cwd: runnerOptions.cwd,
135
+ });
136
+ return collectedFiles.filter((file) => isFileAllowed(file, runnerOptions.filters));
137
+ }
138
+ else if (typeof files === 'function') {
139
+ const collectedFiles = await files();
140
+ return collectedFiles.filter((file) => isFileAllowed(file, runnerOptions.filters));
141
+ }
142
+ throw new Error('Invalid value for "files" property. Expected a string, array or a function');
143
+ }
144
+ /**
145
+ * Import test files using the configured importer.
146
+ */
147
+ async function importFiles(files) {
148
+ for (let file of files) {
149
+ recentlyImportedFile = file;
150
+ await runnerOptions.importer(file);
151
+ }
152
+ }
153
+ /**
154
+ * End tests. We wait for the "beforeExit" event when
155
+ * forceExit is not set to true
156
+ */
157
+ async function endTests(runner) {
158
+ if (runnerOptions.forceExit) {
159
+ await runner.end();
160
+ }
161
+ else {
162
+ return new Promise((resolve) => {
163
+ async function beforeExit() {
164
+ process.removeListener('beforeExit', beforeExit);
165
+ await runner.end();
166
+ resolve();
167
+ }
168
+ process.on('beforeExit', beforeExit);
169
+ });
170
+ }
171
+ }
172
+ /**
173
+ * Show help output in stdout.
174
+ */
175
+ function showHelp() {
176
+ const green = cliui_1.logger.colors.green.bind(cliui_1.logger.colors);
177
+ const grey = cliui_1.logger.colors.grey.bind(cliui_1.logger.colors);
178
+ console.log(`@japa/runner v2.1.1
180
179
 
181
180
  Options:
182
181
  ${green('--tests')} ${grey('Specify test titles')}
@@ -190,290 +189,290 @@ Options:
190
189
 
191
190
  Examples:
192
191
  ${grey('$ node bin/test.js --tags="@github"')}
193
- ${grey('$ node bin/test.js --files="example.spec.js" --force-exit')}`);
194
- }
195
- /**
196
- * Configure the tests runner
197
- */
198
- function configure(options) {
199
- const defaultOptions = {
200
- cwd: process.cwd(),
201
- files: [],
202
- suites: [],
203
- plugins: [],
204
- reporters: [],
205
- timeout: 2000,
206
- filters: {},
207
- setup: [],
208
- teardown: [],
209
- importer: (filePath) => (0, inclusion_1.default)((0, url_1.pathToFileURL)(filePath).href),
210
- refiner: new core_1.Refiner({}),
211
- forceExit: false,
212
- configureSuite: () => { },
213
- };
214
- runnerOptions = Object.assign(defaultOptions, options);
215
- }
216
- exports.configure = configure;
217
- /**
218
- * Process CLI arguments into configuration options. The following
219
- * command line arguments are processed.
220
- *
221
- * * --tests=Specify test titles
222
- * * --tags=Specify test tags
223
- * * --groups=Specify group titles
224
- * * --ignore-tags=Specify negated tags
225
- * * --files=Specify files to match and run
226
- * * --force-exit=Enable/disable force exit
227
- * * --timeout=Define timeout for all the tests
228
- * * -h, --help=Show help
229
- */
230
- function processCliArgs(argv) {
231
- const parsed = (0, getopts_1.default)(argv, {
232
- string: ['tests', 'tags', 'groups', 'ignoreTags', 'files', 'timeout'],
233
- boolean: ['forceExit', 'help'],
234
- alias: {
235
- ignoreTags: 'ignore-tags',
236
- forceExit: 'force-exit',
237
- help: 'h',
238
- },
239
- });
240
- const config = {
241
- filters: {},
242
- };
243
- processAsString(parsed, 'tags', (tags) => (config.filters.tags = tags));
244
- processAsString(parsed, 'ignoreTags', (tags) => {
245
- config.filters.tags = config.filters.tags || [];
246
- tags.forEach((tag) => config.filters.tags.push(`!${tag}`));
247
- });
248
- processAsString(parsed, 'groups', (groups) => (config.filters.groups = groups));
249
- processAsString(parsed, 'tests', (tests) => (config.filters.tests = tests));
250
- processAsString(parsed, 'files', (files) => (config.filters.files = files));
251
- /**
252
- * Show help
253
- */
254
- if (parsed.help) {
255
- showHelp();
256
- process.exit(0);
257
- }
258
- /**
259
- * Get suites
260
- */
261
- if (parsed._.length) {
262
- processAsString({ suites: parsed._ }, 'suites', (suites) => (config.filters.suites = suites));
263
- }
264
- /**
265
- * Get timeout
266
- */
267
- if (parsed.timeout) {
268
- const value = Number(parsed.timeout);
269
- if (!isNaN(value)) {
270
- config.timeout = value;
271
- }
272
- }
273
- /**
274
- * Get forceExit
275
- */
276
- if (parsed.forceExit) {
277
- config.forceExit = true;
278
- }
279
- return config;
280
- }
281
- exports.processCliArgs = processCliArgs;
282
- /**
283
- * Run japa tests
284
- */
285
- async function run() {
286
- const runner = new Core_1.Runner(emitter);
287
- runner.manageUnHandledExceptions();
288
- runner.onSuite(runnerOptions.configureSuite);
289
- const hooks = new hooks_1.Hooks();
290
- let setupRunner;
291
- let teardownRunner;
292
- try {
293
- ensureIsConfigured('Cannot run tests without configuring the tests runner');
294
- /**
295
- * Step 1: Run all plugins
296
- *
297
- * Plugins can also mutate config. So we process the config after
298
- * running plugins only
299
- */
300
- for (let plugin of runnerOptions.plugins) {
301
- await plugin(runnerOptions, runner, { Test: Core_1.Test, TestContext: Core_1.TestContext, Group: Core_1.Group });
302
- }
303
- validateSuitesFilter();
304
- /**
305
- * Step 2: Notify runner about reporters
306
- */
307
- runnerOptions.reporters.forEach((reporter) => runner.registerReporter(reporter));
308
- /**
309
- * Step 3: Configure runner hooks.
310
- */
311
- runnerOptions.setup.forEach((hook) => hooks.add('setup', hook));
312
- runnerOptions.teardown.forEach((hook) => hooks.add('teardown', hook));
313
- setupRunner = hooks.runner('setup');
314
- teardownRunner = hooks.runner('teardown');
315
- /**
316
- * Step 3.1: Run setup hooks
317
- *
318
- * We run the setup hooks before importing test files. It
319
- * allows hooks to setup the app environment for the
320
- * test files.
321
- */
322
- await setupRunner.run(runner);
323
- /**
324
- * Step 4: Entertain files property and import test files
325
- * as part of the default suite
326
- */
327
- if ('files' in runnerOptions && runnerOptions.files.length) {
328
- /**
329
- * Create a default suite for files with no suite
330
- */
331
- globalTimeout = runnerOptions.timeout;
332
- const files = await collectFiles(runnerOptions.files);
333
- /**
334
- * Create and register suite when files are collected.
335
- */
336
- if (files.length) {
337
- activeSuite = new Core_1.Suite('default', emitter, runnerOptions.refiner);
338
- runner.add(activeSuite);
339
- await importFiles(files);
340
- }
341
- }
342
- /**
343
- * Step 5: Entertain suites property and import test files
344
- * for the filtered suites.
345
- */
346
- if ('suites' in runnerOptions) {
347
- for (let suite of runnerOptions.suites) {
348
- if (isSuiteAllowed(suite, runnerOptions.filters)) {
349
- if (suite.timeout !== undefined) {
350
- globalTimeout = suite.timeout;
351
- }
352
- else {
353
- globalTimeout = runnerOptions.timeout;
354
- }
355
- const files = await collectFiles(suite.files);
356
- /**
357
- * Only register the suite and import files when the suite
358
- * files glob + filter has returned one or more files.
359
- */
360
- if (files.length) {
361
- activeSuite = new Core_1.Suite(suite.name, emitter, runnerOptions.refiner);
362
- if (typeof suite.configure === 'function') {
363
- suite.configure(activeSuite);
364
- }
365
- runner.add(activeSuite);
366
- await importFiles(files);
367
- }
368
- }
369
- }
370
- }
371
- /**
372
- * Step 6: Add filters to the refiner
373
- */
374
- Object.keys(runnerOptions.filters).forEach((layer) => {
375
- if (refinerFilteringLayers.includes(layer)) {
376
- const values = runnerOptions.filters[layer];
377
- if (values) {
378
- runnerOptions.refiner.add(layer, values);
379
- }
380
- }
381
- });
382
- /**
383
- * Step 7.1: Start the tests runner
384
- */
385
- await runner.start();
386
- /**
387
- * Step 7.2: Execute all the tests
388
- */
389
- await runner.exec();
390
- /**
391
- * Step 7.3: Run cleanup and teardown hooks
392
- */
393
- await setupRunner.cleanup(runner);
394
- await teardownRunner.run(runner);
395
- await teardownRunner.cleanup(runner);
396
- /**
397
- * Step 7.4: End or wait for process to exit
398
- */
399
- await endTests(runner);
400
- /**
401
- * Step 8: Update the process exit code
402
- */
403
- const summary = runner.getSummary();
404
- if (summary.hasError) {
405
- process.exitCode = 1;
406
- }
407
- runnerOptions.forceExit && process.exit();
408
- }
409
- catch (error) {
410
- if (setupRunner && setupRunner.isCleanupPending) {
411
- await setupRunner.cleanup(error, runner);
412
- }
413
- if (teardownRunner && teardownRunner.isCleanupPending) {
414
- await teardownRunner.cleanup(error, runner);
415
- }
416
- const printer = new errors_printer_1.ErrorsPrinter();
417
- await printer.printError(error);
418
- process.exitCode = 1;
419
- runnerOptions.forceExit && process.exit();
420
- }
421
- }
422
- exports.run = run;
423
- /**
424
- * Add a new test
425
- */
426
- function test(title, callback) {
427
- ensureIsConfigured('Cannot add test without configuring the test runner');
428
- const testInstance = new Core_1.Test(title, getContext, emitter, runnerOptions.refiner, activeGroup);
429
- /**
430
- * Set filename
431
- */
432
- testInstance.options.meta.fileName = recentlyImportedFile;
433
- /**
434
- * Define timeout on the test when exists globally
435
- */
436
- if (globalTimeout !== undefined) {
437
- testInstance.timeout(globalTimeout);
438
- }
439
- /**
440
- * Define test executor function
441
- */
442
- if (callback) {
443
- testInstance.run(callback);
444
- }
445
- /**
446
- * Add test to the group or suite
447
- */
448
- if (activeGroup) {
449
- activeGroup.add(testInstance);
450
- }
451
- else {
452
- activeSuite.add(testInstance);
453
- }
454
- return testInstance;
455
- }
456
- exports.test = test;
457
- /**
458
- * Define test group
459
- */
460
- test.group = function (title, callback) {
461
- ensureIsConfigured('Cannot add test group without configuring the test runner');
462
- /**
463
- * Disallow nested groups
464
- */
465
- if (activeGroup) {
466
- throw new Error('Cannot create nested test groups');
467
- }
468
- activeGroup = new Core_1.Group(title, emitter, runnerOptions.refiner);
469
- /**
470
- * Set filename
471
- */
472
- activeGroup.options.meta.fileName = recentlyImportedFile;
473
- /**
474
- * Add group to the default suite
475
- */
476
- activeSuite.add(activeGroup);
477
- callback(activeGroup);
478
- activeGroup = undefined;
479
- };
192
+ ${grey('$ node bin/test.js --files="example.spec.js" --force-exit')}`);
193
+ }
194
+ /**
195
+ * Configure the tests runner
196
+ */
197
+ function configure(options) {
198
+ const defaultOptions = {
199
+ cwd: process.cwd(),
200
+ files: [],
201
+ suites: [],
202
+ plugins: [],
203
+ reporters: [],
204
+ timeout: 2000,
205
+ filters: {},
206
+ setup: [],
207
+ teardown: [],
208
+ importer: (filePath) => (0, inclusion_1.default)((0, url_1.pathToFileURL)(filePath).href),
209
+ refiner: new core_1.Refiner({}),
210
+ forceExit: false,
211
+ configureSuite: () => { },
212
+ };
213
+ runnerOptions = Object.assign(defaultOptions, options);
214
+ }
215
+ exports.configure = configure;
216
+ /**
217
+ * Process CLI arguments into configuration options. The following
218
+ * command line arguments are processed.
219
+ *
220
+ * * --tests=Specify test titles
221
+ * * --tags=Specify test tags
222
+ * * --groups=Specify group titles
223
+ * * --ignore-tags=Specify negated tags
224
+ * * --files=Specify files to match and run
225
+ * * --force-exit=Enable/disable force exit
226
+ * * --timeout=Define timeout for all the tests
227
+ * * -h, --help=Show help
228
+ */
229
+ function processCliArgs(argv) {
230
+ const parsed = (0, getopts_1.default)(argv, {
231
+ string: ['tests', 'tags', 'groups', 'ignoreTags', 'files', 'timeout'],
232
+ boolean: ['forceExit', 'help'],
233
+ alias: {
234
+ ignoreTags: 'ignore-tags',
235
+ forceExit: 'force-exit',
236
+ help: 'h',
237
+ },
238
+ });
239
+ const config = {
240
+ filters: {},
241
+ };
242
+ processAsString(parsed, 'tags', (tags) => (config.filters.tags = tags));
243
+ processAsString(parsed, 'ignoreTags', (tags) => {
244
+ config.filters.tags = config.filters.tags || [];
245
+ tags.forEach((tag) => config.filters.tags.push(`!${tag}`));
246
+ });
247
+ processAsString(parsed, 'groups', (groups) => (config.filters.groups = groups));
248
+ processAsString(parsed, 'tests', (tests) => (config.filters.tests = tests));
249
+ processAsString(parsed, 'files', (files) => (config.filters.files = files));
250
+ /**
251
+ * Show help
252
+ */
253
+ if (parsed.help) {
254
+ showHelp();
255
+ process.exit(0);
256
+ }
257
+ /**
258
+ * Get suites
259
+ */
260
+ if (parsed._.length) {
261
+ processAsString({ suites: parsed._ }, 'suites', (suites) => (config.filters.suites = suites));
262
+ }
263
+ /**
264
+ * Get timeout
265
+ */
266
+ if (parsed.timeout) {
267
+ const value = Number(parsed.timeout);
268
+ if (!isNaN(value)) {
269
+ config.timeout = value;
270
+ }
271
+ }
272
+ /**
273
+ * Get forceExit
274
+ */
275
+ if (parsed.forceExit) {
276
+ config.forceExit = true;
277
+ }
278
+ return config;
279
+ }
280
+ exports.processCliArgs = processCliArgs;
281
+ /**
282
+ * Run japa tests
283
+ */
284
+ async function run() {
285
+ const runner = new Core_1.Runner(emitter);
286
+ runner.manageUnHandledExceptions();
287
+ runner.onSuite(runnerOptions.configureSuite);
288
+ const hooks = new hooks_1.Hooks();
289
+ let setupRunner;
290
+ let teardownRunner;
291
+ try {
292
+ ensureIsConfigured('Cannot run tests without configuring the tests runner');
293
+ /**
294
+ * Step 1: Run all plugins
295
+ *
296
+ * Plugins can also mutate config. So we process the config after
297
+ * running plugins only
298
+ */
299
+ for (let plugin of runnerOptions.plugins) {
300
+ await plugin(runnerOptions, runner, { Test: Core_1.Test, TestContext: Core_1.TestContext, Group: Core_1.Group });
301
+ }
302
+ validateSuitesFilter();
303
+ /**
304
+ * Step 2: Notify runner about reporters
305
+ */
306
+ runnerOptions.reporters.forEach((reporter) => runner.registerReporter(reporter));
307
+ /**
308
+ * Step 3: Configure runner hooks.
309
+ */
310
+ runnerOptions.setup.forEach((hook) => hooks.add('setup', hook));
311
+ runnerOptions.teardown.forEach((hook) => hooks.add('teardown', hook));
312
+ setupRunner = hooks.runner('setup');
313
+ teardownRunner = hooks.runner('teardown');
314
+ /**
315
+ * Step 3.1: Run setup hooks
316
+ *
317
+ * We run the setup hooks before importing test files. It
318
+ * allows hooks to setup the app environment for the
319
+ * test files.
320
+ */
321
+ await setupRunner.run(runner);
322
+ /**
323
+ * Step 4: Entertain files property and import test files
324
+ * as part of the default suite
325
+ */
326
+ if ('files' in runnerOptions && runnerOptions.files.length) {
327
+ /**
328
+ * Create a default suite for files with no suite
329
+ */
330
+ globalTimeout = runnerOptions.timeout;
331
+ const files = await collectFiles(runnerOptions.files);
332
+ /**
333
+ * Create and register suite when files are collected.
334
+ */
335
+ if (files.length) {
336
+ activeSuite = new Core_1.Suite('default', emitter, runnerOptions.refiner);
337
+ runner.add(activeSuite);
338
+ await importFiles(files);
339
+ }
340
+ }
341
+ /**
342
+ * Step 5: Entertain suites property and import test files
343
+ * for the filtered suites.
344
+ */
345
+ if ('suites' in runnerOptions) {
346
+ for (let suite of runnerOptions.suites) {
347
+ if (isSuiteAllowed(suite, runnerOptions.filters)) {
348
+ if (suite.timeout !== undefined) {
349
+ globalTimeout = suite.timeout;
350
+ }
351
+ else {
352
+ globalTimeout = runnerOptions.timeout;
353
+ }
354
+ const files = await collectFiles(suite.files);
355
+ /**
356
+ * Only register the suite and import files when the suite
357
+ * files glob + filter has returned one or more files.
358
+ */
359
+ if (files.length) {
360
+ activeSuite = new Core_1.Suite(suite.name, emitter, runnerOptions.refiner);
361
+ if (typeof suite.configure === 'function') {
362
+ suite.configure(activeSuite);
363
+ }
364
+ runner.add(activeSuite);
365
+ await importFiles(files);
366
+ }
367
+ }
368
+ }
369
+ }
370
+ /**
371
+ * Step 6: Add filters to the refiner
372
+ */
373
+ Object.keys(runnerOptions.filters).forEach((layer) => {
374
+ if (refinerFilteringLayers.includes(layer)) {
375
+ const values = runnerOptions.filters[layer];
376
+ if (values) {
377
+ runnerOptions.refiner.add(layer, values);
378
+ }
379
+ }
380
+ });
381
+ /**
382
+ * Step 7.1: Start the tests runner
383
+ */
384
+ await runner.start();
385
+ /**
386
+ * Step 7.2: Execute all the tests
387
+ */
388
+ await runner.exec();
389
+ /**
390
+ * Step 7.3: Run cleanup and teardown hooks
391
+ */
392
+ await setupRunner.cleanup(runner);
393
+ await teardownRunner.run(runner);
394
+ await teardownRunner.cleanup(runner);
395
+ /**
396
+ * Step 7.4: End or wait for process to exit
397
+ */
398
+ await endTests(runner);
399
+ /**
400
+ * Step 8: Update the process exit code
401
+ */
402
+ const summary = runner.getSummary();
403
+ if (summary.hasError) {
404
+ process.exitCode = 1;
405
+ }
406
+ runnerOptions.forceExit && process.exit();
407
+ }
408
+ catch (error) {
409
+ if (setupRunner && setupRunner.isCleanupPending) {
410
+ await setupRunner.cleanup(error, runner);
411
+ }
412
+ if (teardownRunner && teardownRunner.isCleanupPending) {
413
+ await teardownRunner.cleanup(error, runner);
414
+ }
415
+ const printer = new errors_printer_1.ErrorsPrinter();
416
+ await printer.printError(error);
417
+ process.exitCode = 1;
418
+ runnerOptions.forceExit && process.exit();
419
+ }
420
+ }
421
+ exports.run = run;
422
+ /**
423
+ * Add a new test
424
+ */
425
+ function test(title, callback) {
426
+ ensureIsConfigured('Cannot add test without configuring the test runner');
427
+ const testInstance = new Core_1.Test(title, getContext, emitter, runnerOptions.refiner, activeGroup);
428
+ /**
429
+ * Set filename
430
+ */
431
+ testInstance.options.meta.fileName = recentlyImportedFile;
432
+ /**
433
+ * Define timeout on the test when exists globally
434
+ */
435
+ if (globalTimeout !== undefined) {
436
+ testInstance.timeout(globalTimeout);
437
+ }
438
+ /**
439
+ * Define test executor function
440
+ */
441
+ if (callback) {
442
+ testInstance.run(callback);
443
+ }
444
+ /**
445
+ * Add test to the group or suite
446
+ */
447
+ if (activeGroup) {
448
+ activeGroup.add(testInstance);
449
+ }
450
+ else {
451
+ activeSuite.add(testInstance);
452
+ }
453
+ return testInstance;
454
+ }
455
+ exports.test = test;
456
+ /**
457
+ * Define test group
458
+ */
459
+ test.group = function (title, callback) {
460
+ ensureIsConfigured('Cannot add test group without configuring the test runner');
461
+ /**
462
+ * Disallow nested groups
463
+ */
464
+ if (activeGroup) {
465
+ throw new Error('Cannot create nested test groups');
466
+ }
467
+ activeGroup = new Core_1.Group(title, emitter, runnerOptions.refiner);
468
+ /**
469
+ * Set filename
470
+ */
471
+ activeGroup.options.meta.fileName = recentlyImportedFile;
472
+ /**
473
+ * Add group to the default suite
474
+ */
475
+ activeSuite.add(activeGroup);
476
+ callback(activeGroup);
477
+ activeGroup = undefined;
478
+ };
@@ -1,67 +1,67 @@
1
- import { Refiner, FilteringOptions, ReporterContract } from '@japa/core';
2
- import { Test, Group, TestContext, Runner, Suite } from '../Core';
3
- /**
4
- * The cleanup function for runner hooks
5
- */
6
- export declare type RunnerHooksCleanupHandler = (error: null | any, runner: Runner) => Promise<any> | any;
7
- /**
8
- * The function that can be registered as a runner hook
9
- */
10
- export declare type RunnerHooksHandler = (runner: Runner) => Promise<any> | any | RunnerHooksCleanupHandler | Promise<RunnerHooksCleanupHandler>;
11
- /**
12
- * Allowed filters
13
- */
14
- export declare type Filters = FilteringOptions & {
15
- files?: string[];
16
- suites?: string[];
17
- };
18
- /**
19
- * Shape of the plugin function
20
- */
21
- export declare type PluginFn = (config: Required<Config>, runner: Runner, classes: {
22
- Test: typeof Test;
23
- TestContext: typeof TestContext;
24
- Group: typeof Group;
25
- }) => void | Promise<void>;
26
- /**
27
- * Runner hooks
28
- */
29
- export declare type RunnerHooks = {
30
- setup: RunnerHooksHandler[];
31
- teardown: RunnerHooksHandler[];
32
- };
33
- /**
34
- * Base configuration options
35
- */
36
- export declare type BaseConfig = {
37
- cwd?: string;
38
- timeout?: number;
39
- plugins?: PluginFn[];
40
- filters?: Filters;
41
- configureSuite?: (suite: Suite) => void;
42
- reporters?: ReporterContract[];
43
- importer?: (filePath: string) => void | Promise<void>;
44
- refiner?: Refiner;
45
- forceExit?: boolean;
46
- } & Partial<RunnerHooks>;
47
- /**
48
- * Type for the "config.files" property
49
- */
50
- export declare type ConfigFiles = string[] | (() => string[] | Promise<string[]>);
51
- /**
52
- * Type for the "config.suite" property
53
- */
54
- export declare type ConfigSuite = {
55
- name: string;
56
- files: string | string[] | (() => string[] | Promise<string[]>);
57
- configure?: (suite: Suite) => void;
58
- timeout?: number;
59
- };
60
- /**
61
- * Configuration options
62
- */
63
- export declare type Config = BaseConfig & ({
64
- files: ConfigFiles;
65
- } | {
66
- suites: ConfigSuite[];
67
- });
1
+ import { Refiner, FilteringOptions, ReporterContract } from '@japa/core';
2
+ import { Test, Group, TestContext, Runner, Suite } from '../Core';
3
+ /**
4
+ * The cleanup function for runner hooks
5
+ */
6
+ export declare type RunnerHooksCleanupHandler = (error: null | any, runner: Runner) => Promise<any> | any;
7
+ /**
8
+ * The function that can be registered as a runner hook
9
+ */
10
+ export declare type RunnerHooksHandler = (runner: Runner) => Promise<any> | any | RunnerHooksCleanupHandler | Promise<RunnerHooksCleanupHandler>;
11
+ /**
12
+ * Allowed filters
13
+ */
14
+ export declare type Filters = FilteringOptions & {
15
+ files?: string[];
16
+ suites?: string[];
17
+ };
18
+ /**
19
+ * Shape of the plugin function
20
+ */
21
+ export declare type PluginFn = (config: Required<Config>, runner: Runner, classes: {
22
+ Test: typeof Test;
23
+ TestContext: typeof TestContext;
24
+ Group: typeof Group;
25
+ }) => void | Promise<void>;
26
+ /**
27
+ * Runner hooks
28
+ */
29
+ export declare type RunnerHooks = {
30
+ setup: RunnerHooksHandler[];
31
+ teardown: RunnerHooksHandler[];
32
+ };
33
+ /**
34
+ * Base configuration options
35
+ */
36
+ export declare type BaseConfig = {
37
+ cwd?: string;
38
+ timeout?: number;
39
+ plugins?: PluginFn[];
40
+ filters?: Filters;
41
+ configureSuite?: (suite: Suite) => void;
42
+ reporters?: ReporterContract[];
43
+ importer?: (filePath: string) => void | Promise<void>;
44
+ refiner?: Refiner;
45
+ forceExit?: boolean;
46
+ } & Partial<RunnerHooks>;
47
+ /**
48
+ * Type for the "config.files" property
49
+ */
50
+ export declare type ConfigFiles = string[] | (() => string[] | Promise<string[]>);
51
+ /**
52
+ * Type for the "config.suite" property
53
+ */
54
+ export declare type ConfigSuite = {
55
+ name: string;
56
+ files: string | string[] | (() => string[] | Promise<string[]>);
57
+ configure?: (suite: Suite) => void;
58
+ timeout?: number;
59
+ };
60
+ /**
61
+ * Configuration options
62
+ */
63
+ export declare type Config = BaseConfig & ({
64
+ files: ConfigFiles;
65
+ } | {
66
+ suites: ConfigSuite[];
67
+ });
@@ -1,10 +1,10 @@
1
- "use strict";
2
- /*
3
- * @japa/runner
4
- *
5
- * (c) Harminder Virk <virk@adonisjs.com>
6
- *
7
- * For the full copyright and license information, please view the LICENSE
8
- * file that was distributed with this source code.
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ "use strict";
2
+ /*
3
+ * @japa/runner
4
+ *
5
+ * (c) Harminder Virk <virk@adonisjs.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,14 +1,14 @@
1
- import { DataSetNode, Test as BaseTest, Group as BaseGroup, Suite as BaseSuite, Runner as BaseRunner, TestContext as BaseTestContext } from '@japa/core';
2
- export declare class TestContext extends BaseTestContext {
3
- test: Test;
4
- constructor(test: Test);
5
- }
6
- export declare class Test<TestData extends DataSetNode = undefined> extends BaseTest<TestContext, TestData> {
7
- static disposeCallbacks: never[];
8
- }
9
- export declare class Group extends BaseGroup<TestContext> {
10
- }
11
- export declare class Suite extends BaseSuite<TestContext> {
12
- }
13
- export declare class Runner extends BaseRunner<TestContext> {
14
- }
1
+ import { DataSetNode, Test as BaseTest, Group as BaseGroup, Suite as BaseSuite, Runner as BaseRunner, TestContext as BaseTestContext } from '@japa/core';
2
+ export declare class TestContext extends BaseTestContext {
3
+ test: Test;
4
+ constructor(test: Test);
5
+ }
6
+ export declare class Test<TestData extends DataSetNode = undefined> extends BaseTest<TestContext, TestData> {
7
+ static disposeCallbacks: never[];
8
+ }
9
+ export declare class Group extends BaseGroup<TestContext> {
10
+ }
11
+ export declare class Suite extends BaseSuite<TestContext> {
12
+ }
13
+ export declare class Runner extends BaseRunner<TestContext> {
14
+ }
@@ -1,32 +1,32 @@
1
- "use strict";
2
- /*
3
- * @japa/runner
4
- *
5
- * (c) Harminder Virk <virk@adonisjs.com>
6
- *
7
- * For the full copyright and license information, please view the LICENSE
8
- * file that was distributed with this source code.
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.Runner = exports.Suite = exports.Group = exports.Test = exports.TestContext = void 0;
12
- const core_1 = require("@japa/core");
13
- class TestContext extends core_1.TestContext {
14
- constructor(test) {
15
- super();
16
- this.test = test;
17
- }
18
- }
19
- exports.TestContext = TestContext;
20
- class Test extends core_1.Test {
21
- }
22
- exports.Test = Test;
23
- Test.disposeCallbacks = [];
24
- class Group extends core_1.Group {
25
- }
26
- exports.Group = Group;
27
- class Suite extends core_1.Suite {
28
- }
29
- exports.Suite = Suite;
30
- class Runner extends core_1.Runner {
31
- }
32
- exports.Runner = Runner;
1
+ "use strict";
2
+ /*
3
+ * @japa/runner
4
+ *
5
+ * (c) Harminder Virk <virk@adonisjs.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.Runner = exports.Suite = exports.Group = exports.Test = exports.TestContext = void 0;
12
+ const core_1 = require("@japa/core");
13
+ class TestContext extends core_1.TestContext {
14
+ constructor(test) {
15
+ super();
16
+ this.test = test;
17
+ }
18
+ }
19
+ exports.TestContext = TestContext;
20
+ class Test extends core_1.Test {
21
+ }
22
+ exports.Test = Test;
23
+ Test.disposeCallbacks = [];
24
+ class Group extends core_1.Group {
25
+ }
26
+ exports.Group = Group;
27
+ class Suite extends core_1.Suite {
28
+ }
29
+ exports.Suite = Suite;
30
+ class Runner extends core_1.Runner {
31
+ }
32
+ exports.Runner = Runner;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@japa/runner",
3
- "version": "2.1.0",
3
+ "version": "2.1.3",
4
4
  "description": "Runner for Japa testing framework",
5
5
  "main": "build/index.js",
6
6
  "files": [
@@ -36,7 +36,7 @@
36
36
  "devDependencies": {
37
37
  "@adonisjs/mrm-preset": "^5.0.3",
38
38
  "@adonisjs/require-ts": "^2.0.12",
39
- "@types/node": "^18.7.14",
39
+ "@types/node": "^18.7.15",
40
40
  "commitizen": "^4.2.5",
41
41
  "cz-conventional-changelog": "^3.3.0",
42
42
  "del-cli": "^5.0.0",
@@ -105,8 +105,8 @@
105
105
  "anyBranch": false
106
106
  },
107
107
  "dependencies": {
108
- "@japa/core": "^7.0.0",
109
- "@japa/errors-printer": "^1.3.10",
108
+ "@japa/core": "^7.0.1",
109
+ "@japa/errors-printer": "^2.0.1",
110
110
  "@poppinss/cliui": "^3.0.2",
111
111
  "@poppinss/hooks": "^6.0.2-0",
112
112
  "fast-glob": "^3.2.11",