@japa/runner 3.0.3 → 3.0.5

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.
Files changed (38) hide show
  1. package/build/chunk-52OY4QRJ.js +284 -0
  2. package/build/chunk-52OY4QRJ.js.map +1 -0
  3. package/build/chunk-CXTCA2MO.js +503 -0
  4. package/build/chunk-CXTCA2MO.js.map +1 -0
  5. package/build/chunk-MWYEWO7K.js +18 -0
  6. package/build/chunk-MWYEWO7K.js.map +1 -0
  7. package/build/chunk-PKOB3ULJ.js +270 -0
  8. package/build/chunk-PKOB3ULJ.js.map +1 -0
  9. package/build/factories/main.js +214 -29
  10. package/build/factories/main.js.map +1 -0
  11. package/build/index.js +243 -202
  12. package/build/index.js.map +1 -0
  13. package/build/modules/core/main.d.ts +0 -1
  14. package/build/modules/core/main.js +22 -121
  15. package/build/modules/core/main.js.map +1 -0
  16. package/build/src/reporters/main.js +12 -37
  17. package/build/src/reporters/main.js.map +1 -0
  18. package/build/src/types.js +15 -9
  19. package/build/src/types.js.map +1 -0
  20. package/package.json +32 -16
  21. package/build/factories/create_diverse_tests.js +0 -106
  22. package/build/factories/runner.js +0 -93
  23. package/build/modules/core/reporters/base.js +0 -183
  24. package/build/modules/core/types.js +0 -9
  25. package/build/src/cli_parser.js +0 -75
  26. package/build/src/config_manager.js +0 -168
  27. package/build/src/create_test.js +0 -53
  28. package/build/src/debug.js +0 -10
  29. package/build/src/exceptions_manager.js +0 -85
  30. package/build/src/files_manager.js +0 -57
  31. package/build/src/helpers.js +0 -34
  32. package/build/src/hooks.js +0 -46
  33. package/build/src/planner.js +0 -98
  34. package/build/src/plugins/retry.js +0 -74
  35. package/build/src/reporters/dot.js +0 -41
  36. package/build/src/reporters/ndjson.js +0 -86
  37. package/build/src/reporters/spec.js +0 -152
  38. package/build/src/validator.js +0 -85
