@japa/runner 3.0.0-8 → 3.0.0-9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/examples/dot.d.ts +1 -0
- package/build/examples/dot.js +11 -0
- package/build/examples/ndjson.d.ts +1 -0
- package/build/examples/ndjson.js +11 -0
- package/build/examples/spec.d.ts +1 -0
- package/build/examples/spec.js +11 -0
- package/build/factories/create_diverse_tests.d.ts +6 -0
- package/build/factories/create_diverse_tests.js +106 -0
- package/build/factories/main.d.ts +5 -42
- package/build/factories/main.js +24 -208
- package/build/factories/runner.d.ts +26 -0
- package/build/factories/runner.js +93 -0
- package/build/index.d.ts +9 -14
- package/build/index.js +202 -237
- package/build/modules/core/main.d.ts +63 -3
- package/build/modules/core/main.js +121 -21
- package/build/modules/core/reporters/base.d.ts +41 -0
- package/build/modules/core/reporters/base.js +183 -0
- package/build/modules/core/types.d.ts +5 -0
- package/build/modules/core/types.js +9 -0
- package/build/src/cli_parser.d.ts +14 -0
- package/build/src/cli_parser.js +75 -0
- package/build/src/config_manager.d.ts +18 -0
- package/build/src/config_manager.js +168 -0
- package/build/src/create_test.d.ts +21 -0
- package/build/src/create_test.js +53 -0
- package/build/src/debug.d.ts +3 -0
- package/build/src/debug.js +10 -0
- package/build/src/exceptions_manager.d.ts +19 -0
- package/build/src/exceptions_manager.js +85 -0
- package/build/src/files_manager.d.ts +18 -0
- package/build/src/files_manager.js +57 -0
- package/build/src/helpers.d.ts +15 -0
- package/build/src/helpers.js +34 -0
- package/build/src/hooks.d.ts +20 -0
- package/build/src/hooks.js +46 -0
- package/build/src/planner.d.ts +25 -0
- package/build/src/planner.js +98 -0
- package/build/src/plugins/retry.d.ts +20 -0
- package/build/src/plugins/retry.js +66 -0
- package/build/src/reporters/dot.d.ts +15 -0
- package/build/src/reporters/dot.js +41 -0
- package/build/src/reporters/main.d.ts +4 -9
- package/build/src/reporters/main.js +37 -11
- package/build/src/reporters/ndjson.d.ts +15 -0
- package/build/src/reporters/ndjson.js +86 -0
- package/build/src/reporters/spec.d.ts +13 -0
- package/build/src/reporters/spec.js +152 -0
- package/build/src/types.d.ts +19 -23
- package/build/src/types.js +9 -14
- package/build/src/validator.d.ts +30 -0
- package/build/src/validator.js +85 -0
- package/build/tests/base_reporter.spec.d.ts +1 -0
- package/build/tests/base_reporter.spec.js +111 -0
- package/build/tests/cli_parser.spec.d.ts +1 -0
- package/build/tests/cli_parser.spec.js +265 -0
- package/build/tests/config_manager.spec.d.ts +1 -0
- package/build/tests/config_manager.spec.js +741 -0
- package/build/tests/core.spec.d.ts +1 -0
- package/build/tests/core.spec.js +31 -0
- package/build/tests/files_manager.spec.d.ts +1 -0
- package/build/tests/files_manager.spec.js +153 -0
- package/build/tests/planner.spec.d.ts +1 -0
- package/build/tests/planner.spec.js +510 -0
- package/build/tests/runner.spec.d.ts +1 -0
- package/build/tests/runner.spec.js +442 -0
- package/build/tests_helpers/main.d.ts +7 -0
- package/build/tests_helpers/main.js +34 -0
- package/package.json +2 -17
- package/build/chunk-7THDHQFT.js +0 -283
- package/build/chunk-HN4AVHWN.js +0 -17
- package/build/chunk-MCOW34SG.js +0 -269
- package/build/chunk-W5IABAQU.js +0 -502
- package/build/main-63126780.d.ts +0 -109
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @japa/runner
|
|
3
|
+
*
|
|
4
|
+
* (c) Japa
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { relative } from 'node:path';
|
|
10
|
+
import { serializeError } from 'serialize-error';
|
|
11
|
+
import { BaseReporter } from '../../modules/core/main.js';
|
|
12
|
+
/**
|
|
13
|
+
* Prints tests progress as JSON. Each event is emitted
|
|
14
|
+
* independently
|
|
15
|
+
*/
|
|
16
|
+
export class NdJSONReporter extends BaseReporter {
|
|
17
|
+
/**
|
|
18
|
+
* Returns the filename relative from the current working dir
|
|
19
|
+
*/
|
|
20
|
+
#getRelativeFilename(fileName) {
|
|
21
|
+
return relative(process.cwd(), fileName);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Serialize errors to JSON
|
|
25
|
+
*/
|
|
26
|
+
#serializeErrors(errors) {
|
|
27
|
+
return errors.map((error) => ({
|
|
28
|
+
phase: error.phase,
|
|
29
|
+
error: serializeError(error.error),
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
onTestEnd(payload) {
|
|
33
|
+
console.log(JSON.stringify({
|
|
34
|
+
event: 'test:end',
|
|
35
|
+
filePath: this.currentFileName,
|
|
36
|
+
relativePath: this.currentFileName
|
|
37
|
+
? this.#getRelativeFilename(this.currentFileName)
|
|
38
|
+
: undefined,
|
|
39
|
+
title: payload.title,
|
|
40
|
+
duration: payload.duration,
|
|
41
|
+
failReason: payload.failReason,
|
|
42
|
+
isFailing: payload.isFailing,
|
|
43
|
+
skipReason: payload.skipReason,
|
|
44
|
+
isSkipped: payload.isSkipped,
|
|
45
|
+
isTodo: payload.isTodo,
|
|
46
|
+
isPinned: payload.isPinned,
|
|
47
|
+
retryAttempt: payload.retryAttempt,
|
|
48
|
+
retries: payload.retries,
|
|
49
|
+
errors: this.#serializeErrors(payload.errors),
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
onGroupStart(payload) {
|
|
53
|
+
console.log(JSON.stringify({
|
|
54
|
+
event: 'group:start',
|
|
55
|
+
title: payload.title,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
onGroupEnd(payload) {
|
|
59
|
+
JSON.stringify({
|
|
60
|
+
event: 'group:end',
|
|
61
|
+
title: payload.title,
|
|
62
|
+
errors: this.#serializeErrors(payload.errors),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
onSuiteStart(payload) {
|
|
66
|
+
console.log(JSON.stringify({
|
|
67
|
+
event: 'suite:start',
|
|
68
|
+
...payload,
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
onSuiteEnd(payload) {
|
|
72
|
+
console.log(JSON.stringify({
|
|
73
|
+
event: 'suite:end',
|
|
74
|
+
...payload,
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
async end() {
|
|
78
|
+
const summary = this.runner.getSummary();
|
|
79
|
+
console.log(JSON.stringify({
|
|
80
|
+
aggregates: summary.aggregates,
|
|
81
|
+
duration: summary.duration,
|
|
82
|
+
failedTestsTitles: summary.failedTestsTitles,
|
|
83
|
+
hasError: summary.hasError,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseReporter } from '../../modules/core/main.js';
|
|
2
|
+
import { GroupStartNode, TestEndNode } from '../../modules/core/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pretty prints the tests on the console
|
|
5
|
+
*/
|
|
6
|
+
export declare class SpecReporter extends BaseReporter {
|
|
7
|
+
#private;
|
|
8
|
+
protected onTestStart(): void;
|
|
9
|
+
protected onTestEnd(payload: TestEndNode): void;
|
|
10
|
+
protected onGroupStart(payload: GroupStartNode): void;
|
|
11
|
+
protected onGroupEnd(): void;
|
|
12
|
+
protected end(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @japa/runner
|
|
3
|
+
*
|
|
4
|
+
* (c) Japa
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import ms from 'ms';
|
|
10
|
+
import { relative } from 'node:path';
|
|
11
|
+
import { colors, icons } from '../helpers.js';
|
|
12
|
+
import { BaseReporter } from '../../modules/core/main.js';
|
|
13
|
+
/**
|
|
14
|
+
* Pretty prints the tests on the console
|
|
15
|
+
*/
|
|
16
|
+
export class SpecReporter extends BaseReporter {
|
|
17
|
+
/**
|
|
18
|
+
* Tracking if the first event we get is for a test without any parent group
|
|
19
|
+
* We need this to decide the display style for tests without groups.
|
|
20
|
+
*/
|
|
21
|
+
#isFirstLoneTest = true;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the icon for the test
|
|
24
|
+
*/
|
|
25
|
+
#getTestIcon(payload) {
|
|
26
|
+
if (payload.isTodo) {
|
|
27
|
+
return colors.cyan(icons.info);
|
|
28
|
+
}
|
|
29
|
+
if (payload.isFailing) {
|
|
30
|
+
return payload.hasError ? colors.magenta(icons.squareSmallFilled) : colors.red(icons.cross);
|
|
31
|
+
}
|
|
32
|
+
if (payload.hasError) {
|
|
33
|
+
return colors.red(icons.cross);
|
|
34
|
+
}
|
|
35
|
+
if (payload.isSkipped) {
|
|
36
|
+
return colors.yellow(icons.bullet);
|
|
37
|
+
}
|
|
38
|
+
return colors.green(icons.tick);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns the test message
|
|
42
|
+
*/
|
|
43
|
+
#getTestMessage(payload) {
|
|
44
|
+
const message = typeof payload.title === 'string' ? payload.title : payload.title.expanded;
|
|
45
|
+
if (payload.isTodo) {
|
|
46
|
+
return colors.blue(message);
|
|
47
|
+
}
|
|
48
|
+
if (payload.isFailing) {
|
|
49
|
+
return payload.hasError ? colors.magenta(message) : colors.red(message);
|
|
50
|
+
}
|
|
51
|
+
if (payload.hasError) {
|
|
52
|
+
return colors.red(message);
|
|
53
|
+
}
|
|
54
|
+
if (payload.isSkipped) {
|
|
55
|
+
return colors.yellow(message);
|
|
56
|
+
}
|
|
57
|
+
return colors.grey(message);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the subtext message for the test
|
|
61
|
+
*/
|
|
62
|
+
#getSubText(payload) {
|
|
63
|
+
if (payload.isSkipped && payload.skipReason) {
|
|
64
|
+
return colors.yellow(payload.skipReason);
|
|
65
|
+
}
|
|
66
|
+
if (!payload.isFailing) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!payload.hasError) {
|
|
70
|
+
return colors.magenta(`Test marked with ".fails()" must finish with an error`);
|
|
71
|
+
}
|
|
72
|
+
if (payload.failReason) {
|
|
73
|
+
return colors.magenta(payload.failReason);
|
|
74
|
+
}
|
|
75
|
+
const testErrorMessage = payload.errors.find((error) => error.phase === 'test');
|
|
76
|
+
if (testErrorMessage && testErrorMessage.error) {
|
|
77
|
+
return colors.magenta(testErrorMessage.error.message);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns the filename relative from the current working dir
|
|
82
|
+
*/
|
|
83
|
+
#getRelativeFilename(fileName) {
|
|
84
|
+
return relative(process.cwd(), fileName);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Prints the test details
|
|
88
|
+
*/
|
|
89
|
+
#printTest(payload) {
|
|
90
|
+
const icon = this.#getTestIcon(payload);
|
|
91
|
+
const message = this.#getTestMessage(payload);
|
|
92
|
+
const prefix = payload.isPinned ? colors.yellow('[PINNED] ') : '';
|
|
93
|
+
const indentation = this.currentFileName || this.currentGroupName ? ' ' : '';
|
|
94
|
+
const duration = colors.dim(`(${ms(Number(payload.duration.toFixed(2)))})`);
|
|
95
|
+
const retries = payload.retryAttempt && payload.retryAttempt > 1
|
|
96
|
+
? colors.dim(`(x${payload.retryAttempt}) `)
|
|
97
|
+
: '';
|
|
98
|
+
let subText = this.#getSubText(payload);
|
|
99
|
+
subText = subText ? `\n${indentation} ${subText}` : '';
|
|
100
|
+
console.log(`${indentation}${icon} ${prefix}${retries}${message} ${duration}${subText}`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Prints the group name
|
|
104
|
+
*/
|
|
105
|
+
#printGroup(payload) {
|
|
106
|
+
const title = this.currentSuiteName !== 'default'
|
|
107
|
+
? `${this.currentSuiteName} / ${payload.title}`
|
|
108
|
+
: payload.title;
|
|
109
|
+
const suffix = this.currentFileName
|
|
110
|
+
? colors.dim(` (${this.#getRelativeFilename(this.currentFileName)})`)
|
|
111
|
+
: '';
|
|
112
|
+
console.log(`\n${title}${suffix}`);
|
|
113
|
+
}
|
|
114
|
+
onTestStart() {
|
|
115
|
+
/**
|
|
116
|
+
* Display the filename when
|
|
117
|
+
*
|
|
118
|
+
* - The filename exists
|
|
119
|
+
* - The test is not under a group
|
|
120
|
+
* - Test is first in a sequence
|
|
121
|
+
*/
|
|
122
|
+
if (this.currentFileName && this.#isFirstLoneTest) {
|
|
123
|
+
console.log(`\n${colors.dim(this.#getRelativeFilename(this.currentFileName))}`);
|
|
124
|
+
}
|
|
125
|
+
this.#isFirstLoneTest = false;
|
|
126
|
+
}
|
|
127
|
+
onTestEnd(payload) {
|
|
128
|
+
this.#printTest(payload);
|
|
129
|
+
}
|
|
130
|
+
onGroupStart(payload) {
|
|
131
|
+
/**
|
|
132
|
+
* When a group starts, we mark the upcoming test as NOT a
|
|
133
|
+
* lone test
|
|
134
|
+
*/
|
|
135
|
+
this.#isFirstLoneTest = false;
|
|
136
|
+
this.#printGroup(payload);
|
|
137
|
+
}
|
|
138
|
+
onGroupEnd() {
|
|
139
|
+
/**
|
|
140
|
+
* When the group ends we assume that the next test can
|
|
141
|
+
* be out of the group, hence a lone test.
|
|
142
|
+
*
|
|
143
|
+
* If this assumption is false, then the `onGroupStart` method
|
|
144
|
+
* will toggle the boolean
|
|
145
|
+
*/
|
|
146
|
+
this.#isFirstLoneTest = true;
|
|
147
|
+
}
|
|
148
|
+
async end() {
|
|
149
|
+
const summary = this.runner.getSummary();
|
|
150
|
+
await this.printSummary(summary);
|
|
151
|
+
}
|
|
152
|
+
}
|
package/build/src/types.d.ts
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { FilteringOptions, NamedReporterContract } from '
|
|
5
|
-
export * from '
|
|
6
|
-
import { Emitter, Refiner } from '@japa/core';
|
|
7
|
-
|
|
1
|
+
/// <reference 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';
|
|
8
6
|
/**
|
|
9
7
|
* Global setup hook
|
|
10
8
|
*/
|
|
11
|
-
type SetupHookState = [[runner: Runner], [error: Error | null, runner: Runner]];
|
|
12
|
-
type SetupHookHandler = HookHandler<SetupHookState[0], SetupHookState[1]>;
|
|
9
|
+
export type SetupHookState = [[runner: Runner], [error: Error | null, runner: Runner]];
|
|
10
|
+
export type SetupHookHandler = HookHandler<SetupHookState[0], SetupHookState[1]>;
|
|
13
11
|
/**
|
|
14
12
|
* Global teardown hook
|
|
15
13
|
*/
|
|
16
|
-
type TeardownHookState = [[runner: Runner], [error: Error | null, runner: Runner]];
|
|
17
|
-
type TeardownHookHandler = HookHandler<TeardownHookState[0], TeardownHookState[1]>;
|
|
14
|
+
export type TeardownHookState = [[runner: Runner], [error: Error | null, runner: Runner]];
|
|
15
|
+
export type TeardownHookHandler = HookHandler<TeardownHookState[0], TeardownHookState[1]>;
|
|
18
16
|
/**
|
|
19
17
|
* Global set of available hooks
|
|
20
18
|
*/
|
|
21
|
-
type HooksEvents = {
|
|
19
|
+
export type HooksEvents = {
|
|
22
20
|
setup: SetupHookState;
|
|
23
21
|
teardown: TeardownHookState;
|
|
24
22
|
};
|
|
25
23
|
/**
|
|
26
24
|
* Parsed command-line arguments
|
|
27
25
|
*/
|
|
28
|
-
type CLIArgs = {
|
|
26
|
+
export type CLIArgs = {
|
|
29
27
|
_?: string[];
|
|
30
28
|
tags?: string | string[];
|
|
31
29
|
files?: string | string[];
|
|
@@ -42,7 +40,7 @@ type CLIArgs = {
|
|
|
42
40
|
/**
|
|
43
41
|
* Set of filters you can apply to run only specific tests
|
|
44
42
|
*/
|
|
45
|
-
type Filters = FilteringOptions & {
|
|
43
|
+
export type Filters = FilteringOptions & {
|
|
46
44
|
files?: string[];
|
|
47
45
|
suites?: string[];
|
|
48
46
|
};
|
|
@@ -50,7 +48,7 @@ type Filters = FilteringOptions & {
|
|
|
50
48
|
* Plugin function receives an instance of the runner,
|
|
51
49
|
* emitter, config and the hooks
|
|
52
50
|
*/
|
|
53
|
-
type PluginFn = (japa: {
|
|
51
|
+
export type PluginFn = (japa: {
|
|
54
52
|
config: NormalizedConfig;
|
|
55
53
|
cliArgs: CLIArgs;
|
|
56
54
|
runner: Runner;
|
|
@@ -59,7 +57,7 @@ type PluginFn = (japa: {
|
|
|
59
57
|
/**
|
|
60
58
|
* Base configuration options
|
|
61
59
|
*/
|
|
62
|
-
type BaseConfig = {
|
|
60
|
+
export type BaseConfig = {
|
|
63
61
|
/**
|
|
64
62
|
* Current working directory. It is required to search for
|
|
65
63
|
* the test files
|
|
@@ -122,11 +120,11 @@ type BaseConfig = {
|
|
|
122
120
|
* A collection of test files defined as a glob or a callback
|
|
123
121
|
* function that returns an array of URLs
|
|
124
122
|
*/
|
|
125
|
-
type TestFiles = string | string[] | (() => URL[] | Promise<URL[]>);
|
|
123
|
+
export type TestFiles = string | string[] | (() => URL[] | Promise<URL[]>);
|
|
126
124
|
/**
|
|
127
125
|
* A test suite to register tests under a named suite
|
|
128
126
|
*/
|
|
129
|
-
type TestSuite = {
|
|
127
|
+
export type TestSuite = {
|
|
130
128
|
/**
|
|
131
129
|
* A unique name for the suite
|
|
132
130
|
*/
|
|
@@ -153,7 +151,7 @@ type TestSuite = {
|
|
|
153
151
|
/**
|
|
154
152
|
* BaseConfig after normalized by the config manager
|
|
155
153
|
*/
|
|
156
|
-
type NormalizedBaseConfig = Required<Omit<BaseConfig, 'reporters'>> & {
|
|
154
|
+
export type NormalizedBaseConfig = Required<Omit<BaseConfig, 'reporters'>> & {
|
|
157
155
|
reporters: {
|
|
158
156
|
activated: string[];
|
|
159
157
|
list: NamedReporterContract[];
|
|
@@ -162,7 +160,7 @@ type NormalizedBaseConfig = Required<Omit<BaseConfig, 'reporters'>> & {
|
|
|
162
160
|
/**
|
|
163
161
|
* Configuration options
|
|
164
162
|
*/
|
|
165
|
-
type Config = BaseConfig & ({
|
|
163
|
+
export type Config = BaseConfig & ({
|
|
166
164
|
files: TestFiles;
|
|
167
165
|
} | {
|
|
168
166
|
suites: TestSuite[];
|
|
@@ -170,10 +168,8 @@ type Config = BaseConfig & ({
|
|
|
170
168
|
/**
|
|
171
169
|
* Config after normalized by the config manager
|
|
172
170
|
*/
|
|
173
|
-
type NormalizedConfig = NormalizedBaseConfig & ({
|
|
171
|
+
export type NormalizedConfig = NormalizedBaseConfig & ({
|
|
174
172
|
files: TestFiles;
|
|
175
173
|
} | {
|
|
176
174
|
suites: Required<TestSuite>[];
|
|
177
175
|
});
|
|
178
|
-
|
|
179
|
-
export { BaseConfig, CLIArgs, Config, Filters, HooksEvents, NormalizedBaseConfig, NormalizedConfig, PluginFn, SetupHookHandler, SetupHookState, TeardownHookHandler, TeardownHookState, TestFiles, TestSuite };
|
package/build/src/types.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
__reExport(types_exports, types_star);
|
|
11
|
-
import * as types_star from "@japa/core/types";
|
|
12
|
-
|
|
13
|
-
// src/types.ts
|
|
14
|
-
__reExport(types_exports2, types_exports);
|
|
1
|
+
/*
|
|
2
|
+
* @japa/runner
|
|
3
|
+
*
|
|
4
|
+
* (c) Japa
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
export * from '../modules/core/types.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NormalizedConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validator encapsulates the validations to perform before running
|
|
4
|
+
* the tests
|
|
5
|
+
*/
|
|
6
|
+
declare class Validator {
|
|
7
|
+
/**
|
|
8
|
+
* Ensures the japa is configured. Otherwise raises an exception
|
|
9
|
+
*/
|
|
10
|
+
ensureIsConfigured(config: NormalizedConfig | undefined): void;
|
|
11
|
+
/**
|
|
12
|
+
* Ensures the japa is in planning phase
|
|
13
|
+
*/
|
|
14
|
+
ensureIsInPlanningPhase(phase: 'idle' | 'planning' | 'executing'): void;
|
|
15
|
+
/**
|
|
16
|
+
* Ensures the suites filter uses a subset of the user configured suites.
|
|
17
|
+
*/
|
|
18
|
+
validateSuitesFilter(config: NormalizedConfig): void;
|
|
19
|
+
/**
|
|
20
|
+
* Ensure there are unique suites
|
|
21
|
+
*/
|
|
22
|
+
validateSuitesForUniqueness(config: NormalizedConfig): void;
|
|
23
|
+
/**
|
|
24
|
+
* Ensure the activated reporters are in the list of defined
|
|
25
|
+
* reporters
|
|
26
|
+
*/
|
|
27
|
+
validateActivatedReporters(config: NormalizedConfig): void;
|
|
28
|
+
}
|
|
29
|
+
declare const _default: Validator;
|
|
30
|
+
export default _default;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @japa/runner
|
|
3
|
+
*
|
|
4
|
+
* (c) Japa
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Validator encapsulates the validations to perform before running
|
|
11
|
+
* the tests
|
|
12
|
+
*/
|
|
13
|
+
class Validator {
|
|
14
|
+
/**
|
|
15
|
+
* Ensures the japa is configured. Otherwise raises an exception
|
|
16
|
+
*/
|
|
17
|
+
ensureIsConfigured(config) {
|
|
18
|
+
if (!config) {
|
|
19
|
+
throw new Error(`Cannot run tests. Make sure to call "configure" method before the "run" method`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Ensures the japa is in planning phase
|
|
24
|
+
*/
|
|
25
|
+
ensureIsInPlanningPhase(phase) {
|
|
26
|
+
if (phase !== 'planning') {
|
|
27
|
+
throw new Error(`Cannot import japa test file directly. It must be imported by calling the "japa.run" method`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Ensures the suites filter uses a subset of the user configured suites.
|
|
32
|
+
*/
|
|
33
|
+
validateSuitesFilter(config) {
|
|
34
|
+
/**
|
|
35
|
+
* Do not perform any validation if no filters are applied
|
|
36
|
+
* in the first place
|
|
37
|
+
*/
|
|
38
|
+
if (!config.filters.suites || !config.filters.suites.length) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Notify user they have applied the suites filter but forgot to define
|
|
43
|
+
* suites
|
|
44
|
+
*/
|
|
45
|
+
if (!('suites' in config) || !config.suites.length) {
|
|
46
|
+
throw new Error(`Cannot apply suites filter. You have not configured any test suites`);
|
|
47
|
+
}
|
|
48
|
+
const suites = config.suites.map(({ name }) => name);
|
|
49
|
+
/**
|
|
50
|
+
* Find unknown suites and report the error
|
|
51
|
+
*/
|
|
52
|
+
const unknownSuites = config.filters.suites.filter((suite) => !suites.includes(suite));
|
|
53
|
+
if (unknownSuites.length) {
|
|
54
|
+
throw new Error(`Cannot apply suites filter. "${unknownSuites[0]}" suite is not configured`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Ensure there are unique suites
|
|
59
|
+
*/
|
|
60
|
+
validateSuitesForUniqueness(config) {
|
|
61
|
+
if (!('suites' in config)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const suites = new Set();
|
|
65
|
+
config.suites.forEach(({ name }) => {
|
|
66
|
+
if (suites.has(name)) {
|
|
67
|
+
throw new Error(`Duplicate suite "${name}"`);
|
|
68
|
+
}
|
|
69
|
+
suites.add(name);
|
|
70
|
+
});
|
|
71
|
+
suites.clear();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Ensure the activated reporters are in the list of defined
|
|
75
|
+
* reporters
|
|
76
|
+
*/
|
|
77
|
+
validateActivatedReporters(config) {
|
|
78
|
+
const reportersList = config.reporters.list.map(({ name }) => name);
|
|
79
|
+
const unknownReporters = config.reporters.activated.filter((name) => !reportersList.includes(name));
|
|
80
|
+
if (unknownReporters.length) {
|
|
81
|
+
throw new Error(`Invalid reporter "${unknownReporters[0]}". Make sure to register it first inside the "reporters.list" array`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export default new Validator();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @japa/runner
|
|
3
|
+
*
|
|
4
|
+
* (c) Japa
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { test } from 'node:test';
|
|
10
|
+
import chaiSubset from 'chai-subset';
|
|
11
|
+
import { assert, default as chai } from 'chai';
|
|
12
|
+
chai.use(chaiSubset);
|
|
13
|
+
import { wrapAssertions } from '../tests_helpers/main.js';
|
|
14
|
+
import { Test, Suite, Group, Runner, Refiner, Emitter, TestContext, BaseReporter, } from '../modules/core/main.js';
|
|
15
|
+
test.describe('Base reporter', () => {
|
|
16
|
+
test('extend base reporter to create a custom reporter', async () => {
|
|
17
|
+
const stack = [];
|
|
18
|
+
class MyReporter extends BaseReporter {
|
|
19
|
+
async start() {
|
|
20
|
+
stack.push('reporter started');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const emitter = new Emitter();
|
|
24
|
+
const runner = new Runner(emitter);
|
|
25
|
+
runner.registerReporter((r, e) => new MyReporter({}).boot(r, e));
|
|
26
|
+
await runner.start();
|
|
27
|
+
await wrapAssertions(() => {
|
|
28
|
+
assert.deepEqual(stack, ['reporter started']);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
test('invoke handlers when suite, groups and tests are executed', async () => {
|
|
32
|
+
const stack = [];
|
|
33
|
+
let summary;
|
|
34
|
+
class MyReporter extends BaseReporter {
|
|
35
|
+
async start() {
|
|
36
|
+
stack.push('reporter started');
|
|
37
|
+
}
|
|
38
|
+
async end() {
|
|
39
|
+
summary = this.runner.getSummary();
|
|
40
|
+
stack.push('reporter ended');
|
|
41
|
+
}
|
|
42
|
+
onTestStart(t) {
|
|
43
|
+
assert.equal(t.title.expanded, '2 + 2');
|
|
44
|
+
assert.equal(this.currentSuiteName, 'unit');
|
|
45
|
+
assert.equal(this.currentGroupName, 'default');
|
|
46
|
+
stack.push('test started');
|
|
47
|
+
}
|
|
48
|
+
onTestEnd(t) {
|
|
49
|
+
assert.equal(t.title.expanded, '2 + 2');
|
|
50
|
+
assert.isFalse(t.hasError);
|
|
51
|
+
stack.push('test ended');
|
|
52
|
+
}
|
|
53
|
+
onGroupStart(g) {
|
|
54
|
+
assert.equal(g.title, 'default');
|
|
55
|
+
assert.equal(this.currentSuiteName, 'unit');
|
|
56
|
+
stack.push('group started');
|
|
57
|
+
}
|
|
58
|
+
onGroupEnd(g) {
|
|
59
|
+
assert.equal(g.title, 'default');
|
|
60
|
+
assert.isFalse(g.hasError);
|
|
61
|
+
stack.push('group ended');
|
|
62
|
+
}
|
|
63
|
+
onSuiteStart(s) {
|
|
64
|
+
assert.equal(s.name, 'unit');
|
|
65
|
+
stack.push('suite started');
|
|
66
|
+
}
|
|
67
|
+
onSuiteEnd(s) {
|
|
68
|
+
assert.equal(s.name, 'unit');
|
|
69
|
+
stack.push('suite ended');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const emitter = new Emitter();
|
|
73
|
+
const runner = new Runner(emitter);
|
|
74
|
+
const refiner = new Refiner();
|
|
75
|
+
const suite = new Suite('unit', emitter, refiner);
|
|
76
|
+
const group = new Group('default', emitter, refiner);
|
|
77
|
+
const t = new Test('2 + 2', (_t) => new TestContext(_t), emitter, refiner, group);
|
|
78
|
+
group.add(t);
|
|
79
|
+
suite.add(group);
|
|
80
|
+
runner.add(suite);
|
|
81
|
+
runner.registerReporter((r, e) => new MyReporter({}).boot(r, e));
|
|
82
|
+
await runner.start();
|
|
83
|
+
await runner.exec();
|
|
84
|
+
await runner.end();
|
|
85
|
+
await wrapAssertions(() => {
|
|
86
|
+
assert.deepEqual(stack, [
|
|
87
|
+
'reporter started',
|
|
88
|
+
'suite started',
|
|
89
|
+
'group started',
|
|
90
|
+
'test started',
|
|
91
|
+
'test ended',
|
|
92
|
+
'group ended',
|
|
93
|
+
'suite ended',
|
|
94
|
+
'reporter ended',
|
|
95
|
+
]);
|
|
96
|
+
assert.containSubset(summary, {
|
|
97
|
+
aggregates: {
|
|
98
|
+
total: 1,
|
|
99
|
+
failed: 0,
|
|
100
|
+
passed: 0,
|
|
101
|
+
regression: 0,
|
|
102
|
+
skipped: 0,
|
|
103
|
+
todo: 1,
|
|
104
|
+
},
|
|
105
|
+
hasError: false,
|
|
106
|
+
failureTree: [],
|
|
107
|
+
failedTestsTitles: [],
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|