@japa/runner 3.1.3 → 3.1.4

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.
@@ -13,9 +13,33 @@ import { AssertionError } from "node:assert";
13
13
 
14
14
  // modules/core/reporters/base.ts
15
15
  import ms from "ms";
16
- import colors from "@poppinss/colors";
16
+
17
+ // src/helpers.ts
18
+ import useColors from "@poppinss/colors";
19
+ import supportsColor from "supports-color";
20
+ var colors = supportsColor.stdout ? useColors.ansi() : useColors.silent();
21
+ var icons = process.platform === "win32" && !process.env.WT_SESSION ? {
22
+ tick: "\u221A",
23
+ cross: "\xD7",
24
+ bullet: "*",
25
+ nodejs: "\u2666",
26
+ pointer: ">",
27
+ info: "i",
28
+ warning: "\u203C",
29
+ squareSmallFilled: "[\u2588]"
30
+ } : {
31
+ tick: "\u2714",
32
+ cross: "\u2716",
33
+ bullet: "\u25CF",
34
+ nodejs: "\u2B22",
35
+ pointer: "\u276F",
36
+ info: "\u2139",
37
+ warning: "\u26A0",
38
+ squareSmallFilled: "\u25FC"
39
+ };
40
+
41
+ // modules/core/reporters/base.ts
17
42
  import { ErrorsPrinter } from "@japa/errors-printer";
