@japa/runner 2.5.1 → 3.0.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE.md +1 -1
  2. package/build/factories/main.d.ts +3 -0
  3. package/build/factories/main.d.ts.map +1 -0
  4. package/build/factories/main.js +2 -0
  5. package/build/factories/runner.d.ts +10 -0
  6. package/build/factories/runner.d.ts.map +1 -0
  7. package/build/factories/runner.js +155 -0
  8. package/build/index.d.ts +8 -29
  9. package/build/index.js +93 -466
  10. package/build/modules/core/main.d.ts +29 -0
  11. package/build/modules/core/main.d.ts.map +1 -0
  12. package/build/modules/core/main.js +68 -0
  13. package/build/modules/core/reporters/base.d.ts +21 -0
  14. package/build/modules/core/reporters/base.d.ts.map +1 -0
  15. package/build/modules/core/reporters/base.js +136 -0
  16. package/build/modules/core/types.d.ts +6 -0
  17. package/build/modules/core/types.d.ts.map +1 -0
  18. package/build/modules/core/types.js +1 -0
  19. package/build/src/cli_parser.d.ts +6 -0
  20. package/build/src/cli_parser.d.ts.map +1 -0
  21. package/build/src/cli_parser.js +49 -0
  22. package/build/src/config_manager.d.ts +7 -0
  23. package/build/src/config_manager.d.ts.map +1 -0
  24. package/build/src/config_manager.js +115 -0
  25. package/build/src/create_test.d.ts +16 -0
  26. package/build/src/create_test.d.ts.map +1 -0
  27. package/build/src/create_test.js +33 -0
  28. package/build/src/debug.d.ts +2 -1
  29. package/build/src/debug.d.ts.map +1 -0
  30. package/build/src/debug.js +2 -12
  31. package/build/src/exceptions_manager.d.ts +7 -0
  32. package/build/src/exceptions_manager.d.ts.map +1 -0
  33. package/build/src/exceptions_manager.js +58 -0
  34. package/build/src/files_manager.d.ts +7 -0
  35. package/build/src/files_manager.d.ts.map +1 -0
  36. package/build/src/files_manager.js +28 -0
  37. package/build/src/helpers.d.ts +23 -0
  38. package/build/src/helpers.d.ts.map +1 -0
  39. package/build/src/helpers.js +2 -0
  40. package/build/src/hooks.d.ts +9 -0
  41. package/build/src/hooks.d.ts.map +1 -0
  42. package/build/src/hooks.js +26 -0
  43. package/build/src/planner.d.ts +18 -0
  44. package/build/src/planner.d.ts.map +1 -0
  45. package/build/src/planner.js +67 -0
  46. package/build/src/plugins/retry.d.ts +8 -0
  47. package/build/src/plugins/retry.d.ts.map +1 -0
  48. package/build/src/plugins/retry.js +42 -0
  49. package/build/src/reporters/dot.d.ts +7 -0
  50. package/build/src/reporters/dot.d.ts.map +1 -0
  51. package/build/src/reporters/dot.js +24 -0
  52. package/build/src/reporters/main.d.ts +5 -0
  53. package/build/src/reporters/main.d.ts.map +1 -0
  54. package/build/src/reporters/main.js +21 -0
  55. package/build/src/reporters/ndjson.d.ts +12 -0
  56. package/build/src/reporters/ndjson.d.ts.map +1 -0
  57. package/build/src/reporters/ndjson.js +61 -0
  58. package/build/src/reporters/spec.d.ts +11 -0
  59. package/build/src/reporters/spec.d.ts.map +1 -0
  60. package/build/src/reporters/spec.js +103 -0
  61. package/build/src/types.d.ts +48 -49
  62. package/build/src/types.d.ts.map +1 -0
  63. package/build/src/types.js +1 -10
  64. package/build/src/validator.d.ts +11 -0
  65. package/build/src/validator.d.ts.map +1 -0
  66. package/build/src/validator.js +46 -0
  67. package/package.json +78 -83
  68. package/build/src/core/main.d.ts +0 -49
  69. package/build/src/core/main.js +0 -87