package/build/index.js CHANGED
@@ -1,214 +1,255 @@
1
- /*
2
- * @japa/runner
3
- *
4
- * (c) Japa
5
- *
6
- * For the full copyright and license information, please view the LICENSE
7
- * file that was distributed with this source code.
8
- */
9
- import { fileURLToPath } from 'node:url';
10
- import { ErrorsPrinter } from '@japa/errors-printer';
11
- import debug from './src/debug.js';
12
- import validator from './src/validator.js';
13
- import { Planner } from './src/planner.js';
14
- import { GlobalHooks } from './src/hooks.js';
15
- import { CliParser } from './src/cli_parser.js';
16
- import { retryPlugin } from './src/plugins/retry.js';
17
- import { ConfigManager } from './src/config_manager.js';
18
- import { ExceptionsManager } from './src/exceptions_manager.js';
19
- import { createTest, createTestGroup } from './src/create_test.js';
20
- import { Emitter, Runner, Suite } from './modules/core/main.js';
21
- /**
22
- * Global emitter instance used by the test
23
- */
24
- const emitter = new Emitter();
25
- /**
26
- * The current active test
27
- */
28
- let activeTest;
29
- /**
30
- * Parsed commandline arguments
31
- */
32
- let cliArgs = {};
33
- /**
34
- * Hydrated config
35
- */
36
- let runnerConfig;
37
- /**
38
- * The state refers to the phase where we configure suites and import
39
- * test files. We stick this metadata to the test instance one can
40
- * later reference within the test.
41
- */
42
- const executionPlanState = {
43
- phase: 'idle',
1
+ import {
2
+ CliParser,
3
+ ConfigManager,
4
+ GlobalHooks,
5
+ Planner,
6
+ createTest,
7
+ createTestGroup,
8
+ debug_default,
9
+ validator_default
10
+ } from "./chunk-CXTCA2MO.js";
11
+ import {
12
+ colors
13
+ } from "./chunk-52OY4QRJ.js";
14
+ import {
15
+ Emitter,
16
+ Runner,
17
+ Suite
18
+ } from "./chunk-PKOB3ULJ.js";
19
+ import "./chunk-MWYEWO7K.js";
20
+
21
+ // index.ts
22
+ import { fileURLToPath } from "node:url";
23
+ import { ErrorsPrinter as ErrorsPrinter2 } from "@japa/errors-printer";
24
+
25
+ // src/plugins/retry.ts
26
+ import { join } from "node:path";
27
+ import findCacheDirectory from "find-cache-dir";
28
+ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
29
+ var CACHE_DIR = findCacheDirectory({ name: "@japa/runner" });
30
+ var SUMMARY_FILE = CACHE_DIR ? join(CACHE_DIR, "summary.json") : void 0;
31
+ async function getFailedTests() {
32
+ try {
33
+ const summary = await readFile(SUMMARY_FILE, "utf-8");
34
+ return JSON.parse(summary);
35
+ } catch (error) {
36
+ if (error.code === "ENOENT") {
37
+ return {};
38
+ }
39
+ throw new Error("Unable to read failed tests cache file", { cause: error });
40
+ }
41
+ }
42
+ async function cacheFailedTests(tests) {
43
+ await mkdir(CACHE_DIR, { recursive: true });
44
+ await writeFile(SUMMARY_FILE, JSON.stringify({ tests }));
45
+ }
46
+ var retryPlugin = async function retry({ config, cliArgs: cliArgs2 }) {
47
+ if (!SUMMARY_FILE) {
48
+ return;
49
+ }
50
+ config.teardown.push(async (runner) => {
51
+ const summary = runner.getSummary();
52
+ await cacheFailedTests(summary.failedTestsTitles);
53
+ });
54
+ if (cliArgs2.failed) {
55
+ try {
56
+ const { tests } = await getFailedTests();
57
+ if (!tests || !tests.length) {
58
+ console.log(colors.bgYellow().black(" No failing tests found. Running all the tests "));
59
+ return;
60
+ }
61
+ config.filters.tests = tests;
62
+ } catch (error) {
63
+ console.log(colors.bgRed().black(" Unable to read failed tests. Running all the tests "));
64
+ console.log(colors.red(error));
65
+ }
66
+ }
44
67
  };
45
- /**
46
- * Create a Japa test. Defining a test without the callback
47
- * will create a todo test.
48
- */
49
- export function test(title, callback) {
50
- validator.ensureIsInPlanningPhase(executionPlanState.phase);
51
- const testInstance = createTest(title, emitter, runnerConfig.refiner, executionPlanState);
52
- testInstance.setup((t) => {
53
- activeTest = t;
54
- return () => {
55
- activeTest = undefined;
56
- };
68
+
69
+ // src/exceptions_manager.ts
70
+ import { ErrorsPrinter } from "@japa/errors-printer";
71
+ var ExceptionsManager = class {
72
+ #exceptionsBuffer = [];
73
+ #rejectionsBuffer = [];
74
+ #state = "watching";
75
+ #errorsPrinter = new ErrorsPrinter({ stackLinesCount: 2, framesMaxLimit: 4 });
76
+ hasErrors = false;
77
+ /**
78
+ * Monitors unhandled exceptions and rejections. The exceptions
79
+ * are stacked in a buffer, so that we do not clutter the
80
+ * tests output and once the tests are over, we will
81
+ * print them to the console.
82
+ *
83
+ * In case the tests are completed, we will print errors as they
84
+ * happen.
85
+ */
86
+ monitor() {
87
+ process.on("uncaughtException", async (error) => {
88
+ this.hasErrors = true;
89
+ if (this.#state === "watching") {
90
+ this.#exceptionsBuffer.push(error);
91
+ } else {
92
+ this.#errorsPrinter.printSectionBorder("[Unhandled Error]");
93
+ await this.#errorsPrinter.printError(error);
94
+ process.exitCode = 1;
95
+ }
96
+ });
97
+ process.on("unhandledRejection", async (error) => {
98
+ this.hasErrors = true;
99
+ if (this.#state === "watching") {
100
+ this.#rejectionsBuffer.push(error);
101
+ } else {
102
+ this.#errorsPrinter.printSectionBorder("[Unhandled Rejection]");
103
+ await this.#errorsPrinter.printError(error);
104
+ process.exitCode = 1;
105
+ }
57
106
  });
58
- if (callback) {
59
- testInstance.run(callback);
107
+ }
108
+ async flow() {
109
+ if (this.#state === "flowing") {
110
+ return;
111
+ }
112
+ this.#state = "flowing";
113
+ if (this.#exceptionsBuffer.length) {
114
+ let exceptionsCount = this.#exceptionsBuffer.length;
115
+ let exceptionsIndex = this.#exceptionsBuffer.length;
116
+ this.#errorsPrinter.printSectionHeader("Unhandled Errors");
117
+ for (let exception of this.#exceptionsBuffer) {
118
+ await this.#errorsPrinter.printError(exception);
119
+ this.#errorsPrinter.printSectionBorder(`[${++exceptionsIndex}/${exceptionsCount}]`);
120
+ }
121
+ this.#exceptionsBuffer = [];
122
+ }
123
+ if (this.#rejectionsBuffer.length) {
124
+ let rejectionsCount = this.#exceptionsBuffer.length;
125
+ let rejectionsIndex = this.#exceptionsBuffer.length;
126
+ this.#errorsPrinter.printSectionBorder("Unhandled Rejections");
127
+ for (let rejection of this.#rejectionsBuffer) {
128
+ await this.#errorsPrinter.printError(rejection);
129
+ this.#errorsPrinter.printSectionBorder(`[${++rejectionsIndex}/${rejectionsCount}]`);
130
+ }
131
+ this.#rejectionsBuffer = [];
60
132
  }
61
- return testInstance;
133
+ }
134
+ };
135
+
136
+ // index.ts
137
+ var emitter = new Emitter();
138
+ var activeTest;
139
+ var cliArgs = {};
140
+ var runnerConfig;
141
+ var executionPlanState = {
142
+ phase: "idle"
143
+ };
144
+ function test(title, callback) {
145
+ validator_default.ensureIsInPlanningPhase(executionPlanState.phase);
146
+ const testInstance = createTest(title, emitter, runnerConfig.refiner, executionPlanState);
147
+ testInstance.setup((t) => {
148
+ activeTest = t;
149
+ return () => {
150
+ activeTest = void 0;
151
+ };
152
+ });
153
+ if (callback) {
154
+ testInstance.run(callback);
155
+ }
156
+ return testInstance;
62
157
  }
63
- /**
64
- * Create a Japa test group
65
- */
66
- test.group = function (title, callback) {
67
- validator.ensureIsInPlanningPhase(executionPlanState.phase);
68
- executionPlanState.group = createTestGroup(title, emitter, runnerConfig.refiner, executionPlanState);
69
- callback(executionPlanState.group);
70
- executionPlanState.group = undefined;
158
+ test.group = function(title, callback) {
159
+ validator_default.ensureIsInPlanningPhase(executionPlanState.phase);
160
+ executionPlanState.group = createTestGroup(
161
+ title,
162
+ emitter,
163
+ runnerConfig.refiner,
164
+ executionPlanState
165
+ );
166
+ callback(executionPlanState.group);
167
+ executionPlanState.group = void 0;
71
168
  };
72
- /**
73
- * Get the test of currently running test
74
- */
75
- export function getActiveTest() {
76
- return activeTest;
169
+ function getActiveTest() {
170
+ return activeTest;
77
171
  }
78
- /**
79
- * Make Japa process command line arguments. Later the parsed output
80
- * will be used by Japa to compute the configuration
81
- */
82
- export function processCLIArgs(argv) {
83
- cliArgs = new CliParser().parse(argv);
172
+ function processCLIArgs(argv) {
173
+ cliArgs = new CliParser().parse(argv);
84
174
  }
85
- /**
86
- * Configure the tests runner with inline configuration. You must
87
- * call configure method before the run method.
88
- *
89
- * Do note: The CLI flags will overwrite the options provided
90
- * to the configure method.
91
- */
92
- export function configure(options) {
93
- runnerConfig = new ConfigManager(options, cliArgs).hydrate();
175
+ function configure(options) {
176
+ runnerConfig = new ConfigManager(options, cliArgs).hydrate();
94
177
  }
95
- /**
96
- * Execute Japa tests. Calling this function will import the test
97
- * files behind the scenes
98
- */
99
- export async function run() {
100
- /**
101
- * Display help when help flag is used
102
- */
103
- if (cliArgs.help) {
104
- console.log(new CliParser().getHelp());
105
- return;
178
+ async function run() {
179
+ if (cliArgs.help) {
180
+ console.log(new CliParser().getHelp());
181
+ return;
182
+ }
183
+ validator_default.ensureIsConfigured(runnerConfig);
184
+ executionPlanState.phase = "planning";
185
+ const runner = new Runner(emitter);
186
+ const globalHooks = new GlobalHooks();
187
+ const exceptionsManager = new ExceptionsManager();
188
+ try {
189
+ await retryPlugin({ config: runnerConfig, runner, emitter, cliArgs });
190
+ for (let plugin of runnerConfig.plugins) {
191
+ debug_default('executing "%s" plugin', plugin.name || "anonymous");
192
+ await plugin({ runner, emitter, cliArgs, config: runnerConfig });
106
193
  }
107
- validator.ensureIsConfigured(runnerConfig);
108
- executionPlanState.phase = 'planning';
109
- const runner = new Runner(emitter);
110
- const globalHooks = new GlobalHooks();
111
- const exceptionsManager = new ExceptionsManager();
112
- try {
113
- /**
114
- * Executing the retry plugin as the first thing
115
- */
116
- await retryPlugin({ config: runnerConfig, runner, emitter, cliArgs });
117
- /**
118
- * Step 1: Executing plugins before creating a plan, so that it can mutate
119
- * the config
120
- */
121
- for (let plugin of runnerConfig.plugins) {
122
- debug('executing "%s" plugin', plugin.name || 'anonymous');
123
- await plugin({ runner, emitter, cliArgs, config: runnerConfig });
124
- }
125
- /**
126
- * Step 2: Creating an execution plan. The output is the result of
127
- * applying all the filters and validations.
128
- */
129
- const { config, reporters, suites, refinerFilters } = await new Planner(runnerConfig).plan();
130
- /**
131
- * Step 3: Registering reporters and filters with the runner
132
- */
133
- reporters.forEach((reporter) => {
134
- debug('registering "%s" reporter', reporter.name);
135
- runner.registerReporter(reporter);
136
- });
137
- refinerFilters.forEach((filter) => {
138
- debug('apply %s filters "%O" ', filter.layer, filter.filters);
139
- config.refiner.add(filter.layer, filter.filters);
140
- });
141
- config.refiner.matchAllTags(cliArgs.matchAll ?? false);
142
- runner.onSuite(config.configureSuite);
143
- /**
144
- * Step 4: Running the setup hooks
145
- */
146
- debug('executing global hooks');
147
- globalHooks.apply(config);
148
- await globalHooks.setup(runner);
149
- /**
150
- * Step 5: Register suites and import test files
151
- */
152
- for (let suite of suites) {
153
- /**
154
- * Creating and configuring the suite
155
- */
156
- executionPlanState.suite = new Suite(suite.name, emitter, config.refiner);
157
- executionPlanState.retries = suite.retries;
158
- executionPlanState.timeout = suite.timeout;
159
- if (typeof suite.configure === 'function') {
160
- suite.configure(executionPlanState.suite);
161
- }
162
- runner.add(executionPlanState.suite);
163
- /**
164
- * Importing suite files
165
- */
166
- for (let fileURL of suite.filesURLs) {
167
- executionPlanState.file = fileURLToPath(fileURL);
168
- debug('importing test file %s', executionPlanState.file);
169
- await config.importer(fileURL);
170
- }
171
- /**
172
- * Resetting global state
173
- */
174
- executionPlanState.suite = undefined;
175
- }
176
- /**
177
- * Onto execution phase
178
- */
179
- executionPlanState.phase = 'executing';
180
- /**
181
- * Monitor for unhandled erorrs and rejections
182
- */
183
- exceptionsManager.monitor();
184
- await runner.start();
185
- await runner.exec();
186
- await globalHooks.teardown(null, runner);
187
- await runner.end();
188
- /**
189
- * Print unhandled errors
190
- */
191
- await exceptionsManager.flow();
192
- const summary = runner.getSummary();
193
- if (summary.hasError || exceptionsManager.hasErrors) {
194
- process.exitCode = 1;
195
- }
196
- if (config.forceExit) {
197
- process.exit();
198
- }
194
+ const { config, reporters, suites, refinerFilters } = await new Planner(runnerConfig).plan();
195
+ reporters.forEach((reporter) => {
196
+ debug_default('registering "%s" reporter', reporter.name);
197
+ runner.registerReporter(reporter);
198
+ });
199
+ refinerFilters.forEach((filter) => {
200
+ debug_default('apply %s filters "%O" ', filter.layer, filter.filters);
201
+ config.refiner.add(filter.layer, filter.filters);
202
+ });
203
+ config.refiner.matchAllTags(cliArgs.matchAll ?? false);
204
+ runner.onSuite(config.configureSuite);
205
+ debug_default("executing global hooks");
206
+ globalHooks.apply(config);
207
+ await globalHooks.setup(runner);
208
+ for (let suite of suites) {
209
+ executionPlanState.suite = new Suite(suite.name, emitter, config.refiner);
210
+ executionPlanState.retries = suite.retries;
211
+ executionPlanState.timeout = suite.timeout;
212
+ if (typeof suite.configure === "function") {
213
+ suite.configure(executionPlanState.suite);
214
+ }
215
+ runner.add(executionPlanState.suite);
216
+ for (let fileURL of suite.filesURLs) {
217
+ executionPlanState.file = fileURLToPath(fileURL);
218
+ debug_default("importing test file %s", executionPlanState.file);
219
+ await config.importer(fileURL);
220
+ }
221
+ executionPlanState.suite = void 0;
199
222
  }
200
- catch (error) {
201
- await globalHooks.teardown(error, runner);
202
- const printer = new ErrorsPrinter();
203
- await printer.printError(error);
204
- /**
205
- * Print unhandled errors in case the code inside
206
- * the try block never got triggered
207
- */
208
- await exceptionsManager.flow();
209
- process.exitCode = 1;
210
- if (runnerConfig.forceExit) {
211
- process.exit();
212
- }
223
+ executionPlanState.phase = "executing";
224
+ exceptionsManager.monitor();
225
+ await runner.start();
226
+ await runner.exec();
227
+ await globalHooks.teardown(null, runner);
228
+ await runner.end();
229
+ await exceptionsManager.flow();
230
+ const summary = runner.getSummary();
231
+ if (summary.hasError || exceptionsManager.hasErrors) {
232
+ process.exitCode = 1;
233
+ }
234
+ if (config.forceExit) {
235
+ process.exit();
213
236
  }
237
+ } catch (error) {
238
+ await globalHooks.teardown(error, runner);
239
+ const printer = new ErrorsPrinter2();
240
+ await printer.printError(error);
241
+ await exceptionsManager.flow();
242
+ process.exitCode = 1;
243
+ if (runnerConfig.forceExit) {
244
+ process.exit();
245
+ }
246
+ }
214
247
  }
248
+ export {
249
+ configure,
250
+ getActiveTest,
251
+ processCLIArgs,
252
+ run,
253
+ test
254
+ };
255
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../index.ts","../src/plugins/retry.ts","../src/exceptions_manager.ts"],"sourcesContent":["/*\n * @japa/runner\n *\n * (c) Japa\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { fileURLToPath } from 'node:url'\nimport { ErrorsPrinter } from '@japa/errors-printer'\nimport type { TestExecutor } from '@japa/core/types'\n\nimport debug from './src/debug.js'\nimport validator from './src/validator.js'\nimport { Planner } from './src/planner.js'\nimport { GlobalHooks } from './src/hooks.js'\nimport { CliParser } from './src/cli_parser.js'\nimport { retryPlugin } from './src/plugins/retry.js'\nimport { ConfigManager } from './src/config_manager.js'\nimport { ExceptionsManager } from './src/exceptions_manager.js'\nimport { createTest, createTestGroup } from './src/create_test.js'\nimport type { CLIArgs, Config, NormalizedConfig } from './src/types.js'\nimport { Emitter, Group, Runner, Suite, Test, TestContext } from './modules/core/main.js'\n\n/**\n * Global emitter instance used by the test\n */\nconst emitter = new Emitter()\n\n/**\n * The current active test\n */\nlet activeTest: Test<any> | undefined\n\n/**\n * Parsed commandline arguments\n */\nlet cliArgs: CLIArgs = {}\n\n/**\n * Hydrated config\n */\nlet runnerConfig: NormalizedConfig | undefined\n\n/**\n * The state refers to the phase where we configure suites and import\n * test files. We stick this metadata to the test instance one can\n * later reference within the test.\n */\nconst executionPlanState: {\n phase: 'idle' | 'planning' | 'executing'\n file?: string\n suite?: Suite\n group?: Group\n timeout?: number\n retries?: number\n} = {\n phase: 'idle',\n}\n\n/**\n * Create a Japa test. Defining a test without the callback\n * will create a todo test.\n */\nexport function test(title: string, callback?: TestExecutor<TestContext, undefined>) {\n validator.ensureIsInPlanningPhase(executionPlanState.phase)\n\n const testInstance = createTest(title, emitter, runnerConfig!.refiner, executionPlanState)\n testInstance.setup((t) => {\n activeTest = t\n return () => {\n activeTest = undefined\n }\n })\n\n if (callback) {\n testInstance.run(callback)\n }\n\n return testInstance\n}\n\n/**\n * Create a Japa test group\n */\ntest.group = function (title: string, callback: (group: Group) => void) {\n validator.ensureIsInPlanningPhase(executionPlanState.phase)\n\n executionPlanState.group = createTestGroup(\n title,\n emitter,\n runnerConfig!.refiner,\n executionPlanState\n )\n callback(executionPlanState.group)\n executionPlanState.group = undefined\n}\n\n/**\n * Get the test of currently running test\n */\nexport function getActiveTest() {\n return activeTest\n}\n\n/**\n * Make Japa process command line arguments. Later the parsed output\n * will be used by Japa to compute the configuration\n */\nexport function processCLIArgs(argv: string[]) {\n cliArgs = new CliParser().parse(argv)\n}\n\n/**\n * Configure the tests runner with inline configuration. You must\n * call configure method before the run method.\n *\n * Do note: The CLI flags will overwrite the options provided\n * to the configure method.\n */\nexport function configure(options: Config) {\n runnerConfig = new ConfigManager(options, cliArgs).hydrate()\n}\n\n/**\n * Execute Japa tests. Calling this function will import the test\n * files behind the scenes\n */\nexport async function run() {\n /**\n * Display help when help flag is used\n */\n if (cliArgs.help) {\n console.log(new CliParser().getHelp())\n return\n }\n\n validator.ensureIsConfigured(runnerConfig)\n\n executionPlanState.phase = 'planning'\n const runner = new Runner(emitter)\n const globalHooks = new GlobalHooks()\n const exceptionsManager = new ExceptionsManager()\n\n try {\n /**\n * Executing the retry plugin as the first thing\n */\n await retryPlugin({ config: runnerConfig!, runner, emitter, cliArgs })\n\n /**\n * Step 1: Executing plugins before creating a plan, so that it can mutate\n * the config\n */\n for (let plugin of runnerConfig!.plugins) {\n debug('executing \"%s\" plugin', plugin.name || 'anonymous')\n await plugin({ runner, emitter, cliArgs, config: runnerConfig! })\n }\n\n /**\n * Step 2: Creating an execution plan. The output is the result of\n * applying all the filters and validations.\n */\n const { config, reporters, suites, refinerFilters } = await new Planner(runnerConfig!).plan()\n\n /**\n * Step 3: Registering reporters and filters with the runner\n */\n reporters.forEach((reporter) => {\n debug('registering \"%s\" reporter', reporter.name)\n runner.registerReporter(reporter)\n })\n refinerFilters.forEach((filter) => {\n debug('apply %s filters \"%O\" ', filter.layer, filter.filters)\n config.refiner.add(filter.layer, filter.filters)\n })\n config.refiner.matchAllTags(cliArgs.matchAll ?? false)\n runner.onSuite(config.configureSuite)\n\n /**\n * Step 4: Running the setup hooks\n */\n debug('executing global hooks')\n globalHooks.apply(config)\n await globalHooks.setup(runner)\n\n /**\n * Step 5: Register suites and import test files\n */\n for (let suite of suites) {\n /**\n * Creating and configuring the suite\n */\n executionPlanState.suite = new Suite(suite.name, emitter, config.refiner)\n executionPlanState.retries = suite.retries\n executionPlanState.timeout = suite.timeout\n if (typeof suite.configure === 'function') {\n suite.configure(executionPlanState.suite)\n }\n runner.add(executionPlanState.suite)\n\n /**\n * Importing suite files\n */\n for (let fileURL of suite.filesURLs) {\n executionPlanState.file = fileURLToPath(fileURL)\n debug('importing test file %s', executionPlanState.file)\n await config.importer(fileURL)\n }\n\n /**\n * Resetting global state\n */\n executionPlanState.suite = undefined\n }\n\n /**\n * Onto execution phase\n */\n executionPlanState.phase = 'executing'\n\n /**\n * Monitor for unhandled erorrs and rejections\n */\n exceptionsManager.monitor()\n\n await runner.start()\n await runner.exec()\n\n await globalHooks.teardown(null, runner)\n await runner.end()\n\n /**\n * Print unhandled errors\n */\n await exceptionsManager.flow()\n\n const summary = runner.getSummary()\n if (summary.hasError || exceptionsManager.hasErrors) {\n process.exitCode = 1\n }\n if (config.forceExit) {\n process.exit()\n }\n } catch (error) {\n await globalHooks.teardown(error, runner)\n const printer = new ErrorsPrinter()\n await printer.printError(error)\n\n /**\n * Print unhandled errors in case the code inside\n * the try block never got triggered\n */\n await exceptionsManager.flow()\n\n process.exitCode = 1\n if (runnerConfig!.forceExit) {\n process.exit()\n }\n }\n}\n","/*\n * @japa/runner\n *\n * (c) Japa\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { join } from 'node:path'\nimport findCacheDirectory from 'find-cache-dir'\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises'\n\nimport { colors } from '../helpers.js'\nimport type { PluginFn } from '../types.js'\n\n/**\n * Paths to the cache directory and the summary file\n */\nconst CACHE_DIR = findCacheDirectory({ name: '@japa/runner' })\nconst SUMMARY_FILE = CACHE_DIR ? join(CACHE_DIR, 'summary.json') : undefined\n\n/**\n * Returns an object with the title of the tests failed during\n * the last run.\n */\nexport async function getFailedTests(): Promise<{ tests?: string[] }> {\n try {\n const summary = await readFile(SUMMARY_FILE!, 'utf-8')\n return JSON.parse(summary)\n } catch (error) {\n if (error.code === 'ENOENT') {\n return {}\n }\n throw new Error('Unable to read failed tests cache file', { cause: error })\n }\n}\n\n/**\n * Writes failing tests to the cache directory\n */\nexport async function cacheFailedTests(tests: string[]) {\n await mkdir(CACHE_DIR!, { recursive: true })\n await writeFile(SUMMARY_FILE!, JSON.stringify({ tests: tests }))\n}\n\n/**\n * Clears the cache dir\n */\nexport async function clearCache() {\n await unlink(SUMMARY_FILE!)\n}\n\n/**\n * Exposes the API to run failing tests using the \"failed\" CLI flag.\n */\nexport const retryPlugin: PluginFn = async function retry({ config, cliArgs }) {\n if (!SUMMARY_FILE) {\n return\n }\n\n config.teardown.push(async (runner) => {\n const summary = runner.getSummary()\n await cacheFailedTests(summary.failedTestsTitles)\n })\n\n if (cliArgs.failed) {\n try {\n const { tests } = await getFailedTests()\n if (!tests || !tests.length) {\n console.log(colors.bgYellow().black(' No failing tests found. Running all the tests '))\n return\n }\n config.filters.tests = tests\n } catch (error) {\n console.log(colors.bgRed().black(' Unable to read failed tests. Running all the tests '))\n console.log(colors.red(error))\n }\n }\n}\n","/*\n * @japa/runner\n *\n * (c) Japa\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { ErrorsPrinter } from '@japa/errors-printer'\n\n/**\n * Handles uncaught exceptions and prints them to the\n * console\n */\nexport class ExceptionsManager {\n #exceptionsBuffer: any[] = []\n #rejectionsBuffer: any[] = []\n #state: 'watching' | 'flowing' = 'watching'\n #errorsPrinter = new ErrorsPrinter({ stackLinesCount: 2, framesMaxLimit: 4 })\n\n hasErrors: boolean = false\n\n /**\n * Monitors unhandled exceptions and rejections. The exceptions\n * are stacked in a buffer, so that we do not clutter the\n * tests output and once the tests are over, we will\n * print them to the console.\n *\n * In case the tests are completed, we will print errors as they\n * happen.\n */\n monitor() {\n process.on('uncaughtException', async (error) => {\n this.hasErrors = true\n if (this.#state === 'watching') {\n this.#exceptionsBuffer.push(error)\n } else {\n this.#errorsPrinter.printSectionBorder('[Unhandled Error]')\n await this.#errorsPrinter.printError(error)\n process.exitCode = 1\n }\n })\n\n process.on('unhandledRejection', async (error) => {\n this.hasErrors = true\n if (this.#state === 'watching') {\n this.#rejectionsBuffer.push(error)\n } else {\n this.#errorsPrinter.printSectionBorder('[Unhandled Rejection]')\n await this.#errorsPrinter.printError(error)\n process.exitCode = 1\n }\n })\n }\n\n async flow() {\n if (this.#state === 'flowing') {\n return\n }\n\n this.#state = 'flowing'\n\n /**\n * Print exceptions\n */\n if (this.#exceptionsBuffer.length) {\n let exceptionsCount = this.#exceptionsBuffer.length\n let exceptionsIndex = this.#exceptionsBuffer.length\n this.#errorsPrinter.printSectionHeader('Unhandled Errors')\n for (let exception of this.#exceptionsBuffer) {\n await this.#errorsPrinter.printError(exception)\n this.#errorsPrinter.printSectionBorder(`[${++exceptionsIndex}/${exceptionsCount}]`)\n }\n this.#exceptionsBuffer = []\n }\n\n /**\n * Print rejections\n */\n if (this.#rejectionsBuffer.length) {\n let rejectionsCount = this.#exceptionsBuffer.length\n let rejectionsIndex = this.#exceptionsBuffer.length\n this.#errorsPrinter.printSectionBorder('Unhandled Rejections')\n for (let rejection of this.#rejectionsBuffer) {\n await this.#errorsPrinter.printError(rejection)\n this.#errorsPrinter.printSectionBorder(`[${++rejectionsIndex}/${rejectionsCount}]`)\n }\n this.#rejectionsBuffer = []\n }\n }\n}\n"],"mappings":"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","names":["ErrorsPrinter","cliArgs","ErrorsPrinter"]}
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import { Emitter, Refiner, Test as BaseTest, Suite as BaseSuite, Group as BaseGroup, Runner as BaseRunner, TestContext as BaseTestContext } from '@japa/core';
3
2
  import { BaseReporter } from './reporters/base.js';
4
3
  import type { DataSetNode, TestHooksCleanupHandler } from './types.js';
@@ -1,121 +1,22 @@
1
- /*
2
- * @japa/runner
3
- *
4
- * (c) Japa
5
- *
6
- * For the full copyright and license information, please view the LICENSE
7
- * file that was distributed with this source code.
8
- */
9
- import { Emitter, Refiner, Test as BaseTest, Suite as BaseSuite, Group as BaseGroup, Runner as BaseRunner, TestContext as BaseTestContext, } from '@japa/core';
10
- import { inspect } from 'node:util';
11
- import { AssertionError } from 'node:assert';
12
- import { BaseReporter } from './reporters/base.js';
13
- export { Emitter, Refiner, BaseReporter };
14
- /**
15
- * Test context carries context data for a given test.
16
- */
17
- export class TestContext extends BaseTestContext {
18
- test;
19
- constructor(test) {
20
- super();
21
- this.test = test;
22
- this.cleanup = (cleanupCallback) => {
23
- test.cleanup(cleanupCallback);
24
- };
25
- }
26
- }
27
- /**
28
- * Test class represents an individual test and exposes API to tweak
29
- * its runtime behavior.
30
- */
31
- export class Test extends BaseTest {
32
- /**
33
- * @inheritdoc
34
- */
35
- static executedCallbacks = [];
36
- /**
37
- * @inheritdoc
38
- */
39
- static executingCallbacks = [];
40
- /**
41
- * Assert the test callback throws an exception when a certain
42
- * error message and optionally is an instance of a given
43
- * Error class.
44
- */
45
- throws(message, errorConstructor) {
46
- const errorInPoint = new AssertionError({});
47
- const existingExecutor = this.options.executor;
48
- if (!existingExecutor) {
49
- throw new Error('Cannot use "test.throws" method without a test callback');
50
- }
51
- /**
52
- * Overwriting existing callback
53
- */
54
- this.options.executor = async (...args) => {
55
- let raisedException;
56
- try {
57
- await existingExecutor(...args);
58
- }
59
- catch (error) {
60
- raisedException = error;
61
- }
62
- /**
63
- * Notify no exception has been raised
64
- */
65
- if (!raisedException) {
66
- errorInPoint.message = 'Expected test to throw an exception';
67
- throw errorInPoint;
68
- }
69
- /**
70
- * Constructor mis-match
71
- */
72
- if (errorConstructor && !(raisedException instanceof errorConstructor)) {
73
- errorInPoint.message = `Expected test to throw "${inspect(errorConstructor)}"`;
74
- throw errorInPoint;
75
- }
76
- /**
77
- * Error does not have a message property
78
- */
79
- const exceptionMessage = raisedException.message;
80
- if (!exceptionMessage || typeof exceptionMessage !== 'string') {
81
- errorInPoint.message = 'Expected test to throw an exception with message property';
82
- throw errorInPoint;
83
- }
84
- /**
85
- * Message does not match
86
- */
87
- if (typeof message === 'string') {
88
- if (exceptionMessage !== message) {
89
- errorInPoint.message = `Expected test to throw "${message}". Instead received "${raisedException.message}"`;
90
- errorInPoint.actual = raisedException.message;
91
- errorInPoint.expected = message;
92
- throw errorInPoint;
93
- }
94
- return;
95
- }
96
- if (!message.test(exceptionMessage)) {
97
- errorInPoint.message = `Expected test error to match "${message}" regular expression`;
98
- throw errorInPoint;
99
- }
100
- };
101
- return this;
102
- }
103
- }
104
- /**
105
- * TestGroup is used to bulk configure a collection of tests and
106
- * define lifecycle hooks for them
107
- */
108
- export class Group extends BaseGroup {
109
- }
110
- /**
111
- * A suite is a collection of tests created around a given
112
- * testing type. For example: A suite for unit tests, a
113
- * suite for functional tests and so on.
114
- */
115
- export class Suite extends BaseSuite {
116
- }
117
- /**
118
- * Runner class is used to execute the tests
119
- */
120
- export class Runner extends BaseRunner {
121
- }
1
+ import {
2
+ BaseReporter,
3
+ Emitter,
4
+ Group,
5
+ Refiner,
6
+ Runner,
7
+ Suite,
8
+ Test,
9
+ TestContext
10
+ } from "../../chunk-PKOB3ULJ.js";
11
+ import "../../chunk-MWYEWO7K.js";
12
+ export {
13
+ BaseReporter,
14
+ Emitter,
15
+ Group,
16
+ Refiner,
17
+ Runner,
18
+ Suite,
19
+ Test,
20
+ TestContext
21
+ };
22
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}