18
- var ansi = colors.ansi();
19
43
  var BaseReporter = class {
20
44
  #options;
21
45
  runner;
@@ -40,29 +64,29 @@ var BaseReporter = class {
40
64
  #printAggregates(summary) {
41
65
  const tests = [];
42
66
  if (summary.aggregates.passed) {
43
- tests.push(ansi.green(`${summary.aggregates.passed} passed`));
67
+ tests.push(colors.green(`${summary.aggregates.passed} passed`));
44
68
  }
45
69
  if (summary.aggregates.failed) {
46
- tests.push(ansi.red(`${summary.aggregates.failed} failed`));
70
+ tests.push(colors.red(`${summary.aggregates.failed} failed`));
47
71
  }
48
72
  if (summary.aggregates.todo) {
49
- tests.push(ansi.cyan(`${summary.aggregates.todo} todo`));
73
+ tests.push(colors.cyan(`${summary.aggregates.todo} todo`));
50
74
  }
51
75
  if (summary.aggregates.skipped) {
52
- tests.push(ansi.yellow(`${summary.aggregates.skipped} skipped`));
76
+ tests.push(colors.yellow(`${summary.aggregates.skipped} skipped`));
53
77
  }
54
78
  if (summary.aggregates.regression) {
55
- tests.push(ansi.magenta(`${summary.aggregates.regression} regression`));
79
+ tests.push(colors.magenta(`${summary.aggregates.regression} regression`));
56
80
  }
57
81
  this.runner.summaryBuilder.use(() => {
58
82
  return [
59
83
  {
60
- key: ansi.dim("Tests"),
61
- value: `${tests.join(", ")} ${ansi.dim(`(${summary.aggregates.total})`)}`
84
+ key: colors.dim("Tests"),
85
+ value: `${tests.join(", ")} ${colors.dim(`(${summary.aggregates.total})`)}`
62
86
  },
63
87
  {
64
- key: ansi.dim("Time"),
65
- value: ansi.dim(ms(summary.duration))
88
+ key: colors.dim("Time"),
89
+ value: colors.dim(ms(summary.duration))
66
90
  }
67
91
  ];
68
92
  });
@@ -134,13 +158,13 @@ var BaseReporter = class {
134
158
  await this.#printErrors(summary);
135
159
  console.log("");
136
160
  if (summary.aggregates.total === 0 && !summary.hasError) {
137
- console.log(ansi.bgYellow().black(" NO TESTS EXECUTED "));
161
+ console.log(colors.bgYellow().black(" NO TESTS EXECUTED "));
138
162
  return;
139
163
  }
140
164
  if (summary.hasError) {
141
- console.log(ansi.bgRed().black(" FAILED "));
165
+ console.log(colors.bgRed().black(" FAILED "));
142
166
  } else {
143
- console.log(ansi.bgGreen().black(" PASSED "));
167
+ console.log(colors.bgGreen().black(" PASSED "));
144
168
  }
145
169
  console.log("");
146
170
  this.#printAggregates(summary);
@@ -258,6 +282,8 @@ var Runner = class extends BaseRunner {
258
282
  };
259
283
 
260
284
  export {
285
+ colors,
286
+ icons,
261
287
  BaseReporter,
262
288
  Emitter,
263
289
  Refiner,
@@ -267,4 +293,4 @@ export {
267
293
  Suite,
268
294
  Runner
269
295
  };
270
- //# sourceMappingURL=chunk-PKOB3ULJ.js.map
296
+ //# sourceMappingURL=chunk-BFNOUWI5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../modules/core/main.ts","../modules/core/reporters/base.ts","../src/helpers.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 {\n Emitter,\n Refiner,\n Test as BaseTest,\n Suite as BaseSuite,\n Group as BaseGroup,\n Runner as BaseRunner,\n TestContext as BaseTestContext,\n} from '@japa/core'\nimport { inspect } from 'node:util'\nimport { AssertionError } from 'node:assert'\nimport { BaseReporter } from './reporters/base.js'\nimport type { DataSetNode, TestHooksCleanupHandler } from './types.js'\n\ndeclare module '@japa/core' {\n interface Test<Context extends Record<any, any>, TestData extends DataSetNode = undefined> {\n throws(message: string | RegExp, errorConstructor?: any): this\n }\n interface TestContext {\n cleanup: (cleanupCallback: TestHooksCleanupHandler<TestContext>) => void\n }\n}\n\nexport { Emitter, Refiner, BaseReporter }\n\n/**\n * Test context carries context data for a given test.\n */\nexport class TestContext extends BaseTestContext {\n /**\n * Register a cleanup function that runs after the test finishes\n * successfully or with an error.\n */\n declare cleanup: (cleanupCallback: TestHooksCleanupHandler<TestContext>) => void\n\n constructor(public test: Test) {\n super()\n this.cleanup = (cleanupCallback: TestHooksCleanupHandler<TestContext>) => {\n test.cleanup(cleanupCallback)\n }\n }\n}\n\n/**\n * Test class represents an individual test and exposes API to tweak\n * its runtime behavior.\n */\nexport class Test<TestData extends DataSetNode = undefined> extends BaseTest<\n TestContext,\n TestData\n> {\n /**\n * @inheritdoc\n */\n static executedCallbacks = []\n\n /**\n * @inheritdoc\n */\n static executingCallbacks = []\n\n /**\n * Assert the test callback throws an exception when a certain\n * error message and optionally is an instance of a given\n * Error class.\n */\n throws(message: string | RegExp, errorConstructor?: any) {\n const errorInPoint = new AssertionError({})\n const existingExecutor = this.options.executor\n if (!existingExecutor) {\n throw new Error('Cannot use \"test.throws\" method without a test callback')\n }\n\n /**\n * Overwriting existing callback\n */\n this.options.executor = async (...args: [any, any, any]) => {\n let raisedException: any\n try {\n await existingExecutor(...args)\n } catch (error) {\n raisedException = error\n }\n\n /**\n * Notify no exception has been raised\n */\n if (!raisedException) {\n errorInPoint.message = 'Expected test to throw an exception'\n throw errorInPoint\n }\n\n /**\n * Constructor mis-match\n */\n if (errorConstructor && !(raisedException instanceof errorConstructor)) {\n errorInPoint.message = `Expected test to throw \"${inspect(errorConstructor)}\"`\n throw errorInPoint\n }\n\n /**\n * Error does not have a message property\n */\n const exceptionMessage: unknown = raisedException.message\n if (!exceptionMessage || typeof exceptionMessage !== 'string') {\n errorInPoint.message = 'Expected test to throw an exception with message property'\n throw errorInPoint\n }\n\n /**\n * Message does not match\n */\n if (typeof message === 'string') {\n if (exceptionMessage !== message) {\n errorInPoint.message = `Expected test to throw \"${message}\". Instead received \"${raisedException.message}\"`\n errorInPoint.actual = raisedException.message\n errorInPoint.expected = message\n throw errorInPoint\n }\n return\n }\n\n if (!message.test(exceptionMessage)) {\n errorInPoint.message = `Expected test error to match \"${message}\" regular expression`\n throw errorInPoint\n }\n }\n\n return this\n }\n}\n\n/**\n * TestGroup is used to bulk configure a collection of tests and\n * define lifecycle hooks for them\n */\nexport class Group extends BaseGroup<TestContext> {}\n\n/**\n * A suite is a collection of tests created around a given\n * testing type. For example: A suite for unit tests, a\n * suite for functional tests and so on.\n */\nexport class Suite extends BaseSuite<TestContext> {}\n\n/**\n * Runner class is used to execute the tests\n */\nexport class Runner extends BaseRunner<TestContext> {}\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 ms from 'ms'\nimport { colors } from '../../../src/helpers.js'\nimport { ErrorsPrinter } from '@japa/errors-printer'\n\nimport type {\n TestEndNode,\n SuiteEndNode,\n GroupEndNode,\n TestStartNode,\n RunnerSummary,\n RunnerEndNode,\n GroupStartNode,\n SuiteStartNode,\n RunnerStartNode,\n BaseReporterOptions,\n} from '../types.js'\nimport { Emitter, Runner } from '../main.js'\n\n/**\n * Base reporter to build custom reporters on top of\n */\nexport abstract class BaseReporter {\n #options: BaseReporterOptions\n runner?: Runner\n\n /**\n * Path to the file for which the tests are getting executed\n */\n currentFileName?: string\n\n /**\n * Suite for which the tests are getting executed\n */\n currentSuiteName?: string\n\n /**\n * Group for which the tests are getting executed\n */\n currentGroupName?: string\n\n constructor(options: BaseReporterOptions = {}) {\n this.#options = Object.assign({ stackLinesCount: 2 }, options)\n }\n\n /**\n * Pretty prints the aggregates\n */\n #printAggregates(summary: RunnerSummary) {\n const tests: string[] = []\n\n /**\n * Set value for tests row\n */\n if (summary.aggregates.passed) {\n tests.push(colors.green(`${summary.aggregates.passed} passed`))\n }\n if (summary.aggregates.failed) {\n tests.push(colors.red(`${summary.aggregates.failed} failed`))\n }\n if (summary.aggregates.todo) {\n tests.push(colors.cyan(`${summary.aggregates.todo} todo`))\n }\n if (summary.aggregates.skipped) {\n tests.push(colors.yellow(`${summary.aggregates.skipped} skipped`))\n }\n if (summary.aggregates.regression) {\n tests.push(colors.magenta(`${summary.aggregates.regression} regression`))\n }\n\n this.runner!.summaryBuilder.use(() => {\n return [\n {\n key: colors.dim('Tests'),\n value: `${tests.join(', ')} ${colors.dim(`(${summary.aggregates.total})`)}`,\n },\n {\n key: colors.dim('Time'),\n value: colors.dim(ms(summary.duration)),\n },\n ]\n })\n\n console.log(this.runner!.summaryBuilder.build().join('\\n'))\n }\n\n /**\n * Aggregates errors tree to a flat array\n */\n #aggregateErrors(summary: RunnerSummary) {\n const errorsList: { phase: string; title: string; error: Error }[] = []\n\n summary.failureTree.forEach((suite) => {\n suite.errors.forEach((error) => errorsList.push({ title: suite.name, ...error }))\n\n suite.children.forEach((testOrGroup) => {\n /**\n * Suite child is a test\n */\n if (testOrGroup.type === 'test') {\n testOrGroup.errors.forEach((error) => {\n errorsList.push({ title: `${suite.name} / ${testOrGroup.title}`, ...error })\n })\n return\n }\n\n /**\n * Suite child is a group\n */\n testOrGroup.errors.forEach((error) => {\n errorsList.push({ title: testOrGroup.name, ...error })\n })\n testOrGroup.children.forEach((test) => {\n test.errors.forEach((error) => {\n errorsList.push({ title: `${testOrGroup.name} / ${test.title}`, ...error })\n })\n })\n })\n })\n\n return errorsList\n }\n\n /**\n * Pretty print errors\n */\n async #printErrors(summary: RunnerSummary) {\n if (!summary.failureTree.length) {\n return\n }\n\n const errorPrinter = new ErrorsPrinter({\n stackLinesCount: this.#options.stackLinesCount,\n framesMaxLimit: this.#options.framesMaxLimit,\n })\n\n errorPrinter.printSectionHeader('ERRORS')\n await errorPrinter.printErrors(this.#aggregateErrors(summary))\n }\n\n /**\n * Handlers to capture events\n */\n protected onTestStart(_: TestStartNode): void {}\n protected onTestEnd(_: TestEndNode) {}\n\n protected onGroupStart(_: GroupStartNode) {}\n protected onGroupEnd(_: GroupEndNode) {}\n\n protected onSuiteStart(_: SuiteStartNode) {}\n protected onSuiteEnd(_: SuiteEndNode) {}\n\n protected async start(_: RunnerStartNode) {}\n protected async end(_: RunnerEndNode) {}\n\n /**\n * Print tests summary\n */\n protected async printSummary(summary: RunnerSummary) {\n await this.#printErrors(summary)\n\n console.log('')\n if (summary.aggregates.total === 0 && !summary.hasError) {\n console.log(colors.bgYellow().black(' NO TESTS EXECUTED '))\n return\n }\n\n if (summary.hasError) {\n console.log(colors.bgRed().black(' FAILED '))\n } else {\n console.log(colors.bgGreen().black(' PASSED '))\n }\n console.log('')\n this.#printAggregates(summary)\n }\n\n /**\n * Invoked by the tests runner when tests are about to start\n */\n boot(runner: Runner, emitter: Emitter) {\n this.runner = runner\n\n emitter.on('test:start', (payload) => {\n this.currentFileName = payload.meta.fileName\n this.onTestStart(payload)\n })\n\n emitter.on('test:end', (payload) => {\n this.onTestEnd(payload)\n })\n\n emitter.on('group:start', (payload) => {\n this.currentGroupName = payload.title\n this.currentFileName = payload.meta.fileName\n this.onGroupStart(payload)\n })\n\n emitter.on('group:end', (payload) => {\n this.currentGroupName = undefined\n this.onGroupEnd(payload)\n })\n\n emitter.on('suite:start', (payload) => {\n this.currentSuiteName = payload.name\n this.onSuiteStart(payload)\n })\n\n emitter.on('suite:end', (payload) => {\n this.currentSuiteName = undefined\n this.onSuiteEnd(payload)\n })\n\n emitter.on('runner:start', async (payload) => {\n await this.start(payload)\n })\n\n emitter.on('runner:end', async (payload) => {\n await this.end(payload)\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 useColors from '@poppinss/colors'\nimport supportsColor from 'supports-color'\nimport { Colors } from '@poppinss/colors/types'\n\nexport const colors: Colors = supportsColor.stdout ? useColors.ansi() : useColors.silent()\n\n/**\n * A collection of platform specific icons\n */\nexport const icons =\n process.platform === 'win32' && !process.env.WT_SESSION\n ? {\n tick: '√',\n cross: '×',\n bullet: '*',\n nodejs: '♦',\n pointer: '>',\n info: 'i',\n warning: '‼',\n squareSmallFilled: '[█]',\n }\n : {\n tick: '✔',\n cross: '✖',\n bullet: '●',\n nodejs: '⬢',\n pointer: '❯',\n info: 'ℹ',\n warning: '⚠',\n squareSmallFilled: '◼',\n }\n"],"mappings":"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","names":[]}
@@ -1,15 +1,15 @@
1
1
  import {
2
- colors,
3
2
  dot,
4
3
  ndjson,
5
4
  spec
6
- } from "./chunk-LRVNUQHW.js";
5
+ } from "./chunk-PHC5CJQG.js";
7
6
  import {
8
7
  Group,
9
8
  Refiner,
10
9
  Test,
11
- TestContext
12
- } from "./chunk-PKOB3ULJ.js";
10
+ TestContext,
11
+ colors
12
+ } from "./chunk-BFNOUWI5.js";
13
13
 
14
14
  // src/debug.ts
15
15
  import { debuglog } from "node:util";
@@ -501,4 +501,4 @@ export {
501
501
  createTest,
502
502
  createTestGroup
503
503
  };
504
- //# sourceMappingURL=chunk-CYPN7IGE.js.map
504
+ //# sourceMappingURL=chunk-NVI2OU43.js.map
@@ -1,30 +1,8 @@
1
1
  import {
2
- BaseReporter
3
- } from "./chunk-PKOB3ULJ.js";
4
-
5
- // src/helpers.ts
6
- import useColors from "@poppinss/colors";
7
- import supportsColor from "supports-color";
8
- var colors = supportsColor.stdout ? useColors.ansi() : useColors.silent();
9
- var icons = process.platform === "win32" && !process.env.WT_SESSION ? {
10
- tick: "\u221A",
11
- cross: "\xD7",
12
- bullet: "*",
13
- nodejs: "\u2666",
14
- pointer: ">",
15
- info: "i",
16
- warning: "\u203C",
17
- squareSmallFilled: "[\u2588]"
18
- } : {
19
- tick: "\u2714",
20
- cross: "\u2716",
21
- bullet: "\u25CF",
22
- nodejs: "\u2B22",
23
- pointer: "\u276F",
24
- info: "\u2139",
25
- warning: "\u26A0",
26
- squareSmallFilled: "\u25FC"
27
- };
2
+ BaseReporter,
3
+ colors,
4
+ icons
5
+ } from "./chunk-BFNOUWI5.js";
28
6
 
29
7
  // src/reporters/dot.ts
30
8
  var DotReporter = class extends BaseReporter {
@@ -277,9 +255,8 @@ var ndjson = (options) => {
277
255
  };
278
256
 
279
257
  export {
280
- colors,
281
258
  spec,
282
259
  dot,
283
260
  ndjson
284
261
  };
285
- //# sourceMappingURL=chunk-LRVNUQHW.js.map
262
+ //# sourceMappingURL=chunk-PHC5CJQG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/reporters/dot.ts","../src/reporters/spec.ts","../src/reporters/ndjson.ts","../src/reporters/main.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 { colors, icons } from '../helpers.js'\nimport type { TestEndNode } from '../../modules/core/types.js'\nimport { BaseReporter } from '../../modules/core/reporters/base.js'\n\n/**\n * Minimal reporter that prints each test as an icon.\n */\nexport class DotReporter extends BaseReporter {\n /**\n * When a test ended\n */\n protected onTestEnd(payload: TestEndNode) {\n let output = ''\n if (payload.isTodo) {\n output = colors.cyan(icons.info)\n } else if (payload.hasError || payload.isFailing) {\n output = payload.hasError ? colors.magenta(icons.squareSmallFilled) : colors.red(icons.cross)\n } else if (payload.isSkipped) {\n output = colors.yellow(icons.bullet)\n } else {\n output = colors.green(icons.tick)\n }\n\n process.stdout.write(`${output}`)\n }\n\n /**\n * When test runner ended\n */\n protected async end() {\n console.log('')\n await this.printSummary(this.runner!.getSummary())\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 ms from 'ms'\nimport { relative } from 'node:path'\n\nimport { colors, icons } from '../helpers.js'\nimport { BaseReporter } from '../../modules/core/main.js'\nimport { GroupStartNode, TestEndNode } from '../../modules/core/types.js'\n\n/**\n * Pretty prints the tests on the console\n */\nexport class SpecReporter extends BaseReporter {\n /**\n * Tracking if the first event we get is for a test without any parent group\n * We need this to decide the display style for tests without groups.\n */\n #isFirstLoneTest = true\n\n /**\n * Returns the icon for the test\n */\n #getTestIcon(payload: TestEndNode) {\n if (payload.isTodo) {\n return colors.cyan(icons.info)\n }\n\n if (payload.isFailing) {\n return payload.hasError ? colors.magenta(icons.squareSmallFilled) : colors.red(icons.cross)\n }\n\n if (payload.hasError) {\n return colors.red(icons.cross)\n }\n\n if (payload.isSkipped) {\n return colors.yellow(icons.bullet)\n }\n\n return colors.green(icons.tick)\n }\n\n /**\n * Returns the test message\n */\n #getTestMessage(payload: TestEndNode) {\n const message = payload.title.expanded\n\n if (payload.isTodo) {\n return colors.blue(message)\n }\n\n if (payload.isFailing) {\n return payload.hasError ? colors.magenta(message) : colors.red(message)\n }\n\n if (payload.hasError) {\n return colors.red(message)\n }\n\n if (payload.isSkipped) {\n return colors.yellow(message)\n }\n\n return colors.grey(message)\n }\n\n /**\n * Returns the subtext message for the test\n */\n #getSubText(payload: TestEndNode): string | undefined {\n if (payload.isSkipped && payload.skipReason) {\n return colors.yellow(payload.skipReason)\n }\n\n if (!payload.isFailing) {\n return\n }\n\n if (!payload.hasError) {\n return colors.magenta(`Test marked with \".fails()\" must finish with an error`)\n }\n\n if (payload.failReason) {\n return colors.magenta(payload.failReason)\n }\n\n const testErrorMessage = payload.errors.find((error) => error.phase === 'test')\n if (testErrorMessage && testErrorMessage.error) {\n return colors.magenta(testErrorMessage.error.message)\n }\n }\n\n /**\n * Returns the filename relative from the current working dir\n */\n #getRelativeFilename(fileName: string) {\n return relative(process.cwd(), fileName)\n }\n\n /**\n * Prints the test details\n */\n #printTest(payload: TestEndNode) {\n const icon = this.#getTestIcon(payload)\n const message = this.#getTestMessage(payload)\n const prefix = payload.isPinned ? colors.yellow('[PINNED] ') : ''\n const indentation = this.currentFileName || this.currentGroupName ? ' ' : ''\n const duration = colors.dim(`(${ms(Number(payload.duration.toFixed(2)))})`)\n const retries =\n payload.retryAttempt && payload.retryAttempt > 1\n ? colors.dim(`(x${payload.retryAttempt}) `)\n : ''\n\n let subText = this.#getSubText(payload)\n subText = subText ? `\\n${indentation} ${subText}` : ''\n\n console.log(`${indentation}${icon} ${prefix}${retries}${message} ${duration}${subText}`)\n }\n\n /**\n * Prints the group name\n */\n #printGroup(payload: GroupStartNode) {\n const title =\n this.currentSuiteName !== 'default'\n ? `${this.currentSuiteName} / ${payload.title}`\n : payload.title\n\n const suffix = this.currentFileName\n ? colors.dim(` (${this.#getRelativeFilename(this.currentFileName)})`)\n : ''\n\n console.log(`\\n${title}${suffix}`)\n }\n\n protected onTestStart(): void {\n /**\n * Display the filename when\n *\n * - The filename exists\n * - The test is not under a group\n * - Test is first in a sequence\n */\n if (this.currentFileName && this.#isFirstLoneTest) {\n console.log(`\\n${colors.dim(this.#getRelativeFilename(this.currentFileName))}`)\n }\n this.#isFirstLoneTest = false\n }\n\n protected onTestEnd(payload: TestEndNode): void {\n this.#printTest(payload)\n }\n\n protected onGroupStart(payload: GroupStartNode): void {\n /**\n * When a group starts, we mark the upcoming test as NOT a\n * lone test\n */\n this.#isFirstLoneTest = false\n this.#printGroup(payload)\n }\n\n protected onGroupEnd(): void {\n /**\n * When the group ends we assume that the next test can\n * be out of the group, hence a lone test.\n *\n * If this assumption is false, then the `onGroupStart` method\n * will toggle the boolean\n */\n this.#isFirstLoneTest = true\n }\n\n protected async end() {\n const summary = this.runner!.getSummary()\n await this.printSummary(summary)\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 { relative } from 'node:path'\nimport { serializeError } from 'serialize-error'\n\nimport { BaseReporter } from '../../modules/core/main.js'\nimport type {\n TestEndNode,\n SuiteEndNode,\n GroupEndNode,\n SuiteStartNode,\n GroupStartNode,\n} from '../../modules/core/types.js'\n\n/**\n * Prints tests progress as JSON. Each event is emitted\n * independently\n */\nexport class NdJSONReporter extends BaseReporter {\n /**\n * Returns the filename relative from the current working dir\n */\n #getRelativeFilename(fileName: string) {\n return relative(process.cwd(), fileName)\n }\n\n /**\n * Serialize errors to JSON\n */\n #serializeErrors(errors: TestEndNode['errors']) {\n return errors.map((error) => ({\n phase: error.phase,\n error: serializeError(error.error),\n }))\n }\n\n protected onTestEnd(payload: TestEndNode): void {\n console.log(\n JSON.stringify({\n event: 'test:end',\n filePath: this.currentFileName,\n relativePath: this.currentFileName\n ? this.#getRelativeFilename(this.currentFileName)\n : undefined,\n title: payload.title,\n duration: payload.duration,\n failReason: payload.failReason,\n isFailing: payload.isFailing,\n skipReason: payload.skipReason,\n isSkipped: payload.isSkipped,\n isTodo: payload.isTodo,\n isPinned: payload.isPinned,\n retryAttempt: payload.retryAttempt,\n retries: payload.retries,\n errors: this.#serializeErrors(payload.errors),\n })\n )\n }\n\n protected onGroupStart(payload: GroupStartNode): void {\n console.log(\n JSON.stringify({\n event: 'group:start',\n title: payload.title,\n })\n )\n }\n\n protected onGroupEnd(payload: GroupEndNode): void {\n JSON.stringify({\n event: 'group:end',\n title: payload.title,\n errors: this.#serializeErrors(payload.errors),\n })\n }\n\n protected onSuiteStart(payload: SuiteStartNode): void {\n console.log(\n JSON.stringify({\n event: 'suite:start',\n ...payload,\n })\n )\n }\n\n protected onSuiteEnd(payload: SuiteEndNode): void {\n console.log(\n JSON.stringify({\n event: 'suite:end',\n ...payload,\n })\n )\n }\n\n protected async end() {\n const summary = this.runner!.getSummary()\n console.log(\n JSON.stringify({\n aggregates: summary.aggregates,\n duration: summary.duration,\n failedTestsTitles: summary.failedTestsTitles,\n hasError: summary.hasError,\n })\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 { DotReporter } from './dot.js'\nimport { SpecReporter } from './spec.js'\nimport { NdJSONReporter } from './ndjson.js'\nimport type { BaseReporterOptions, NamedReporterContract } from '../types.js'\n\n/**\n * Create an instance of the spec reporter\n */\nexport const spec: (options?: BaseReporterOptions) => NamedReporterContract = (options) => {\n return {\n name: 'spec',\n handler: (...args) => new SpecReporter(options).boot(...args),\n }\n}\n\n/**\n * Create an instance of the dot reporter\n */\nexport const dot: (options?: BaseReporterOptions) => NamedReporterContract = (options) => {\n return {\n name: 'dot',\n handler: (...args) => new DotReporter(options).boot(...args),\n }\n}\n\n/**\n * Create an instance of the ndjson reporter\n */\nexport const ndjson: (options?: BaseReporterOptions) => NamedReporterContract = (options) => {\n return {\n name: 'ndjson',\n handler: (...args) => new NdJSONReporter(options).boot(...args),\n }\n}\n"],"mappings":"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","names":["relative","relative"]}
@@ -5,13 +5,13 @@ import {
5
5
  Planner,
6
6
  createTest,
7
7
  createTestGroup
8
- } from "../chunk-CYPN7IGE.js";
9
- import "../chunk-LRVNUQHW.js";
8
+ } from "../chunk-NVI2OU43.js";
9
+ import "../chunk-PHC5CJQG.js";
10
10
  import {
11
11
  Emitter,
12
12
  Runner,
13
13
  Suite
14
- } from "../chunk-PKOB3ULJ.js";
14
+ } from "../chunk-BFNOUWI5.js";
15
15
  import "../chunk-OBDV3O36.js";