@@ -0,0 +1,9 @@
1
+ import { Runner } from '../modules/core/main.js';
2
+ import type { Config } from './types.js';
3
+ export declare class GlobalHooks {
4
+ #private;
5
+ apply(config: Required<Config>): void;
6
+ setup(runner: Runner): Promise<void>;
7
+ teardown(error: Error | null, runner: Runner): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,KAAK,EAAE,MAAM,EAAkD,MAAM,YAAY,CAAA;AAKxF,qBAAa,WAAW;;IAQtB,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IAQxB,KAAK,CAAC,MAAM,EAAE,MAAM;IASpB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM;CAWnD"}
@@ -0,0 +1,26 @@
1
+ import Hooks from '@poppinss/hooks';
2
+ export class GlobalHooks {
3
+ #hooks = new Hooks();
4
+ #setupRunner;
5
+ #teardownRunner;
6
+ apply(config) {
7
+ config.setup.forEach((hook) => this.#hooks.add('setup', hook));
8
+ config.teardown.forEach((hook) => this.#hooks.add('teardown', hook));
9
+ }
10
+ async setup(runner) {
11
+ this.#setupRunner = this.#hooks.runner('setup');
12
+ this.#teardownRunner = this.#hooks.runner('teardown');
13
+ await this.#setupRunner.run(runner);
14
+ }
15
+ async teardown(error, runner) {
16
+ if (this.#setupRunner) {
17
+ await this.#setupRunner.cleanup(error, runner);
18
+ }
19
+ if (this.#teardownRunner) {
20
+ if (!error) {
21
+ await this.#teardownRunner.run(runner);
22
+ }
23
+ await this.#teardownRunner.cleanup(error, runner);
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,18 @@
1
+ /// <reference types="@types/node" resolution-mode="require"/>
2
+ import type { Config, TestSuite } from './types.js';
3
+ export declare class Planner {
4
+ #private;
5
+ constructor(config: Required<Config>);
6
+ plan(): Promise<{
7
+ reporters: import("@japa/core/types").NamedReporterContract[];
8
+ suites: (TestSuite & {
9
+ filesURLs: URL[];
10
+ })[];
11
+ refinerFilters: {
12
+ layer: "tags" | "tests" | "groups";
13
+ filters: string[];
14
+ }[];
15
+ config: Required<Config>;
16
+ }>;
17
+ }
18
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/planner.ts"],"names":[],"mappings":";AAWA,OAAO,KAAK,EAAE,MAAM,EAAa,SAAS,EAAE,MAAM,YAAY,CAAA;AAO9D,qBAAa,OAAO;;gBAIN,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IA6E9B,IAAI;;;;;;;;;;;CAWX"}
@@ -0,0 +1,67 @@
1
+ import validator from './validator.js';
2
+ import { FilesManager } from './files_manager.js';
3
+ export class Planner {
4
+ #config;
5
+ #fileManager = new FilesManager();
6
+ constructor(config) {
7
+ validator.validateActivatedReporters(config);
8
+ validator.validateSuitesFilter(config);
9
+ validator.validateSuitesForUniqueness(config);
10
+ this.#config = config;
11
+ }
12
+ #getActivatedReporters() {
13
+ return this.#config.reporters.activated.map((activated) => {
14
+ return this.#config.reporters.list.find(({ name }) => activated === name);
15
+ });
16
+ }
17
+ async #collectFiles(files) {
18
+ let filesURLs = await this.#fileManager.getFiles(this.#config.cwd, files);
19
+ if (this.#config.filters.files && this.#config.filters.files.length) {
20
+ filesURLs = this.#fileManager.grep(filesURLs, this.#config.filters.files);
21
+ }
22
+ return filesURLs;
23
+ }
24
+ async #getSuites() {
25
+ let suites = [];
26
+ let suitesFilters = this.#config.filters.suites || [];
27
+ if ('files' in this.#config) {
28
+ suites.push({
29
+ name: 'default',
30
+ files: this.#config.files,
31
+ timeout: this.#config.timeout,
32
+ retries: this.#config.retries,
33
+ filesURLs: await this.#collectFiles(this.#config.files),
34
+ });
35
+ }
36
+ if ('suites' in this.#config) {
37
+ for (let suite of this.#config.suites) {
38
+ if (!suitesFilters.length || suitesFilters.includes(suite.name)) {
39
+ suites.push({
40
+ ...suite,
41
+ filesURLs: await this.#collectFiles(suite.files),
42
+ });
43
+ }
44
+ }
45
+ }
46
+ return suites;
47
+ }
48
+ #getRefinerFilters() {
49
+ return Object.keys(this.#config.filters).reduce((result, layer) => {
50
+ if (layer === 'tests' || layer === 'tags' || layer === 'groups') {
51
+ result.push({ layer, filters: this.#config.filters[layer] });
52
+ }
53
+ return result;
54
+ }, []);
55
+ }
56
+ async plan() {
57
+ const suites = await this.#getSuites();
58
+ const reporters = this.#getActivatedReporters();
59
+ const refinerFilters = this.#getRefinerFilters();
60
+ return {
61
+ reporters,
62
+ suites,
63
+ refinerFilters,
64
+ config: this.#config,
65
+ };
66
+ }
67
+ }
@@ -0,0 +1,8 @@
1
+ import type { PluginFn } from '../types.js';
2
+ export declare function getFailedTests(): Promise<{
3
+ tests?: string[];
4
+ }>;
5
+ export declare function cacheFailedTests(tests: string[]): Promise<void>;
6
+ export declare function clearCache(): Promise<void>;
7
+ export declare const retryPlugin: PluginFn;
8
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../src/plugins/retry.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAY3C,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAUpE;AAKD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,iBAGrD;AAKD,wBAAsB,UAAU,kBAE/B;AAKD,eAAO,MAAM,WAAW,EAAE,QAkBzB,CAAA"}
@@ -0,0 +1,42 @@
1
+ import { join } from 'node:path';
2
+ import findCacheDirectory from 'find-cache-dir';
3
+ import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
4
+ import cliui from '../helpers.js';
5
+ const CACHE_DIR = findCacheDirectory({ name: '@japa/runner' });
6
+ const SUMMARY_FILE = CACHE_DIR ? join(CACHE_DIR, 'summary.json') : undefined;
7
+ export async function getFailedTests() {
8
+ try {
9
+ const summary = await readFile(SUMMARY_FILE, 'utf-8');
10
+ return JSON.parse(summary);
11
+ }
12
+ catch (error) {
13
+ if (error.code === 'ENOENT') {
14
+ return {};
15
+ }
16
+ throw new Error('Unable to read failed tests cache file', { cause: error });
17
+ }
18
+ }
19
+ export async function cacheFailedTests(tests) {
20
+ await mkdir(CACHE_DIR, { recursive: true });
21
+ await writeFile(SUMMARY_FILE, JSON.stringify({ tests: tests }));
22
+ }
23
+ export async function clearCache() {
24
+ await unlink(SUMMARY_FILE);
25
+ }
26
+ export const retryPlugin = async function retry({ config, cliArgs }) {
27
+ if (!SUMMARY_FILE) {
28
+ return;
29
+ }
30
+ config.teardown.push(async (runner) => {
31
+ const summary = runner.getSummary();
32
+ await cacheFailedTests(summary.failedTestsTitles);
33
+ });
34
+ if (cliArgs.retry) {
35
+ const { tests } = await getFailedTests();
36
+ if (!tests || !tests.length) {
37
+ console.log(cliui.colors.bgYellow().black(' No failing tests found. Running all the tests '));
38
+ return;
39
+ }
40
+ config.filters.tests = tests;
41
+ }
42
+ };
@@ -0,0 +1,7 @@
1
+ import type { TestEndNode } from '../../modules/core/types.js';
2
+ import { BaseReporter } from '../../modules/core/reporters/base.js';
3
+ export declare class DotReporter extends BaseReporter {
4
+ protected onTestEnd(payload: TestEndNode): void;
5
+ protected end(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=dot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/reporters/dot.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAA;AAKnE,qBAAa,WAAY,SAAQ,YAAY;IAI3C,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW;cAkBxB,GAAG;CAIpB"}
@@ -0,0 +1,24 @@
1
+ import cliui from '../helpers.js';
2
+ import { BaseReporter } from '../../modules/core/reporters/base.js';
3
+ export class DotReporter extends BaseReporter {
4
+ onTestEnd(payload) {
5
+ let output = '';
6
+ if (payload.isTodo) {
7
+ output = cliui.colors.cyan('-');
8
+ }
9
+ else if (payload.hasError || payload.isFailing) {
10
+ output = cliui.colors.red('×');
11
+ }
12
+ else if (payload.isSkipped) {
13
+ output = cliui.colors.yellow('-');
14
+ }
15
+ else {
16
+ output = cliui.colors.green('•');
17
+ }
18
+ process.stdout.write(`${output}`);
19
+ }
20
+ async end() {
21
+ console.log('');
22
+ await this.printSummary(this.runner.getSummary());
23
+ }
24
+ }
@@ -0,0 +1,5 @@
1
+ import type { BaseReporterOptions, NamedReporterContract } from '../types.js';
2
+ export declare const spec: (options?: BaseReporterOptions) => NamedReporterContract;
3
+ export declare const dot: (options?: BaseReporterOptions) => NamedReporterContract;
4
+ export declare const ndjson: (options?: BaseReporterOptions) => NamedReporterContract;
5
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/reporters/main.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAK7E,eAAO,MAAM,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,qBAKrD,CAAA;AAKD,eAAO,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,qBAKpD,CAAA;AAKD,eAAO,MAAM,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,qBAKvD,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { DotReporter } from './dot.js';
2
+ import { SpecReporter } from './spec.js';
3
+ import { NdJSONReporter } from './ndjson.js';
4
+ export const spec = (options) => {
5
+ return {
6
+ name: 'spec',
7
+ handler: (...args) => new SpecReporter(options).boot(...args),
8
+ };
9
+ };
10
+ export const dot = (options) => {
11
+ return {
12
+ name: 'dot',
13
+ handler: (...args) => new DotReporter(options).boot(...args),
14
+ };
15
+ };
16
+ export const ndjson = (options) => {
17
+ return {
18
+ name: 'ndjson',
19
+ handler: (...args) => new NdJSONReporter(options).boot(...args),
20
+ };
21
+ };
@@ -0,0 +1,12 @@
1
+ import { BaseReporter } from '../../modules/core/main.js';
2
+ import type { TestEndNode, SuiteEndNode, GroupEndNode, SuiteStartNode, GroupStartNode } from '../../modules/core/types.js';
3
+ export declare class NdJSONReporter extends BaseReporter {
4
+ #private;
5
+ protected onTestEnd(payload: TestEndNode): void;
6
+ protected onGroupStart(payload: GroupStartNode): void;
7
+ protected onGroupEnd(payload: GroupEndNode): void;
8
+ protected onSuiteStart(payload: SuiteStartNode): void;
9
+ protected onSuiteEnd(payload: SuiteEndNode): void;
10
+ protected end(): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=ndjson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ndjson.d.ts","sourceRoot":"","sources":["../../../src/reporters/ndjson.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,cAAc,EACf,MAAM,6BAA6B,CAAA;AAMpC,qBAAa,cAAe,SAAQ,YAAY;;IAQ9C,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAuB/C,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IASrD,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAQjD,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IASrD,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;cASjC,GAAG;CAWpB"}
@@ -0,0 +1,61 @@
1
+ import { relative } from 'node:path';
2
+ import { BaseReporter } from '../../modules/core/main.js';
3
+ export class NdJSONReporter extends BaseReporter {
4
+ #getRelativeFilename(fileName) {
5
+ return relative(process.cwd(), fileName);
6
+ }
7
+ onTestEnd(payload) {
8
+ console.log(JSON.stringify({
9
+ event: 'test:end',
10
+ filePath: this.currentFileName,
11
+ relativePath: this.currentFileName
12
+ ? this.#getRelativeFilename(this.currentFileName)
13
+ : undefined,
14
+ title: payload.title,
15
+ duration: payload.duration,
16
+ failReason: payload.failReason,
17
+ isFailing: payload.isFailing,
18
+ skipReason: payload.skipReason,
19
+ isSkipped: payload.isSkipped,
20
+ isTodo: payload.isTodo,
21
+ isPinned: payload.isPinned,
22
+ retryAttempt: payload.retryAttempt,
23
+ retries: payload.retries,
24
+ errors: payload.errors,
25
+ }));
26
+ }
27
+ onGroupStart(payload) {
28
+ console.log(JSON.stringify({
29
+ event: 'group:start',
30
+ title: payload.title,
31
+ }));
32
+ }
33
+ onGroupEnd(payload) {
34
+ JSON.stringify({
35
+ event: 'group:end',
36
+ title: payload.title,
37
+ errors: payload.errors,
38
+ });
39
+ }
40
+ onSuiteStart(payload) {
41
+ console.log(JSON.stringify({
42
+ event: 'suite:start',
43
+ ...payload,
44
+ }));
45
+ }
46
+ onSuiteEnd(payload) {
47
+ console.log(JSON.stringify({
48
+ event: 'suite:end',
49
+ ...payload,
50
+ }));
51
+ }
52
+ async end() {
53
+ const summary = this.runner.getSummary();
54
+ console.log(JSON.stringify({
55
+ aggregates: summary.aggregates,
56
+ duration: summary.duration,
57
+ failedTestsTitles: summary.failedTestsTitles,
58
+ hasError: summary.hasError,
59
+ }));
60
+ }
61
+ }
@@ -0,0 +1,11 @@
1
+ import { BaseReporter } from '../../modules/core/main.js';
2
+ import { GroupStartNode, TestEndNode } from '../../modules/core/types.js';
3
+ export declare class SpecReporter extends BaseReporter {
4
+ #private;
5
+ protected onTestStart(): void;
6
+ protected onTestEnd(payload: TestEndNode): void;
7
+ protected onGroupStart(payload: GroupStartNode): void;
8
+ protected onGroupEnd(): void;
9
+ protected end(): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/reporters/spec.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAKzE,qBAAa,YAAa,SAAQ,YAAY;;IA8H5C,SAAS,CAAC,WAAW,IAAI,IAAI;IAc7B,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAI/C,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IASrD,SAAS,CAAC,UAAU,IAAI,IAAI;cAWZ,GAAG;CAIpB"}
@@ -0,0 +1,103 @@
1
+ import ms from 'ms';
2
+ import { relative } from 'node:path';
3
+ import cliui from '../helpers.js';
4
+ import { BaseReporter } from '../../modules/core/main.js';
5
+ export class SpecReporter extends BaseReporter {
6
+ #isFirstLoneTest = true;
7
+ #getTestIcon(payload) {
8
+ if (payload.isTodo) {
9
+ return cliui.colors.cyan(cliui.icons.info);
10
+ }
11
+ if (payload.isFailing) {
12
+ return payload.hasError
13
+ ? cliui.colors.magenta(cliui.icons.squareSmallFilled)
14
+ : cliui.colors.red(cliui.icons.cross);
15
+ }
16
+ if (payload.hasError) {
17
+ return cliui.colors.red(cliui.icons.cross);
18
+ }
19
+ if (payload.isSkipped) {
20
+ return cliui.colors.yellow(cliui.icons.bullet);
21
+ }
22
+ return cliui.colors.green(cliui.icons.tick);
23
+ }
24
+ #getTestMessage(payload) {
25
+ const message = typeof payload.title === 'string' ? payload.title : payload.title.expanded;
26
+ if (payload.isTodo) {
27
+ return cliui.colors.blue(message);
28
+ }
29
+ if (payload.isFailing) {
30
+ return payload.hasError ? cliui.colors.magenta(message) : cliui.colors.red(message);
31
+ }
32
+ if (payload.hasError) {
33
+ return cliui.colors.red(message);
34
+ }
35
+ if (payload.isSkipped) {
36
+ return cliui.colors.yellow(message);
37
+ }
38
+ return cliui.colors.grey(message);
39
+ }
40
+ #getSubText(payload) {
41
+ if (payload.isSkipped && payload.skipReason) {
42
+ return cliui.colors.yellow(payload.skipReason);
43
+ }
44
+ if (!payload.isFailing) {
45
+ return;
46
+ }
47
+ if (!payload.hasError) {
48
+ return cliui.colors.magenta(`Test marked with ".fails()" must finish with an error`);
49
+ }
50
+ if (payload.failReason) {
51
+ return cliui.colors.magenta(payload.failReason);
52
+ }
53
+ const testErrorMessage = payload.errors.find((error) => error.phase === 'test');
54
+ if (testErrorMessage && testErrorMessage.error) {
55
+ return cliui.colors.magenta(testErrorMessage.error.message);
56
+ }
57
+ }
58
+ #getRelativeFilename(fileName) {
59
+ return relative(process.cwd(), fileName);
60
+ }
61
+ #printTest(payload) {
62
+ const icon = this.#getTestIcon(payload);
63
+ const message = this.#getTestMessage(payload);
64
+ const prefix = payload.isPinned ? cliui.colors.yellow('[PINNED] ') : '';
65
+ const indentation = this.currentFileName || this.currentGroupName ? ' ' : '';
66
+ const duration = cliui.colors.dim(`(${ms(payload.duration)})`);
67
+ const retries = payload.retryAttempt && payload.retryAttempt > 1
68
+ ? cliui.colors.dim(`(x${payload.retryAttempt}) `)
69
+ : '';
70
+ let subText = this.#getSubText(payload);
71
+ subText = subText ? `\n${indentation} ${subText}` : '';
72
+ console.log(`${indentation}${icon} ${prefix}${retries}${message} ${duration}${subText}`);
73
+ }
74
+ #printGroup(payload) {
75
+ const title = this.currentSuiteName !== 'default'
76
+ ? `${this.currentSuiteName} / ${payload.title}`
77
+ : payload.title;
78
+ const suffix = this.currentFileName
79
+ ? cliui.colors.dim(` (${this.#getRelativeFilename(this.currentFileName)})`)
80
+ : '';
81
+ console.log(`\n${title}${suffix}`);
82
+ }
83
+ onTestStart() {
84
+ if (this.currentFileName && this.#isFirstLoneTest) {
85
+ console.log(`\n${cliui.colors.dim(this.#getRelativeFilename(this.currentFileName))}`);
86
+ }
87
+ this.#isFirstLoneTest = false;
88
+ }
89
+ onTestEnd(payload) {
90
+ this.#printTest(payload);
91
+ }
92
+ onGroupStart(payload) {
93
+ this.#isFirstLoneTest = false;
94
+ this.#printGroup(payload);
95
+ }
96
+ onGroupEnd() {
97
+ this.#isFirstLoneTest = true;
98
+ }
99
+ async end() {
100
+ const summary = this.runner.getSummary();
101
+ await this.printSummary(summary);
102
+ }
103
+ }
@@ -1,68 +1,67 @@
1
- import { Refiner, FilteringOptions, ReporterContract } from '@japa/core';
2
- import { Test, Group, TestContext, Runner, Suite } from './core/main';
3
- /**
4
- * The cleanup function for runner hooks
5
- */
6
- export declare type RunnerHooksCleanupHandler = (error: null | any, runner: Runner) => Promise<any> | any;
7
- /**
8
- * The function that can be registered as a runner hook
9
- */
10
- export declare type RunnerHooksHandler = (runner: Runner) => Promise<any> | any | RunnerHooksCleanupHandler | Promise<RunnerHooksCleanupHandler>;
11
- /**
12
- * Allowed filters
13
- */
1
+ /// <reference types="@types/node" resolution-mode="require"/>
2
+ import type { HookHandler } from '@poppinss/hooks/types';
3
+ import type { Emitter, Refiner, Runner, Suite } from '../modules/core/main.js';
4
+ import type { FilteringOptions, NamedReporterContract } from '../modules/core/types.js';
5
+ export * from '../modules/core/types.js';
6
+ export type SetupHookState = [[runner: Runner], [error: Error | null, runner: Runner]];
7
+ export type SetupHookHandler = HookHandler<SetupHookState[0], SetupHookState[1]>;
8
+ export type TeardownHookState = [[runner: Runner], [error: Error | null, runner: Runner]];
9
+ export type TeardownHookHandler = HookHandler<TeardownHookState[0], TeardownHookState[1]>;
10
+ export type HooksEvents = {
11
+ setup: SetupHookState;
12
+ teardown: TeardownHookState;
13
+ };
14
+ export type CLIArgs = {
15
+ _?: string[];
16
+ tags?: string | string[];
17
+ files?: string | string[];
18
+ tests?: string | string[];
19
+ groups?: string | string[];
20
+ timeout?: string;
21
+ retries?: string;
22
+ reporter?: string | string[];
23
+ forceExit?: boolean;
24
+ help?: boolean;
25
+ matchAll?: boolean;
26
+ } & Record<string, string | string[] | boolean>;
14
27
  export type Filters = FilteringOptions & {
15
28
  files?: string[];
16
29
  suites?: string[];
17
30
  };
