@japa/runner 4.4.0 → 4.4.1

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.
@@ -1,519 +0,0 @@
1
- import {
2
- dot,
3
- github,
4
- ndjson,
5
- spec
6
- } from "./chunk-RFKFNXTE.js";
7
- import {
8
- Group,
9
- Refiner,
10
- Test,
11
- TestContext,
12
- colors
13
- } from "./chunk-L7YZLDZD.js";
14
-
15
- // src/debug.ts
16
- import { debuglog } from "util";
17
- var debug_default = debuglog("japa:runner");
18
-
19
- // src/validator.ts
20
- var Validator = class {
21
- /**
22
- * Ensures the japa is configured. Otherwise raises an exception
23
- */
24
- ensureIsConfigured(config) {
25
- if (!config) {
26
- throw new Error(
27
- `Cannot run tests. Make sure to call "configure" method before the "run" method`
28
- );
29
- }
30
- }
31
- /**
32
- * Ensures the japa is in planning phase
33
- */
34
- ensureIsInPlanningPhase(phase) {
35
- if (phase !== "planning") {
36
- throw new Error(
37
- `Cannot import japa test file directly. It must be imported by calling the "japa.run" method`
38
- );
39
- }
40
- }
41
- /**
42
- * Ensures the suites filter uses a subset of the user configured suites.
43
- */
44
- validateSuitesFilter(config) {
45
- if (!config.filters.suites || !config.filters.suites.length) {
46
- return;
47
- }
48
- if (!("suites" in config) || !config.suites.length) {
49
- throw new Error(`Cannot apply suites filter. You have not configured any test suites`);
50
- }
51
- const suites = config.suites.map(({ name }) => name);
52
- const unknownSuites = config.filters.suites.filter((suite) => !suites.includes(suite));
53
- if (unknownSuites.length) {
54
- throw new Error(`Cannot apply suites filter. "${unknownSuites[0]}" suite is not configured`);
55
- }
56
- }
57
- /**
58
- * Ensure there are unique suites
59
- */
60
- validateSuitesForUniqueness(config) {
61
- if (!("suites" in config)) {
62
- return;
63
- }
64
- const suites = /* @__PURE__ */ new Set();
65
- config.suites.forEach(({ name }) => {
66
- if (suites.has(name)) {
67
- throw new Error(`Duplicate suite "${name}"`);
68
- }
69
- suites.add(name);
70
- });
71
- suites.clear();
72
- }
73
- /**
74
- * Ensure the activated reporters are in the list of defined
75
- * reporters
76
- */
77
- validateActivatedReporters(config) {
78
- const reportersList = config.reporters.list.map(({ name }) => name);
79
- const unknownReporters = config.reporters.activated.filter(
80
- (name) => !reportersList.includes(name)
81
- );
82
- if (unknownReporters.length) {
83
- throw new Error(
84
- `Invalid reporter "${unknownReporters[0]}". Make sure to register it first inside the "reporters.list" array`
85
- );
86
- }
87
- }
88
- };
89
- var validator_default = new Validator();
90
-
91
- // src/files_manager.ts
92
- import slash from "slash";
93
- import fastGlob from "fast-glob";
94
- import { pathToFileURL } from "url";
95
- var FILE_SUFFIX_EXPRESSION = /(\.spec|\.test)?\.[js|ts|jsx|tsx|mjs|mts|cjs|cts]+$/;
96
- var FilesManager = class {
97
- /**
98
- * Returns a collection of files from the user defined
99
- * glob or the implementation function
100
- */
101
- async getFiles(cwd, files, excludes) {
102
- if (Array.isArray(files) || typeof files === "string") {
103
- const testFiles = await fastGlob(files, {
104
- absolute: true,
105
- onlyFiles: true,
106
- cwd,
107
- ignore: excludes
108
- });
109
- return testFiles.map((file) => pathToFileURL(file));
110
- }
111
- return await files();
112
- }
113
- /**
114
- * Applies file name filter on a collection of file
115
- * URLs
116
- */
117
- grep(files, filters) {
118
- return files.filter((file) => {
119
- const filename = slash(file.pathname);
120
- const filenameWithoutTestSuffix = filename.replace(FILE_SUFFIX_EXPRESSION, "");
121
- return !!filters.find((filter) => {
122
- if (filename.endsWith(filter)) {
123
- return true;
124
- }
125
- const filterSegments = filter.split("/").reverse();
126
- const fileSegments = filenameWithoutTestSuffix.split("/").reverse();
127
- return filterSegments.every((segment, index) => {
128
- return fileSegments[index] && (segment === "*" || fileSegments[index].endsWith(segment));
129
- });
130
- });
131
- });
132
- }
133
- };
134
-
135
- // src/planner.ts
136
- var Planner = class {
137
- #config;
138
- #fileManager = new FilesManager();
139
- constructor(config) {
140
- validator_default.validateActivatedReporters(config);
141
- validator_default.validateSuitesFilter(config);
142
- validator_default.validateSuitesForUniqueness(config);
143
- this.#config = config;
144
- }
145
- /**
146
- * Returns a list of reporters based upon the activated
147
- * reporters list.
148
- */
149
- #getActivatedReporters() {
150
- return this.#config.reporters.activated.map((activated) => {
151
- return this.#config.reporters.list.find(({ name }) => activated === name);
152
- });
153
- }
154
- /**
155
- * A generic method to collect files from the user defined
156
- * files glob and apply the files filter
157
- */
158
- async #collectFiles(files) {
159
- let filesURLs = await this.#fileManager.getFiles(this.#config.cwd, files, this.#config.exclude);
160
- if (this.#config.filters.files && this.#config.filters.files.length) {
161
- filesURLs = this.#fileManager.grep(filesURLs, this.#config.filters.files);
162
- }
163
- return filesURLs;
164
- }
165
- /**
166
- * Returns a collection of suites and their associated
167
- * test files by applying all the filters
168
- */
169
- async #getSuites() {
170
- let suites = [];
171
- let suitesFilters = this.#config.filters.suites || [];
172
- if ("files" in this.#config) {
173
- suites.push({
174
- name: "default",
175
- files: this.#config.files,
176
- timeout: this.#config.timeout,
177
- retries: this.#config.retries,
178
- filesURLs: await this.#collectFiles(this.#config.files)
179
- });
180
- }
181
- if ("suites" in this.#config) {
182
- for (let suite of this.#config.suites) {
183
- if (!suitesFilters.length || suitesFilters.includes(suite.name)) {
184
- suites.push({
185
- ...suite,
186
- filesURLs: await this.#collectFiles(suite.files)
187
- });
188
- }
189
- }
190
- }
191
- return suites;
192
- }
193
- /**
194
- * Returns a list of filters to the passed to the refiner
195
- */
196
- #getRefinerFilters() {
197
- return Object.keys(this.#config.filters).reduce(
198
- (result, layer) => {
199
- if (layer === "tests" || layer === "tags" || layer === "groups") {
200
- result.push({ layer, filters: this.#config.filters[layer] });
201
- }
202
- return result;
203
- },
204
- []
205
- );
206
- }
207
- /**
208
- * Creates a plan for running the tests
209
- */
210
- async plan() {
211
- const suites = await this.#getSuites();
212
- const reporters = this.#getActivatedReporters();
213
- const refinerFilters = this.#getRefinerFilters();
214
- return {
215
- reporters,
216
- suites,
217
- refinerFilters,
218
- config: this.#config
219
- };
220
- }
221
- };
222
-
223
- // src/hooks.ts
224
- import Hooks from "@poppinss/hooks";
225
- var GlobalHooks = class {
226
- #hooks = new Hooks();
227
- #setupRunner;
228
- #teardownRunner;
229
- /**
230
- * Apply hooks from the config
231
- */
232
- apply(config) {
233
- config.setup.forEach((hook) => this.#hooks.add("setup", hook));
234
- config.teardown.forEach((hook) => this.#hooks.add("teardown", hook));
235
- }
236
- /**
237
- * Perform setup
238
- */
239
- async setup(runner) {
240
- this.#setupRunner = this.#hooks.runner("setup");
241
- this.#teardownRunner = this.#hooks.runner("teardown");
242
- await this.#setupRunner.run(runner);
243
- }
244
- /**
245
- * Perform cleanup
246
- */
247
- async teardown(error, runner) {
248
- if (this.#setupRunner) {
249
- await this.#setupRunner.cleanup(error, runner);
250
- }
251
- if (this.#teardownRunner) {
252
- if (!error) {
253
- await this.#teardownRunner.run(runner);
254
- }
255
- await this.#teardownRunner.cleanup(error, runner);
256
- }
257
- }
258
- };
259
-
260
- // src/cli_parser.ts
261
- import getopts from "getopts";
262
- var OPTIONS = {
263
- string: ["tests", "groups", "tags", "files", "timeout", "retries", "reporters", "bailLayer"],
264
- boolean: ["help", "matchAll", "failed", "bail", "listPinned"],
265
- alias: {
266
- forceExit: "force-exit",
267
- matchAll: "match-all",
268
- listPinned: "list-pinned",
269
- bailLayer: "bail-layer",
270
- help: "h"
271
- }
272
- };
273
- var GET_HELP = () => `
274
- ${colors.yellow("@japa/runner v2.3.0")}
275
-
276
- ${colors.green("--tests")} ${colors.dim("Filter tests by the test title")}
277
- ${colors.green("--groups")} ${colors.dim("Filter tests by the group title")}
278
- ${colors.green("--tags")} ${colors.dim("Filter tests by tags")}
279
- ${colors.green("--match-all")} ${colors.dim("Run tests that matches all the supplied tags")}
280
- ${colors.green("--list-pinned")} ${colors.dim("List pinned tests")}
281
- ${colors.green("--files")} ${colors.dim("Filter tests by the file name")}
282
- ${colors.green("--force-exit")} ${colors.dim("Forcefully exit the process")}
283
- ${colors.green("--timeout")} ${colors.dim("Define default timeout for all tests")}
284
- ${colors.green("--retries")} ${colors.dim("Define default retries for all tests")}
285
- ${colors.green("--reporters")} ${colors.dim("Activate one or more test reporters")}
286
- ${colors.green("--failed")} ${colors.dim("Run tests failed during the last run")}
287
- ${colors.green("--bail")} ${colors.dim("Exit early when a test fails")}
288
- ${colors.green("--bail-layer")} ${colors.dim('Specify at which layer to enable the bail mode. Can be "group" or "suite"')}
289
- ${colors.green("-h, --help")} ${colors.dim("View help")}
290
-
291
- ${colors.yellow("Examples:")}
292
- ${colors.dim('node bin/test.js --tags="@github"')}
293
- ${colors.dim('node bin/test.js --tags="~@github"')}
294
- ${colors.dim('node bin/test.js --tags="@github,@slow,@integration" --match-all')}
295
- ${colors.dim("node bin/test.js --force-exit")}
296
- ${colors.dim('node bin/test.js --files="user"')}
297
- ${colors.dim('node bin/test.js --files="functional/user"')}
298
- ${colors.dim('node bin/test.js --files="unit/user"')}
299
- ${colors.dim("node bin/test.js --failed")}
300
- ${colors.dim("node bin/test.js --bail")}
301
- ${colors.dim("node bin/test.js --bail=group")}
302
-
303
- ${colors.yellow("Notes:")}
304
- - When groups and tests filters are applied together. We will first filter the
305
- tests by group title and then apply the tests filter.
306
- - The timeout defined on test object takes precedence over the ${colors.green("--timeout")} flag.
307
- - The retries defined on test object takes precedence over the ${colors.green("--retries")} flag.
308
- - The ${colors.green("--files")} flag checks for the file names ending with the filter substring.
309
- - The ${colors.green("--tags")} filter runs tests that has one or more of the supplied tags.
310
- - You can use the ${colors.green("--match-all")} flag to run tests that has all the supplied tags.
311
- `;
312
- var CliParser = class {
313
- /**
314
- * Parses command-line arguments
315
- */
316
- parse(argv) {
317
- return getopts(argv, OPTIONS);
318
- }
319
- /**
320
- * Returns the help string
321
- */
322
- getHelp() {
323
- return GET_HELP();
324
- }
325
- };
326
-
327
- // src/config_manager.ts
328
- var NOOP = () => {
329
- };
330
- var DEFAULTS = {
331
- files: [],
332
- timeout: 2e3,
333
- retries: 0,
334
- forceExit: false,
335
- plugins: [],
336
- reporters: {
337
- activated: ["spec"].concat(process.env.GITHUB_ACTIONS === "true" ? ["github"] : []),
338
- list: [spec(), ndjson(), dot(), github()]
339
- },
340
- importer: (filePath) => import(filePath.href),
341
- configureSuite: () => {
342
- }
343
- };
344
- var ConfigManager = class {
345
- #config;
346
- #cliArgs;
347
- constructor(config, cliArgs) {
348
- this.#config = config;
349
- this.#cliArgs = cliArgs;
350
- }
351
- /**
352
- * Processes a CLI argument and converts it to an
353
- * array of strings
354
- */
355
- #processAsArray(value, splitByComma) {
356
- return Array.isArray(value) ? value : splitByComma ? value.split(",").map((item) => item.trim()) : [value];
357
- }
358
- /**
359
- * Returns a copy of filters based upon the CLI
360
- * arguments.
361
- */
362
- #getCLIFilters() {
363
- const filters = {};
364
- if (this.#cliArgs.tags) {
365
- filters.tags = this.#processAsArray(this.#cliArgs.tags, true);
366
- }
367
- if (this.#cliArgs.tests) {
368
- filters.tests = this.#processAsArray(this.#cliArgs.tests, false);
369
- }
370
- if (this.#cliArgs.files) {
371
- filters.files = this.#processAsArray(this.#cliArgs.files, true);
372
- }
373
- if (this.#cliArgs.groups) {
374
- filters.groups = this.#processAsArray(this.#cliArgs.groups, false);
375
- }
376
- if (this.#cliArgs._ && this.#cliArgs._.length) {
377
- filters.suites = this.#processAsArray(this.#cliArgs._, true);
378
- }
379
- return filters;
380
- }
381
- /**
382
- * Returns the timeout from the CLI args
383
- */
384
- #getCLITimeout() {
385
- if (this.#cliArgs.timeout) {
386
- const value = Number(this.#cliArgs.timeout);
387
- if (!Number.isNaN(value)) {
388
- return value;
389
- }
390
- }
391
- }
392
- /**
393
- * Returns the retries from the CLI args
394
- */
395
- #getCLIRetries() {
396
- if (this.#cliArgs.retries) {
397
- const value = Number(this.#cliArgs.retries);
398
- if (!Number.isNaN(value)) {
399
- return value;
400
- }
401
- }
402
- }
403
- /**
404
- * Returns the forceExit property from the CLI args
405
- */
406
- #getCLIForceExit() {
407
- if (this.#cliArgs.forceExit) {
408
- return true;
409
- }
410
- }
411
- /**
412
- * Returns reporters selected using the commandline
413
- * --reporter flag
414
- */
415
- #getCLIReporters() {
416
- if (this.#cliArgs.reporters) {
417
- return this.#processAsArray(this.#cliArgs.reporters, true);
418
- }
419
- }
420
- /**
421
- * Hydrates the config with user defined options and the
422
- * command-line flags.
423
- */
424
- hydrate() {
425
- const cliFilters = this.#getCLIFilters();
426
- const cliRetries = this.#getCLIRetries();
427
- const cliTimeout = this.#getCLITimeout();
428
- const cliReporters = this.#getCLIReporters();
429
- const cliForceExit = this.#getCLIForceExit();
430
- debug_default("filters applied using CLI flags %O", cliFilters);
431
- const baseConfig = {
432
- cwd: this.#config.cwd ?? process.cwd(),
433
- exclude: this.#config.exclude || ["node_modules/**", ".git/**", "coverage/**"],
434
- filters: Object.assign({}, this.#config.filters ?? {}, cliFilters),
435
- importer: this.#config.importer ?? DEFAULTS.importer,
436
- refiner: this.#config.refiner ?? new Refiner(),
437
- retries: cliRetries ?? this.#config.retries ?? DEFAULTS.retries,
438
- timeout: cliTimeout ?? this.#config.timeout ?? DEFAULTS.timeout,
439
- plugins: this.#config.plugins ?? DEFAULTS.plugins,
440
- forceExit: cliForceExit ?? this.#config.forceExit ?? DEFAULTS.forceExit,
441
- reporters: this.#config.reporters ? {
442
- activated: this.#config.reporters.activated,
443
- list: this.#config.reporters.list || DEFAULTS.reporters.list
444
- } : DEFAULTS.reporters,
445
- configureSuite: this.#config.configureSuite ?? DEFAULTS.configureSuite,
446
- setup: this.#config.setup || [],
447
- teardown: this.#config.teardown || []
448
- };
449
- if (cliReporters) {
450
- baseConfig.reporters.activated = cliReporters;
451
- }
452
- if ("files" in this.#config) {
453
- return {
454
- files: this.#config.files,
455
- ...baseConfig
456
- };
457
- }
458
- return {
459
- suites: this.#config.suites.map((suite) => {
460
- return {
461
- name: suite.name,
462
- files: suite.files,
463
- timeout: cliTimeout ?? suite.timeout ?? baseConfig.timeout,
464
- retries: cliRetries ?? suite.retries ?? baseConfig.retries,
465
- configure: suite.configure || NOOP
466
- };
467
- }),
468
- ...baseConfig
469
- };
470
- }
471
- };
472
-
473
- // src/create_test.ts
474
- var contextBuilder = (testInstance) => new TestContext(testInstance);
475
- function createTest(title, emitter, refiner, debuggingError, options) {
476
- const testInstance = new Test(title, contextBuilder, emitter, refiner, options.group);
477
- testInstance.options.meta.suite = options.suite;
478
- testInstance.options.meta.group = options.group;
479
- testInstance.options.meta.fileName = options.file;
480
- testInstance.options.meta.abort = (message) => {
481
- debuggingError.message = message;
482
- throw debuggingError;
483
- };
484
- if (options.timeout !== void 0) {
485
- testInstance.timeout(options.timeout);
486
- }
487
- if (options.retries !== void 0) {
488
- testInstance.retry(options.retries);
489
- }
490
- if (options.group) {
491
- options.group.add(testInstance);
492
- } else if (options.suite) {
493
- options.suite.add(testInstance);
494
- }
495
- return testInstance;
496
- }
497
- function createTestGroup(title, emitter, refiner, options) {
498
- if (options.group) {
499
- throw new Error("Nested groups are not supported by Japa");
500
- }
501
- const group = new Group(title, emitter, refiner);
502
- group.options.meta.suite = options.suite;
503
- group.options.meta.fileName = options.file;
504
- if (options.suite) {
505
- options.suite.add(group);
506
- }
507
- return group;
508
- }
509
-
510
- export {
511
- debug_default,
512
- validator_default,
513
- Planner,
514
- GlobalHooks,
515
- CliParser,
516
- ConfigManager,
517
- createTest,
518
- createTestGroup
519
- };