16
16
 
17
17
  // factories/runner.ts
package/build/index.js CHANGED
@@ -7,15 +7,14 @@ import {
7
7
  createTestGroup,
8
8
  debug_default,
9
9
  validator_default
10
- } from "./chunk-CYPN7IGE.js";
11
- import {
12
- colors
13
- } from "./chunk-LRVNUQHW.js";
10
+ } from "./chunk-NVI2OU43.js";
11
+ import "./chunk-PHC5CJQG.js";
14
12
  import {
15
13
  Emitter,
16
14
  Runner,
17
- Suite
18
- } from "./chunk-PKOB3ULJ.js";
15
+ Suite,
16
+ colors
17
+ } from "./chunk-BFNOUWI5.js";
19
18
  import "./chunk-OBDV3O36.js";
20
19
 
21
20
  // index.ts
@@ -1 +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":";;;;;;;;;;;;;;;;;;;;;AASA,SAAS,qBAAqB;AAC9B,SAAS,iBAAAA,sBAAqB;;;ACD9B,SAAS,YAAY;AACrB,OAAO,wBAAwB;AAC/B,SAAS,OAAO,UAAU,QAAQ,iBAAiB;AAQnD,IAAM,YAAY,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC7D,IAAM,eAAe,YAAY,KAAK,WAAW,cAAc,IAAI;AAMnE,eAAsB,iBAAgD;AACpE,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,cAAe,OAAO;AACrD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,SAAS,OAAO;AACd,QAAI,MAAM,SAAS,UAAU;AAC3B,aAAO,CAAC;AAAA,IACV;AACA,UAAM,IAAI,MAAM,0CAA0C,EAAE,OAAO,MAAM,CAAC;AAAA,EAC5E;AACF;AAKA,eAAsB,iBAAiB,OAAiB;AACtD,QAAM,MAAM,WAAY,EAAE,WAAW,KAAK,CAAC;AAC3C,QAAM,UAAU,cAAe,KAAK,UAAU,EAAE,MAAa,CAAC,CAAC;AACjE;AAYO,IAAM,cAAwB,eAAe,MAAM,EAAE,QAAQ,SAAAC,SAAQ,GAAG;AAC7E,MAAI,CAAC,cAAc;AACjB;AAAA,EACF;AAEA,SAAO,SAAS,KAAK,OAAO,WAAW;AACrC,UAAM,UAAU,OAAO,WAAW;AAClC,UAAM,iBAAiB,QAAQ,iBAAiB;AAAA,EAClD,CAAC;AAED,MAAIA,SAAQ,QAAQ;AAClB,QAAI;AACF,YAAM,EAAE,MAAM,IAAI,MAAM,eAAe;AACvC,UAAI,CAAC,SAAS,CAAC,MAAM,QAAQ;AAC3B,gBAAQ,IAAI,OAAO,SAAS,EAAE,MAAM,iDAAiD,CAAC;AACtF;AAAA,MACF;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB,SAAS,OAAO;AACd,cAAQ,IAAI,OAAO,MAAM,EAAE,MAAM,sDAAsD,CAAC;AACxF,cAAQ,IAAI,OAAO,IAAI,KAAK,CAAC;AAAA,IAC/B;AAAA,EACF;AACF;;;ACtEA,SAAS,qBAAqB;AAMvB,IAAM,oBAAN,MAAwB;AAAA,EAC7B,oBAA2B,CAAC;AAAA,EAC5B,oBAA2B,CAAC;AAAA,EAC5B,SAAiC;AAAA,EACjC,iBAAiB,IAAI,cAAc,EAAE,iBAAiB,GAAG,gBAAgB,EAAE,CAAC;AAAA,EAE5E,YAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWrB,UAAU;AACR,YAAQ,GAAG,qBAAqB,OAAO,UAAU;AAC/C,WAAK,YAAY;AACjB,UAAI,KAAK,WAAW,YAAY;AAC9B,aAAK,kBAAkB,KAAK,KAAK;AAAA,MACnC,OAAO;AACL,aAAK,eAAe,mBAAmB,mBAAmB;AAC1D,cAAM,KAAK,eAAe,WAAW,KAAK;AAC1C,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,CAAC;AAED,YAAQ,GAAG,sBAAsB,OAAO,UAAU;AAChD,WAAK,YAAY;AACjB,UAAI,KAAK,WAAW,YAAY;AAC9B,aAAK,kBAAkB,KAAK,KAAK;AAAA,MACnC,OAAO;AACL,aAAK,eAAe,mBAAmB,uBAAuB;AAC9D,cAAM,KAAK,eAAe,WAAW,KAAK;AAC1C,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO;AACX,QAAI,KAAK,WAAW,WAAW;AAC7B;AAAA,IACF;AAEA,SAAK,SAAS;AAKd,QAAI,KAAK,kBAAkB,QAAQ;AACjC,UAAI,kBAAkB,KAAK,kBAAkB;AAC7C,UAAI,kBAAkB,KAAK,kBAAkB;AAC7C,WAAK,eAAe,mBAAmB,kBAAkB;AACzD,eAAS,aAAa,KAAK,mBAAmB;AAC5C,cAAM,KAAK,eAAe,WAAW,SAAS;AAC9C,aAAK,eAAe,mBAAmB,IAAI,EAAE,eAAe,IAAI,eAAe,GAAG;AAAA,MACpF;AACA,WAAK,oBAAoB,CAAC;AAAA,IAC5B;AAKA,QAAI,KAAK,kBAAkB,QAAQ;AACjC,UAAI,kBAAkB,KAAK,kBAAkB;AAC7C,UAAI,kBAAkB,KAAK,kBAAkB;AAC7C,WAAK,eAAe,mBAAmB,sBAAsB;AAC7D,eAAS,aAAa,KAAK,mBAAmB;AAC5C,cAAM,KAAK,eAAe,WAAW,SAAS;AAC9C,aAAK,eAAe,mBAAmB,IAAI,EAAE,eAAe,IAAI,eAAe,GAAG;AAAA,MACpF;AACA,WAAK,oBAAoB,CAAC;AAAA,IAC5B;AAAA,EACF;AACF;;;AF/DA,IAAM,UAAU,IAAI,QAAQ;AAK5B,IAAI;AAKJ,IAAI,UAAmB,CAAC;AAKxB,IAAI;AAOJ,IAAM,qBAOF;AAAA,EACF,OAAO;AACT;AAMO,SAAS,KAAK,OAAe,UAAiD;AACnF,oBAAU,wBAAwB,mBAAmB,KAAK;AAE1D,QAAM,eAAe,WAAW,OAAO,SAAS,aAAc,SAAS,kBAAkB;AACzF,eAAa,MAAM,CAAC,MAAM;AACxB,iBAAa;AACb,WAAO,MAAM;AACX,mBAAa;AAAA,IACf;AAAA,EACF,CAAC;AAED,MAAI,UAAU;AACZ,iBAAa,IAAI,QAAQ;AAAA,EAC3B;AAEA,SAAO;AACT;AAKA,KAAK,QAAQ,SAAU,OAAe,UAAkC;AACtE,oBAAU,wBAAwB,mBAAmB,KAAK;AAE1D,qBAAmB,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,IACA,aAAc;AAAA,IACd;AAAA,EACF;AACA,WAAS,mBAAmB,KAAK;AACjC,qBAAmB,QAAQ;AAC7B;AAKO,SAAS,gBAAgB;AAC9B,SAAO;AACT;AAMO,SAAS,eAAe,MAAgB;AAC7C,YAAU,IAAI,UAAU,EAAE,MAAM,IAAI;AACtC;AASO,SAAS,UAAU,SAAiB;AACzC,iBAAe,IAAI,cAAc,SAAS,OAAO,EAAE,QAAQ;AAC7D;AAMA,eAAsB,MAAM;AAI1B,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,IAAI,UAAU,EAAE,QAAQ,CAAC;AACrC;AAAA,EACF;AAEA,oBAAU,mBAAmB,YAAY;AAEzC,qBAAmB,QAAQ;AAC3B,QAAM,SAAS,IAAI,OAAO,OAAO;AACjC,QAAM,cAAc,IAAI,YAAY;AACpC,QAAM,oBAAoB,IAAI,kBAAkB;AAEhD,MAAI;AAIF,UAAM,YAAY,EAAE,QAAQ,cAAe,QAAQ,SAAS,QAAQ,CAAC;AAMrE,aAAS,UAAU,aAAc,SAAS;AACxC,oBAAM,yBAAyB,OAAO,QAAQ,WAAW;AACzD,YAAM,OAAO,EAAE,QAAQ,SAAS,SAAS,QAAQ,aAAc,CAAC;AAAA,IAClE;AAMA,UAAM,EAAE,QAAQ,WAAW,QAAQ,eAAe,IAAI,MAAM,IAAI,QAAQ,YAAa,EAAE,KAAK;AAK5F,cAAU,QAAQ,CAAC,aAAa;AAC9B,oBAAM,6BAA6B,SAAS,IAAI;AAChD,aAAO,iBAAiB,QAAQ;AAAA,IAClC,CAAC;AACD,mBAAe,QAAQ,CAAC,WAAW;AACjC,oBAAM,0BAA0B,OAAO,OAAO,OAAO,OAAO;AAC5D,aAAO,QAAQ,IAAI,OAAO,OAAO,OAAO,OAAO;AAAA,IACjD,CAAC;AACD,WAAO,QAAQ,aAAa,QAAQ,YAAY,KAAK;AACrD,WAAO,QAAQ,OAAO,cAAc;AAKpC,kBAAM,wBAAwB;AAC9B,gBAAY,MAAM,MAAM;AACxB,UAAM,YAAY,MAAM,MAAM;AAK9B,aAAS,SAAS,QAAQ;AAIxB,yBAAmB,QAAQ,IAAI,MAAM,MAAM,MAAM,SAAS,OAAO,OAAO;AACxE,yBAAmB,UAAU,MAAM;AACnC,yBAAmB,UAAU,MAAM;AACnC,UAAI,OAAO,MAAM,cAAc,YAAY;AACzC,cAAM,UAAU,mBAAmB,KAAK;AAAA,MAC1C;AACA,aAAO,IAAI,mBAAmB,KAAK;AAKnC,eAAS,WAAW,MAAM,WAAW;AACnC,2BAAmB,OAAO,cAAc,OAAO;AAC/C,sBAAM,0BAA0B,mBAAmB,IAAI;AACvD,cAAM,OAAO,SAAS,OAAO;AAAA,MAC/B;AAKA,yBAAmB,QAAQ;AAAA,IAC7B;AAKA,uBAAmB,QAAQ;AAK3B,sBAAkB,QAAQ;AAE1B,UAAM,OAAO,MAAM;AACnB,UAAM,OAAO,KAAK;AAElB,UAAM,YAAY,SAAS,MAAM,MAAM;AACvC,UAAM,OAAO,IAAI;AAKjB,UAAM,kBAAkB,KAAK;AAE7B,UAAM,UAAU,OAAO,WAAW;AAClC,QAAI,QAAQ,YAAY,kBAAkB,WAAW;AACnD,cAAQ,WAAW;AAAA,IACrB;AACA,QAAI,OAAO,WAAW;AACpB,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,SAAS,OAAO;AACd,UAAM,YAAY,SAAS,OAAO,MAAM;AACxC,UAAM,UAAU,IAAIC,eAAc;AAClC,UAAM,QAAQ,WAAW,KAAK;AAM9B,UAAM,kBAAkB,KAAK;AAE7B,YAAQ,WAAW;AACnB,QAAI,aAAc,WAAW;AAC3B,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AACF;","names":["ErrorsPrinter","cliArgs","ErrorsPrinter"]}
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"]}
@@ -7,7 +7,7 @@ import {
7
7
  Suite,
8
8
  Test,
9
9
  TestContext
10
- } from "../../chunk-PKOB3ULJ.js";
10
+ } from "../../chunk-BFNOUWI5.js";
11
11
  import "../../chunk-OBDV3O36.js";