18
- /**
19
- * Shape of the plugin function
20
- */
21
- export type PluginFn = (config: Required<Config>, runner: Runner, classes: {
22
- Test: typeof Test;
23
- TestContext: typeof TestContext;
24
- Group: typeof Group;
31
+ export type PluginFn = (japa: {
32
+ config: Required<Config>;
33
+ cliArgs: CLIArgs;
34
+ runner: Runner;
35
+ emitter: Emitter;
25
36
  }) => void | Promise<void>;
26
- /**
27
- * Runner hooks
28
- */
29
- export type RunnerHooks = {
30
- setup: RunnerHooksHandler[];
31
- teardown: RunnerHooksHandler[];
32
- };
33
- /**
34
- * Base configuration options
35
- */
36
37
  export type BaseConfig = {
37
- cliArgs?: Record<string, any>;
38
38
  cwd?: string;
39
39
  timeout?: number;
40
- plugins?: PluginFn[];
40
+ retries?: number;
41
41
  filters?: Filters;
42
42
  configureSuite?: (suite: Suite) => void;
43
- reporters?: ReporterContract[];
44
- importer?: (filePath: string) => void | Promise<void>;
43
+ reporters?: {
44
+ activated: string[];
45
+ list: NamedReporterContract[];
46
+ };
47
+ plugins?: PluginFn[];
48
+ importer?: (filePath: URL) => void | Promise<void>;
45
49
  refiner?: Refiner;
46
50
  forceExit?: boolean;
47
- } & Partial<RunnerHooks>;
48
- /**
49
- * Type for the "config.files" property
50
- */
51
- export type ConfigFiles = string[] | (() => string[] | Promise<string[]>);
52
- /**
53
- * Type for the "config.suite" property
54
- */
55
- export type ConfigSuite = {
51
+ setup?: SetupHookHandler[];
52
+ teardown?: TeardownHookHandler[];
53
+ };
54
+ export type TestFiles = string | string[] | (() => URL[] | Promise<URL[]>);
55
+ export type TestSuite = {
56
56
  name: string;
57
- files: string | string[] | (() => string[] | Promise<string[]>);
57
+ files: TestFiles;
58
58
  configure?: (suite: Suite) => void;
59
59
  timeout?: number;
60
+ retries?: number;
60
61
  };
61
- /**
62
- * Configuration options
63
- */
64
62
  export type Config = BaseConfig & ({
65
- files: ConfigFiles;
63
+ files: TestFiles;
66
64
  } | {
67
- suites: ConfigSuite[];
65
+ suites: TestSuite[];
68
66
  });
67
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1 @@
1
- "use strict";
2
- /*
3
- * @japa/runner
4
- *
5
- * (c) Japa.dev
6
- *
7
- * For the full copyright and license information, please view the LICENSE
8
- * file that was distributed with this source code.
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export * from '../modules/core/types.js';
@@ -0,0 +1,11 @@
1
+ import { Config } from './types.js';
2
+ declare class Validator {
3
+ ensureIsConfigured(config: Required<Config> | undefined): void;
4
+ ensureIsInPlanningPhase(phase: 'idle' | 'planning' | 'executing'): void;
5
+ validateSuitesFilter(config: Required<Config>): void;
6
+ validateSuitesForUniqueness(config: Required<Config>): void;
7
+ validateActivatedReporters(config: Required<Config>): void;
8
+ }
9
+ declare const _default: Validator;
10
+ export default _default;
11
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/validator.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAMnC,cAAM,SAAS;IAIb,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,SAAS;IAWvD,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW;IAWhE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IA+B7C,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IAoBpD,0BAA0B,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;CAYpD;;AAED,wBAA8B"}
@@ -0,0 +1,46 @@
1
+ class Validator {
2
+ ensureIsConfigured(config) {
3
+ if (!config) {
4
+ throw new Error(`Cannot run tests. Make sure to call "configure" method before the "run" method`);
5
+ }
6
+ }
7
+ ensureIsInPlanningPhase(phase) {
8
+ if (phase !== 'planning') {
9
+ throw new Error(`Cannot import japa test file directly. It must be imported by calling the "japa.run" method`);
10
+ }
11
+ }
12
+ validateSuitesFilter(config) {
13
+ if (!config.filters.suites || !config.filters.suites.length) {
14
+ return;
15
+ }
16
+ if (!('suites' in config) || !config.suites.length) {
17
+ throw new Error(`Cannot apply suites filter. You have not configured any test suites`);
18
+ }
19
+ const suites = config.suites.map(({ name }) => name);
20
+ const unknownSuites = config.filters.suites.filter((suite) => !suites.includes(suite));
21
+ if (unknownSuites.length) {
22
+ throw new Error(`Cannot apply suites filter. "${unknownSuites[0]}" suite is not configured`);
23
+ }
24
+ }
25
+ validateSuitesForUniqueness(config) {
26
+ if (!('suites' in config)) {
27
+ return;
28
+ }
29
+ const suites = new Set();
30
+ config.suites.forEach(({ name }) => {
31
+ if (suites.has(name)) {
32
+ throw new Error(`Duplicate suite "${name}"`);
33
+ }
34
+ suites.add(name);
35
+ });
36
+ suites.clear();
37
+ }
38
+ validateActivatedReporters(config) {
39
+ const reportersList = config.reporters.list.map(({ name }) => name);
40
+ const unknownReporters = config.reporters.activated.filter((name) => !reportersList.includes(name));
41
+ if (unknownReporters.length) {
42
+ throw new Error(`Invalid reporter "${unknownReporters[0]}". Make sure to register it first inside the "reporters.list" array`);
43
+ }
44
+ }
45
+ }
46
+ export default new Validator();