12
12
  export {
13
13
  BaseReporter,
@@ -2,8 +2,8 @@ import {
2
2
  dot,
3
3
  ndjson,
4
4
  spec
5
- } from "../../chunk-LRVNUQHW.js";
6
- import "../../chunk-PKOB3ULJ.js";
5
+ } from "../../chunk-PHC5CJQG.js";
6
+ import "../../chunk-BFNOUWI5.js";
7
7
  import "../../chunk-OBDV3O36.js";
8
8
  export {
9
9
  dot,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@japa/runner",
3
3
  "description": "Runner for Japa testing framework",
4
- "version": "3.1.3",
4
+ "version": "3.1.4",
5
5
  "engines": {
6
6
  "node": ">=18.16.0"
7
7
  },
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@japa/core": "^9.0.1",
68
- "@japa/errors-printer": "^3.0.3",
68
+ "@japa/errors-printer": "^3.0.4",
69
69
  "@poppinss/colors": "^4.1.3",
70
70
  "@poppinss/hooks": "^7.2.3",
71
71
  "fast-glob": "^3.3.2",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/helpers.ts","../src/reporters/dot.ts","../src/reporters/spec.ts","../src/reporters/ndjson.ts","../src/reporters/main.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 useColors from '@poppinss/colors'\nimport supportsColor from 'supports-color'\nimport { Colors } from '@poppinss/colors/types'\n\nexport const colors: Colors = supportsColor.stdout ? useColors.ansi() : useColors.silent()\n\n/**\n * A collection of platform specific icons\n */\nexport const icons =\n process.platform === 'win32' && !process.env.WT_SESSION\n ? {\n tick: '√',\n cross: '×',\n bullet: '*',\n nodejs: '♦',\n pointer: '>',\n info: 'i',\n warning: '‼',\n squareSmallFilled: '[█]',\n }\n : {\n tick: '✔',\n cross: '✖',\n bullet: '●',\n nodejs: '⬢',\n pointer: '❯',\n info: 'ℹ',\n warning: '⚠',\n squareSmallFilled: '◼',\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 { colors, icons } from '../helpers.js'\nimport type { TestEndNode } from '../../modules/core/types.js'\nimport { BaseReporter } from '../../modules/core/reporters/base.js'\n\n/**\n * Minimal reporter that prints each test as an icon.\n */\nexport class DotReporter extends BaseReporter {\n /**\n * When a test ended\n */\n protected onTestEnd(payload: TestEndNode) {\n let output = ''\n if (payload.isTodo) {\n output = colors.cyan(icons.info)\n } else if (payload.hasError || payload.isFailing) {\n output = payload.hasError ? colors.magenta(icons.squareSmallFilled) : colors.red(icons.cross)\n } else if (payload.isSkipped) {\n output = colors.yellow(icons.bullet)\n } else {\n output = colors.green(icons.tick)\n }\n\n process.stdout.write(`${output}`)\n }\n\n /**\n * When test runner ended\n */\n protected async end() {\n console.log('')\n await this.printSummary(this.runner!.getSummary())\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 ms from 'ms'\nimport { relative } from 'node:path'\n\nimport { colors, icons } from '../helpers.js'\nimport { BaseReporter } from '../../modules/core/main.js'\nimport { GroupStartNode, TestEndNode } from '../../modules/core/types.js'\n\n/**\n * Pretty prints the tests on the console\n */\nexport class SpecReporter extends BaseReporter {\n /**\n * Tracking if the first event we get is for a test without any parent group\n * We need this to decide the display style for tests without groups.\n */\n #isFirstLoneTest = true\n\n /**\n * Returns the icon for the test\n */\n #getTestIcon(payload: TestEndNode) {\n if (payload.isTodo) {\n return colors.cyan(icons.info)\n }\n\n if (payload.isFailing) {\n return payload.hasError ? colors.magenta(icons.squareSmallFilled) : colors.red(icons.cross)\n }\n\n if (payload.hasError) {\n return colors.red(icons.cross)\n }\n\n if (payload.isSkipped) {\n return colors.yellow(icons.bullet)\n }\n\n return colors.green(icons.tick)\n }\n\n /**\n * Returns the test message\n */\n #getTestMessage(payload: TestEndNode) {\n const message = payload.title.expanded\n\n if (payload.isTodo) {\n return colors.blue(message)\n }\n\n if (payload.isFailing) {\n return payload.hasError ? colors.magenta(message) : colors.red(message)\n }\n\n if (payload.hasError) {\n return colors.red(message)\n }\n\n if (payload.isSkipped) {\n return colors.yellow(message)\n }\n\n return colors.grey(message)\n }\n\n /**\n * Returns the subtext message for the test\n */\n #getSubText(payload: TestEndNode): string | undefined {\n if (payload.isSkipped && payload.skipReason) {\n return colors.yellow(payload.skipReason)\n }\n\n if (!payload.isFailing) {\n return\n }\n\n if (!payload.hasError) {\n return colors.magenta(`Test marked with \".fails()\" must finish with an error`)\n }\n\n if (payload.failReason) {\n return colors.magenta(payload.failReason)\n }\n\n const testErrorMessage = payload.errors.find((error) => error.phase === 'test')\n if (testErrorMessage && testErrorMessage.error) {\n return colors.magenta(testErrorMessage.error.message)\n }\n }\n\n /**\n * Returns the filename relative from the current working dir\n */\n #getRelativeFilename(fileName: string) {\n return relative(process.cwd(), fileName)\n }\n\n /**\n * Prints the test details\n */\n #printTest(payload: TestEndNode) {\n const icon = this.#getTestIcon(payload)\n const message = this.#getTestMessage(payload)\n const prefix = payload.isPinned ? colors.yellow('[PINNED] ') : ''\n const indentation = this.currentFileName || this.currentGroupName ? ' ' : ''\n const duration = colors.dim(`(${ms(Number(payload.duration.toFixed(2)))})`)\n const retries =\n payload.retryAttempt && payload.retryAttempt > 1\n ? colors.dim(`(x${payload.retryAttempt}) `)\n : ''\n\n let subText = this.#getSubText(payload)\n subText = subText ? `\\n${indentation} ${subText}` : ''\n\n console.log(`${indentation}${icon} ${prefix}${retries}${message} ${duration}${subText}`)\n }\n\n /**\n * Prints the group name\n */\n #printGroup(payload: GroupStartNode) {\n const title =\n this.currentSuiteName !== 'default'\n ? `${this.currentSuiteName} / ${payload.title}`\n : payload.title\n\n const suffix = this.currentFileName\n ? colors.dim(` (${this.#getRelativeFilename(this.currentFileName)})`)\n : ''\n\n console.log(`\\n${title}${suffix}`)\n }\n\n protected onTestStart(): void {\n /**\n * Display the filename when\n *\n * - The filename exists\n * - The test is not under a group\n * - Test is first in a sequence\n */\n if (this.currentFileName && this.#isFirstLoneTest) {\n console.log(`\\n${colors.dim(this.#getRelativeFilename(this.currentFileName))}`)\n }\n this.#isFirstLoneTest = false\n }\n\n protected onTestEnd(payload: TestEndNode): void {\n this.#printTest(payload)\n }\n\n protected onGroupStart(payload: GroupStartNode): void {\n /**\n * When a group starts, we mark the upcoming test as NOT a\n * lone test\n */\n this.#isFirstLoneTest = false\n this.#printGroup(payload)\n }\n\n protected onGroupEnd(): void {\n /**\n * When the group ends we assume that the next test can\n * be out of the group, hence a lone test.\n *\n * If this assumption is false, then the `onGroupStart` method\n * will toggle the boolean\n */\n this.#isFirstLoneTest = true\n }\n\n protected async end() {\n const summary = this.runner!.getSummary()\n await this.printSummary(summary)\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 { relative } from 'node:path'\nimport { serializeError } from 'serialize-error'\n\nimport { BaseReporter } from '../../modules/core/main.js'\nimport type {\n TestEndNode,\n SuiteEndNode,\n GroupEndNode,\n SuiteStartNode,\n GroupStartNode,\n} from '../../modules/core/types.js'\n\n/**\n * Prints tests progress as JSON. Each event is emitted\n * independently\n */\nexport class NdJSONReporter extends BaseReporter {\n /**\n * Returns the filename relative from the current working dir\n */\n #getRelativeFilename(fileName: string) {\n return relative(process.cwd(), fileName)\n }\n\n /**\n * Serialize errors to JSON\n */\n #serializeErrors(errors: TestEndNode['errors']) {\n return errors.map((error) => ({\n phase: error.phase,\n error: serializeError(error.error),\n }))\n }\n\n protected onTestEnd(payload: TestEndNode): void {\n console.log(\n JSON.stringify({\n event: 'test:end',\n filePath: this.currentFileName,\n relativePath: this.currentFileName\n ? this.#getRelativeFilename(this.currentFileName)\n : undefined,\n title: payload.title,\n duration: payload.duration,\n failReason: payload.failReason,\n isFailing: payload.isFailing,\n skipReason: payload.skipReason,\n isSkipped: payload.isSkipped,\n isTodo: payload.isTodo,\n isPinned: payload.isPinned,\n retryAttempt: payload.retryAttempt,\n retries: payload.retries,\n errors: this.#serializeErrors(payload.errors),\n })\n )\n }\n\n protected onGroupStart(payload: GroupStartNode): void {\n console.log(\n JSON.stringify({\n event: 'group:start',\n title: payload.title,\n })\n )\n }\n\n protected onGroupEnd(payload: GroupEndNode): void {\n JSON.stringify({\n event: 'group:end',\n title: payload.title,\n errors: this.#serializeErrors(payload.errors),\n })\n }\n\n protected onSuiteStart(payload: SuiteStartNode): void {\n console.log(\n JSON.stringify({\n event: 'suite:start',\n ...payload,\n })\n )\n }\n\n protected onSuiteEnd(payload: SuiteEndNode): void {\n console.log(\n JSON.stringify({\n event: 'suite:end',\n ...payload,\n })\n )\n }\n\n protected async end() {\n const summary = this.runner!.getSummary()\n console.log(\n JSON.stringify({\n aggregates: summary.aggregates,\n duration: summary.duration,\n failedTestsTitles: summary.failedTestsTitles,\n hasError: summary.hasError,\n })\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 { DotReporter } from './dot.js'\nimport { SpecReporter } from './spec.js'\nimport { NdJSONReporter } from './ndjson.js'\nimport type { BaseReporterOptions, NamedReporterContract } from '../types.js'\n\n/**\n * Create an instance of the spec reporter\n */\nexport const spec: (options?: BaseReporterOptions) => NamedReporterContract = (options) => {\n return {\n name: 'spec',\n handler: (...args) => new SpecReporter(options).boot(...args),\n }\n}\n\n/**\n * Create an instance of the dot reporter\n */\nexport const dot: (options?: BaseReporterOptions) => NamedReporterContract = (options) => {\n return {\n name: 'dot',\n handler: (...args) => new DotReporter(options).boot(...args),\n }\n}\n\n/**\n * Create an instance of the ndjson reporter\n */\nexport const ndjson: (options?: BaseReporterOptions) => NamedReporterContract = (options) => {\n return {\n name: 'ndjson',\n handler: (...args) => new NdJSONReporter(options).boot(...args),\n }\n}\n"],"mappings":"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","names":["relative","relative"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../modules/core/main.ts","../modules/core/reporters/base.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 {\n Emitter,\n Refiner,\n Test as BaseTest,\n Suite as BaseSuite,\n Group as BaseGroup,\n Runner as BaseRunner,\n TestContext as BaseTestContext,\n} from '@japa/core'\nimport { inspect } from 'node:util'\nimport { AssertionError } from 'node:assert'\nimport { BaseReporter } from './reporters/base.js'\nimport type { DataSetNode, TestHooksCleanupHandler } from './types.js'\n\ndeclare module '@japa/core' {\n interface Test<Context extends Record<any, any>, TestData extends DataSetNode = undefined> {\n throws(message: string | RegExp, errorConstructor?: any): this\n }\n interface TestContext {\n cleanup: (cleanupCallback: TestHooksCleanupHandler<TestContext>) => void\n }\n}\n\nexport { Emitter, Refiner, BaseReporter }\n\n/**\n * Test context carries context data for a given test.\n */\nexport class TestContext extends BaseTestContext {\n /**\n * Register a cleanup function that runs after the test finishes\n * successfully or with an error.\n */\n declare cleanup: (cleanupCallback: TestHooksCleanupHandler<TestContext>) => void\n\n constructor(public test: Test) {\n super()\n this.cleanup = (cleanupCallback: TestHooksCleanupHandler<TestContext>) => {\n test.cleanup(cleanupCallback)\n }\n }\n}\n\n/**\n * Test class represents an individual test and exposes API to tweak\n * its runtime behavior.\n */\nexport class Test<TestData extends DataSetNode = undefined> extends BaseTest<\n TestContext,\n TestData\n> {\n /**\n * @inheritdoc\n */\n static executedCallbacks = []\n\n /**\n * @inheritdoc\n */\n static executingCallbacks = []\n\n /**\n * Assert the test callback throws an exception when a certain\n * error message and optionally is an instance of a given\n * Error class.\n */\n throws(message: string | RegExp, errorConstructor?: any) {\n const errorInPoint = new AssertionError({})\n const existingExecutor = this.options.executor\n if (!existingExecutor) {\n throw new Error('Cannot use \"test.throws\" method without a test callback')\n }\n\n /**\n * Overwriting existing callback\n */\n this.options.executor = async (...args: [any, any, any]) => {\n let raisedException: any\n try {\n await existingExecutor(...args)\n } catch (error) {\n raisedException = error\n }\n\n /**\n * Notify no exception has been raised\n */\n if (!raisedException) {\n errorInPoint.message = 'Expected test to throw an exception'\n throw errorInPoint\n }\n\n /**\n * Constructor mis-match\n */\n if (errorConstructor && !(raisedException instanceof errorConstructor)) {\n errorInPoint.message = `Expected test to throw \"${inspect(errorConstructor)}\"`\n throw errorInPoint\n }\n\n /**\n * Error does not have a message property\n */\n const exceptionMessage: unknown = raisedException.message\n if (!exceptionMessage || typeof exceptionMessage !== 'string') {\n errorInPoint.message = 'Expected test to throw an exception with message property'\n throw errorInPoint\n }\n\n /**\n * Message does not match\n */\n if (typeof message === 'string') {\n if (exceptionMessage !== message) {\n errorInPoint.message = `Expected test to throw \"${message}\". Instead received \"${raisedException.message}\"`\n errorInPoint.actual = raisedException.message\n errorInPoint.expected = message\n throw errorInPoint\n }\n return\n }\n\n if (!message.test(exceptionMessage)) {\n errorInPoint.message = `Expected test error to match \"${message}\" regular expression`\n throw errorInPoint\n }\n }\n\n return this\n }\n}\n\n/**\n * TestGroup is used to bulk configure a collection of tests and\n * define lifecycle hooks for them\n */\nexport class Group extends BaseGroup<TestContext> {}\n\n/**\n * A suite is a collection of tests created around a given\n * testing type. For example: A suite for unit tests, a\n * suite for functional tests and so on.\n */\nexport class Suite extends BaseSuite<TestContext> {}\n\n/**\n * Runner class is used to execute the tests\n */\nexport class Runner extends BaseRunner<TestContext> {}\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 ms from 'ms'\nimport colors from '@poppinss/colors'\nimport { ErrorsPrinter } from '@japa/errors-printer'\n\nimport type {\n TestEndNode,\n SuiteEndNode,\n GroupEndNode,\n TestStartNode,\n RunnerSummary,\n RunnerEndNode,\n GroupStartNode,\n SuiteStartNode,\n RunnerStartNode,\n BaseReporterOptions,\n} from '../types.js'\nimport { Emitter, Runner } from '../main.js'\n\nconst ansi = colors.ansi()\n\n/**\n * Base reporter to build custom reporters on top of\n */\nexport abstract class BaseReporter {\n #options: BaseReporterOptions\n runner?: Runner\n\n /**\n * Path to the file for which the tests are getting executed\n */\n currentFileName?: string\n\n /**\n * Suite for which the tests are getting executed\n */\n currentSuiteName?: string\n\n /**\n * Group for which the tests are getting executed\n */\n currentGroupName?: string\n\n constructor(options: BaseReporterOptions = {}) {\n this.#options = Object.assign({ stackLinesCount: 2 }, options)\n }\n\n /**\n * Pretty prints the aggregates\n */\n #printAggregates(summary: RunnerSummary) {\n const tests: string[] = []\n\n /**\n * Set value for tests row\n */\n if (summary.aggregates.passed) {\n tests.push(ansi.green(`${summary.aggregates.passed} passed`))\n }\n if (summary.aggregates.failed) {\n tests.push(ansi.red(`${summary.aggregates.failed} failed`))\n }\n if (summary.aggregates.todo) {\n tests.push(ansi.cyan(`${summary.aggregates.todo} todo`))\n }\n if (summary.aggregates.skipped) {\n tests.push(ansi.yellow(`${summary.aggregates.skipped} skipped`))\n }\n if (summary.aggregates.regression) {\n tests.push(ansi.magenta(`${summary.aggregates.regression} regression`))\n }\n\n this.runner!.summaryBuilder.use(() => {\n return [\n {\n key: ansi.dim('Tests'),\n value: `${tests.join(', ')} ${ansi.dim(`(${summary.aggregates.total})`)}`,\n },\n {\n key: ansi.dim('Time'),\n value: ansi.dim(ms(summary.duration)),\n },\n ]\n })\n\n console.log(this.runner!.summaryBuilder.build().join('\\n'))\n }\n\n /**\n * Aggregates errors tree to a flat array\n */\n #aggregateErrors(summary: RunnerSummary) {\n const errorsList: { phase: string; title: string; error: Error }[] = []\n\n summary.failureTree.forEach((suite) => {\n suite.errors.forEach((error) => errorsList.push({ title: suite.name, ...error }))\n\n suite.children.forEach((testOrGroup) => {\n /**\n * Suite child is a test\n */\n if (testOrGroup.type === 'test') {\n testOrGroup.errors.forEach((error) => {\n errorsList.push({ title: `${suite.name} / ${testOrGroup.title}`, ...error })\n })\n return\n }\n\n /**\n * Suite child is a group\n */\n testOrGroup.errors.forEach((error) => {\n errorsList.push({ title: testOrGroup.name, ...error })\n })\n testOrGroup.children.forEach((test) => {\n test.errors.forEach((error) => {\n errorsList.push({ title: `${testOrGroup.name} / ${test.title}`, ...error })\n })\n })\n })\n })\n\n return errorsList\n }\n\n /**\n * Pretty print errors\n */\n async #printErrors(summary: RunnerSummary) {\n if (!summary.failureTree.length) {\n return\n }\n\n const errorPrinter = new ErrorsPrinter({\n stackLinesCount: this.#options.stackLinesCount,\n framesMaxLimit: this.#options.framesMaxLimit,\n })\n\n errorPrinter.printSectionHeader('ERRORS')\n await errorPrinter.printErrors(this.#aggregateErrors(summary))\n }\n\n /**\n * Handlers to capture events\n */\n protected onTestStart(_: TestStartNode): void {}\n protected onTestEnd(_: TestEndNode) {}\n\n protected onGroupStart(_: GroupStartNode) {}\n protected onGroupEnd(_: GroupEndNode) {}\n\n protected onSuiteStart(_: SuiteStartNode) {}\n protected onSuiteEnd(_: SuiteEndNode) {}\n\n protected async start(_: RunnerStartNode) {}\n protected async end(_: RunnerEndNode) {}\n\n /**\n * Print tests summary\n */\n protected async printSummary(summary: RunnerSummary) {\n await this.#printErrors(summary)\n\n console.log('')\n if (summary.aggregates.total === 0 && !summary.hasError) {\n console.log(ansi.bgYellow().black(' NO TESTS EXECUTED '))\n return\n }\n\n if (summary.hasError) {\n console.log(ansi.bgRed().black(' FAILED '))\n } else {\n console.log(ansi.bgGreen().black(' PASSED '))\n }\n console.log('')\n this.#printAggregates(summary)\n }\n\n /**\n * Invoked by the tests runner when tests are about to start\n */\n boot(runner: Runner, emitter: Emitter) {\n this.runner = runner\n\n emitter.on('test:start', (payload) => {\n this.currentFileName = payload.meta.fileName\n this.onTestStart(payload)\n })\n\n emitter.on('test:end', (payload) => {\n this.onTestEnd(payload)\n })\n\n emitter.on('group:start', (payload) => {\n this.currentGroupName = payload.title\n this.currentFileName = payload.meta.fileName\n this.onGroupStart(payload)\n })\n\n emitter.on('group:end', (payload) => {\n this.currentGroupName = undefined\n this.onGroupEnd(payload)\n })\n\n emitter.on('suite:start', (payload) => {\n this.currentSuiteName = payload.name\n this.onSuiteStart(payload)\n })\n\n emitter.on('suite:end', (payload) => {\n this.currentSuiteName = undefined\n this.onSuiteEnd(payload)\n })\n\n emitter.on('runner:start', async (payload) => {\n await this.start(payload)\n })\n\n emitter.on('runner:end', async (payload) => {\n await this.end(payload)\n })\n }\n}\n"],"mappings":"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","names":[]}