@itmetsam/samurai-framework 0.15.1 → 0.15.2
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/dist/api.d.ts +1 -1
- package/dist/cli/main.js +1 -1
- package/dist/runner/pooled-run.js +3 -3
- package/dist/runner/registry.d.ts +13 -4
- package/dist/runner/registry.js +26 -9
- package/dist/runner/run-test.js +1 -1
- package/dist/runner/run.d.ts +2 -0
- package/dist/runner/run.js +2 -1
- package/dist/runner/skip.d.ts +2 -1
- package/dist/runner/skip.js +3 -2
- package/dist/runner/suite.d.ts +10 -4
- package/dist/runner/suite.js +19 -10
- package/dist/runner/test-runner.js +3 -3
- package/dist/steps/model.d.ts +2 -0
- package/dist/steps/parse.js +36 -10
- package/dist/types/test.d.ts +10 -0
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { test, describe, beforeEach, afterEach, beforeAll, afterAll, } from "./r
|
|
|
2
2
|
export { expect } from "./assert/expect.js";
|
|
3
3
|
export { defineConfig } from "./config/config.js";
|
|
4
4
|
export { defineStep, type StepDefinition, type StepResult, type StepRunInput, } from "./flows/steps/index.js";
|
|
5
|
-
export type { AllHookFixtures, TestFixtures } from "./types/test.js";
|
|
5
|
+
export type { AllHookFixtures, TestDetails, TestFixtures, } from "./types/test.js";
|
|
6
6
|
export { generatedFile, type GeneratedFile, type FileInput, } from "./browser/generated-files.js";
|
package/dist/cli/main.js
CHANGED
|
@@ -60,7 +60,7 @@ export async function main(argv, io) {
|
|
|
60
60
|
io.out(`${JSON.stringify(tests, null, 2)}\n`);
|
|
61
61
|
else
|
|
62
62
|
for (const found of tests)
|
|
63
|
-
io.out(`${found.name}${found.modifier ? ` [${found.modifier}]` : ""}\n ${found.file}\n`);
|
|
63
|
+
io.out(`${found.name}${found.modifier ? ` [${found.modifier}${found.reason ? `: ${found.reason}` : ""}]` : ""}\n ${found.file}\n`);
|
|
64
64
|
return 0;
|
|
65
65
|
}
|
|
66
66
|
const human = values.json
|
|
@@ -70,9 +70,9 @@ export function poolMode(input) {
|
|
|
70
70
|
export async function runPooled(pool, planned, items, reporter, signal) {
|
|
71
71
|
reporter.setOrder(planned);
|
|
72
72
|
for (const { test, browser } of planned) {
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
reporter.onTestSkipped(test, browser,
|
|
73
|
+
const skip = staticSkip(test);
|
|
74
|
+
if (skip)
|
|
75
|
+
reporter.onTestSkipped(test, browser, skip);
|
|
76
76
|
}
|
|
77
77
|
const started = new Set();
|
|
78
78
|
const ended = new Set();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AllHook, EachHook, RegisteredTestCase, TestCaseBase } from "../types/test.js";
|
|
1
|
+
import type { AllHook, EachHook, RegisteredTestCase, TestCaseBase, TestDetails } from "../types/test.js";
|
|
2
2
|
type Body = TestCaseBase["function"];
|
|
3
3
|
/** `test(title, fn)`, `test.skip(title, fn)`, `test.skip(condition, reason)` and the other forms */
|
|
4
4
|
export interface TestFunction {
|
|
@@ -10,16 +10,25 @@ export interface TestFunction {
|
|
|
10
10
|
/** Runs only this test (and the other `only` ones) */
|
|
11
11
|
only(title: string, fn: Body): void;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* With a title and a body it registers a skipped test, `{ reason }` saying why; with a condition it skips the
|
|
15
|
+
* running test when the condition is true
|
|
16
|
+
*/
|
|
14
17
|
interface SkipFunction {
|
|
15
18
|
(title: string, fn: Body): void;
|
|
19
|
+
(title: string, details: TestDetails, fn: Body): void;
|
|
16
20
|
(condition: boolean, reason?: string): void;
|
|
17
21
|
}
|
|
22
|
+
/** `describe.skip` and `describe.fixme`: every test inside gets the modifier, and `{ reason }` says why */
|
|
23
|
+
interface DescribeSkipFunction {
|
|
24
|
+
(title: string, fn: () => void): void;
|
|
25
|
+
(title: string, details: TestDetails, fn: () => void): void;
|
|
26
|
+
}
|
|
18
27
|
/** `describe(title, fn)` and the same with a modifier on every test inside */
|
|
19
28
|
export interface DescribeFunction {
|
|
20
29
|
(title: string, fn: () => void): void;
|
|
21
|
-
skip
|
|
22
|
-
fixme
|
|
30
|
+
skip: DescribeSkipFunction;
|
|
31
|
+
fixme: DescribeSkipFunction;
|
|
23
32
|
only(title: string, fn: () => void): void;
|
|
24
33
|
}
|
|
25
34
|
export declare const test: TestFunction;
|
package/dist/runner/registry.js
CHANGED
|
@@ -4,8 +4,8 @@ import { SkipSignal } from "./skip.js";
|
|
|
4
4
|
import { addHook, currentSuite, enterSuite, leaveSuite, modifierOf, resetSuites, } from "./suite.js";
|
|
5
5
|
const registered = [];
|
|
6
6
|
/** Runs `fn` as the `describe` block `title`, under `modifier` when there is one. `fn` runs immediately and must be synchronous. */
|
|
7
|
-
function openDescribe(file, title, fn, modifier) {
|
|
8
|
-
enterSuite(file, title, modifier);
|
|
7
|
+
function openDescribe(file, title, fn, modifier, reason) {
|
|
8
|
+
enterSuite(file, title, modifier, reason);
|
|
9
9
|
try {
|
|
10
10
|
const result = fn();
|
|
11
11
|
if (result instanceof Promise) {
|
|
@@ -17,18 +17,17 @@ function openDescribe(file, title, fn, modifier) {
|
|
|
17
17
|
leaveSuite();
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
function add(file, title, fn, modifier) {
|
|
20
|
+
function add(file, title, fn, modifier, reason) {
|
|
21
21
|
const suite = currentSuite(file);
|
|
22
22
|
const titlePath = [...titlesOf(suite), title];
|
|
23
23
|
const name = titlePath.join(" > ");
|
|
24
|
-
const effective = modifierOf(modifier, suite);
|
|
25
24
|
registered.push({
|
|
26
25
|
name,
|
|
27
26
|
titlePath,
|
|
28
27
|
function: fn,
|
|
29
28
|
file,
|
|
30
29
|
suite,
|
|
31
|
-
...(
|
|
30
|
+
...modifierOf({ modifier, ...(reason !== undefined && { reason }) }, suite),
|
|
32
31
|
});
|
|
33
32
|
logger.debug("Registered test %s", name);
|
|
34
33
|
}
|
|
@@ -40,26 +39,44 @@ function titlesOf(suite) {
|
|
|
40
39
|
titles.unshift(s.title);
|
|
41
40
|
return titles;
|
|
42
41
|
}
|
|
42
|
+
/** The body and `{ reason }` of `(title, fn)` and `(title, details, fn)` */
|
|
43
|
+
function bodyAndReason(call, title, second, third) {
|
|
44
|
+
const [details, fn] = typeof second === "function"
|
|
45
|
+
? [undefined, second]
|
|
46
|
+
: [second, third];
|
|
47
|
+
if (typeof fn !== "function")
|
|
48
|
+
throw new TypeError(`${call}(${JSON.stringify(title)}) needs a function as its last argument`);
|
|
49
|
+
const reason = details?.reason;
|
|
50
|
+
return { fn: fn, ...(reason !== undefined && { reason }) };
|
|
51
|
+
}
|
|
43
52
|
/** `test.skip` and `test.fixme`: a title and a body register a test with the modifier; a condition skips the running test */
|
|
44
53
|
function skipping(annotation) {
|
|
45
|
-
return ((first, second) => {
|
|
54
|
+
return ((first, second, third) => {
|
|
46
55
|
if (typeof first === "string") {
|
|
56
|
+
const { fn, reason } = bodyAndReason(`test.${annotation}`, first, second, third);
|
|
47
57
|
// Frames: Error, callerFile, this function, the spec
|
|
48
|
-
add(callerFile(), first,
|
|
58
|
+
add(callerFile(), first, fn, annotation, reason);
|
|
49
59
|
return;
|
|
50
60
|
}
|
|
51
61
|
if (first)
|
|
52
62
|
throw new SkipSignal(annotation, second);
|
|
53
63
|
});
|
|
54
64
|
}
|
|
65
|
+
/** `describe.skip` and `describe.fixme`, with or without `{ reason }` */
|
|
66
|
+
function describeSkipping(annotation) {
|
|
67
|
+
return ((title, second, third) => {
|
|
68
|
+
const { fn, reason } = bodyAndReason(`describe.${annotation}`, title, second, third);
|
|
69
|
+
openDescribe(callerFile(), title, fn, annotation, reason);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
55
72
|
export const test = Object.assign((title, fn) => add(callerFile(), title, fn), {
|
|
56
73
|
skip: skipping("skip"),
|
|
57
74
|
fixme: skipping("fixme"),
|
|
58
75
|
only: (title, fn) => add(callerFile(), title, fn, "only"),
|
|
59
76
|
});
|
|
60
77
|
export const describe = Object.assign((title, fn) => openDescribe(callerFile(), title, fn), {
|
|
61
|
-
skip: (
|
|
62
|
-
fixme: (
|
|
78
|
+
skip: describeSkipping("skip"),
|
|
79
|
+
fixme: describeSkipping("fixme"),
|
|
63
80
|
only: (title, fn) => openDescribe(callerFile(), title, fn, "only"),
|
|
64
81
|
});
|
|
65
82
|
/** Runs before each test of the `describe` block it is written in (of the file, at the top level) */
|
package/dist/runner/run-test.js
CHANGED
|
@@ -67,7 +67,7 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
67
67
|
// A test marked skip or fixme never runs, whoever asked for it (a flow's test node, a worker)
|
|
68
68
|
const marked = staticSkip(test);
|
|
69
69
|
if (marked) {
|
|
70
|
-
reporter.onTestSkipped(test, browserName,
|
|
70
|
+
reporter.onTestSkipped(test, browserName, marked);
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
logger.verbose("Starting test: %s in %s", test.name, browserName);
|
package/dist/runner/run.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export interface FoundTest {
|
|
|
21
21
|
file: string;
|
|
22
22
|
/** `skip` or `fixme` (not run), or `only` (focused); absent for a plain test. A modifier on a `describe` counts. */
|
|
23
23
|
modifier?: Modifier;
|
|
24
|
+
/** The `{ reason }` given with the `skip` or `fixme` that applies */
|
|
25
|
+
reason?: string;
|
|
24
26
|
}
|
|
25
27
|
/** Imports the project's specs without running anything and lists the tests the options select */
|
|
26
28
|
export declare function listTests(options?: RunTestsOptions): Promise<FoundTest[]>;
|
package/dist/runner/run.js
CHANGED
|
@@ -35,10 +35,11 @@ export async function runTests(options = {}) {
|
|
|
35
35
|
}
|
|
36
36
|
/** Imports the project's specs without running anything and lists the tests the options select */
|
|
37
37
|
export async function listTests(options = {}) {
|
|
38
|
-
return inProject(options, async (runner) => (await runner.register()).map(({ name, file, modifier }) => ({
|
|
38
|
+
return inProject(options, async (runner) => (await runner.register()).map(({ name, file, modifier, reason }) => ({
|
|
39
39
|
name,
|
|
40
40
|
file,
|
|
41
41
|
...(modifier && { modifier }),
|
|
42
|
+
...(reason !== undefined && { reason }),
|
|
42
43
|
})));
|
|
43
44
|
}
|
|
44
45
|
/** Imports the project's specs without running anything and lists the config's groups with the tests each holds */
|
package/dist/runner/skip.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RegisteredTestCase } from "../types/test.js";
|
|
2
|
+
import type { TestSkip } from "./reporter.js";
|
|
2
3
|
/** Thrown by `test.skip(condition, reason)` and `test.fixme(condition, reason)` inside a test: the test ends as skipped */
|
|
3
4
|
export declare class SkipSignal extends Error {
|
|
4
5
|
readonly annotation: "skip" | "fixme";
|
|
@@ -7,4 +8,4 @@ export declare class SkipSignal extends Error {
|
|
|
7
8
|
}
|
|
8
9
|
export declare function isSkipSignal(error: unknown): error is SkipSignal;
|
|
9
10
|
/** Why a test does not run at all: it is marked `skip` or `fixme`, itself or by a `describe` around it */
|
|
10
|
-
export declare function staticSkip(test: Pick<RegisteredTestCase, "modifier"
|
|
11
|
+
export declare function staticSkip(test: Pick<RegisteredTestCase, "modifier" | "reason">): TestSkip | undefined;
|
package/dist/runner/skip.js
CHANGED
|
@@ -12,7 +12,8 @@ export function isSkipSignal(error) {
|
|
|
12
12
|
}
|
|
13
13
|
/** Why a test does not run at all: it is marked `skip` or `fixme`, itself or by a `describe` around it */
|
|
14
14
|
export function staticSkip(test) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const { modifier, reason } = test;
|
|
16
|
+
return modifier === "skip" || modifier === "fixme"
|
|
17
|
+
? { annotation: modifier, ...(reason !== undefined && { reason }) }
|
|
17
18
|
: undefined;
|
|
18
19
|
}
|
package/dist/runner/suite.d.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import type { EachHook, Modifier, Suite } from "../types/test.js";
|
|
2
2
|
/** The four hook lists a suite can hold */
|
|
3
3
|
export type HookKind = "beforeEach" | "afterEach" | "beforeAll" | "afterAll";
|
|
4
|
-
export declare function newSuite(title?: string, parent?: Suite, modifier?: Modifier): Suite;
|
|
4
|
+
export declare function newSuite(title?: string, parent?: Suite, modifier?: Modifier, reason?: string): Suite;
|
|
5
5
|
/** The suite a test or hook written now belongs to: the innermost open `describe`, else the file's own */
|
|
6
6
|
export declare function currentSuite(file: string): Suite;
|
|
7
7
|
/** Opens a `describe` block under the current suite; `leaveSuite` closes it */
|
|
8
|
-
export declare function enterSuite(file: string, title: string, modifier?: Modifier): Suite;
|
|
8
|
+
export declare function enterSuite(file: string, title: string, modifier?: Modifier, reason?: string): Suite;
|
|
9
9
|
export declare function leaveSuite(): void;
|
|
10
10
|
/** Forgets every suite: a run registers its specs afresh */
|
|
11
11
|
export declare function resetSuites(): void;
|
|
12
12
|
/**
|
|
13
13
|
* What applies to a test: the innermost `skip` or `fixme` (the test's own, then its suites', inside out), else
|
|
14
|
-
* `only` when the test or any suite around it is focused. A skip beats a focus.
|
|
14
|
+
* `only` when the test or any suite around it is focused. A skip beats a focus. The reason comes with the skip
|
|
15
|
+
* or fixme that applies.
|
|
15
16
|
*/
|
|
16
|
-
export declare function modifierOf(own:
|
|
17
|
+
export declare function modifierOf(own: Mark, suite: Suite): Mark;
|
|
18
|
+
/** A modifier and the reason given with it */
|
|
19
|
+
export interface Mark {
|
|
20
|
+
modifier?: Modifier;
|
|
21
|
+
reason?: string;
|
|
22
|
+
}
|
|
17
23
|
/** The suites from the file's root down to `suite` */
|
|
18
24
|
export declare function suiteChain(suite: Suite): Suite[];
|
|
19
25
|
/** The `beforeEach` hooks of a test: outermost suite first, in the order they were written */
|
package/dist/runner/suite.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
const roots = new Map();
|
|
3
3
|
/** The `describe` blocks being registered, outermost first */
|
|
4
4
|
const open = [];
|
|
5
|
-
export function newSuite(title, parent, modifier) {
|
|
5
|
+
export function newSuite(title, parent, modifier, reason) {
|
|
6
6
|
return {
|
|
7
7
|
...(title !== undefined && { title }),
|
|
8
8
|
...(parent && { parent }),
|
|
9
9
|
...(modifier && { modifier }),
|
|
10
|
+
...(reason !== undefined && { reason }),
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
/** The suite a test or hook written now belongs to: the innermost open `describe`, else the file's own */
|
|
@@ -22,8 +23,8 @@ export function currentSuite(file) {
|
|
|
22
23
|
return root;
|
|
23
24
|
}
|
|
24
25
|
/** Opens a `describe` block under the current suite; `leaveSuite` closes it */
|
|
25
|
-
export function enterSuite(file, title, modifier) {
|
|
26
|
-
const suite = newSuite(title, currentSuite(file), modifier);
|
|
26
|
+
export function enterSuite(file, title, modifier, reason) {
|
|
27
|
+
const suite = newSuite(title, currentSuite(file), modifier, reason);
|
|
27
28
|
open.push(suite);
|
|
28
29
|
return suite;
|
|
29
30
|
}
|
|
@@ -37,18 +38,26 @@ export function resetSuites() {
|
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
40
|
* What applies to a test: the innermost `skip` or `fixme` (the test's own, then its suites', inside out), else
|
|
40
|
-
* `only` when the test or any suite around it is focused. A skip beats a focus.
|
|
41
|
+
* `only` when the test or any suite around it is focused. A skip beats a focus. The reason comes with the skip
|
|
42
|
+
* or fixme that applies.
|
|
41
43
|
*/
|
|
42
44
|
export function modifierOf(own, suite) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
if (own.modifier === "skip" || own.modifier === "fixme")
|
|
46
|
+
return markOf(own);
|
|
47
|
+
let focused = own.modifier === "only";
|
|
48
|
+
for (let s = suite; s; s = s.parent) {
|
|
46
49
|
if (s.modifier === "only")
|
|
47
50
|
focused = true;
|
|
48
|
-
else
|
|
49
|
-
|
|
51
|
+
else if (s.modifier)
|
|
52
|
+
return markOf(s);
|
|
50
53
|
}
|
|
51
|
-
return
|
|
54
|
+
return focused ? { modifier: "only" } : {};
|
|
55
|
+
}
|
|
56
|
+
function markOf({ modifier, reason }) {
|
|
57
|
+
return {
|
|
58
|
+
...(modifier && { modifier }),
|
|
59
|
+
...(reason !== undefined && { reason }),
|
|
60
|
+
};
|
|
52
61
|
}
|
|
53
62
|
/** The suites from the file's root down to `suite` */
|
|
54
63
|
export function suiteChain(suite) {
|
|
@@ -123,9 +123,9 @@ export default class TestRunner {
|
|
|
123
123
|
try {
|
|
124
124
|
for (const browser of browsers) {
|
|
125
125
|
for (const test of selected) {
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
reporter.onTestSkipped(test, browser,
|
|
126
|
+
const skip = staticSkip(test);
|
|
127
|
+
if (skip) {
|
|
128
|
+
reporter.onTestSkipped(test, browser, skip);
|
|
129
129
|
continue;
|
|
130
130
|
}
|
|
131
131
|
if (signal?.aborted) {
|
package/dist/steps/model.d.ts
CHANGED
|
@@ -158,4 +158,6 @@ export interface ParsedTest {
|
|
|
158
158
|
};
|
|
159
159
|
/** `skip` or `fixme` (not run), or `only` (focused), as the runner applies it: a modifier on a `describe` counts */
|
|
160
160
|
modifier?: Modifier;
|
|
161
|
+
/** The `{ reason }` written with the `skip` or `fixme` that applies, when it is a string literal */
|
|
162
|
+
reason?: string;
|
|
161
163
|
}
|
package/dist/steps/parse.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { stringOf } from "./parse/literals.js";
|
|
2
|
+
import { readObject, stringOf } from "./parse/literals.js";
|
|
3
3
|
import { readStep } from "./parse/step.js";
|
|
4
4
|
function parseStatement(source, statement, sourceFile) {
|
|
5
5
|
const start = statement.getStart(sourceFile);
|
|
@@ -57,11 +57,33 @@ function calleeOf(expression) {
|
|
|
57
57
|
};
|
|
58
58
|
return undefined;
|
|
59
59
|
}
|
|
60
|
-
/**
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* The callback of `test(title, fn)` and `describe(title, fn)`, and for a skip or fixme also of
|
|
62
|
+
* `(title, { reason }, fn)` with the reason when it is a literal
|
|
63
|
+
*/
|
|
64
|
+
function callbackOf(node, modifier) {
|
|
65
|
+
const [, second, third] = node.arguments;
|
|
66
|
+
if ((modifier === "skip" || modifier === "fixme") &&
|
|
67
|
+
second &&
|
|
68
|
+
ts.isObjectLiteralExpression(second)) {
|
|
69
|
+
const reason = readObject(second, ["reason"])?.reason;
|
|
70
|
+
return {
|
|
71
|
+
callback: third,
|
|
72
|
+
...(typeof reason === "string" && { reason }),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { callback: second };
|
|
76
|
+
}
|
|
77
|
+
/** What the runner applies to a test (see `modifierOf` in the runner): the innermost `skip` or `fixme` with its reason, else `only` */
|
|
78
|
+
function effectiveMark(own, describes) {
|
|
62
79
|
const chain = [own, ...[...describes].reverse()];
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
const skip = chain.find((m) => m.modifier === "skip" || m.modifier === "fixme");
|
|
81
|
+
if (skip)
|
|
82
|
+
return {
|
|
83
|
+
modifier: skip.modifier,
|
|
84
|
+
...(skip.reason !== undefined && { reason: skip.reason }),
|
|
85
|
+
};
|
|
86
|
+
return chain.some((m) => m.modifier === "only") ? { modifier: "only" } : {};
|
|
65
87
|
}
|
|
66
88
|
/** The tests in a spec file, with their steps and where each statement sits */
|
|
67
89
|
export function parseSpec(source) {
|
|
@@ -73,24 +95,28 @@ export function parseSpec(source) {
|
|
|
73
95
|
: undefined;
|
|
74
96
|
if (ts.isCallExpression(node) && callee) {
|
|
75
97
|
const title = stringOf(node.arguments[0]);
|
|
76
|
-
const
|
|
98
|
+
const { callback, reason } = callbackOf(node, callee.modifier);
|
|
99
|
+
const body = callbackBody(callback);
|
|
100
|
+
const mark = {
|
|
101
|
+
...(callee.modifier && { modifier: callee.modifier }),
|
|
102
|
+
...(reason !== undefined && { reason }),
|
|
103
|
+
};
|
|
77
104
|
if (title !== undefined && body && callee.name === "test") {
|
|
78
105
|
// `test.skip(condition, reason)` has no title and no body, so it stays a step of the test it is in
|
|
79
106
|
const titlePath = [...titles, title];
|
|
80
|
-
const modifier = effectiveModifier(callee.modifier, describes);
|
|
81
107
|
tests.push({
|
|
82
108
|
titlePath,
|
|
83
109
|
name: titlePath.join(" > "),
|
|
84
110
|
steps: body.statements.map((statement) => parseStatement(source, statement, sourceFile)),
|
|
85
111
|
bodyStart: body.getStart(sourceFile) + 1,
|
|
86
112
|
bodyEnd: body.end - 1,
|
|
87
|
-
fixtures: callbackFixtures(
|
|
88
|
-
...(
|
|
113
|
+
fixtures: callbackFixtures(callback, sourceFile),
|
|
114
|
+
...effectiveMark(mark, describes),
|
|
89
115
|
});
|
|
90
116
|
return;
|
|
91
117
|
}
|
|
92
118
|
if (title !== undefined && body && callee.name === "describe") {
|
|
93
|
-
ts.forEachChild(body, (child) => visit(child, [...titles, title], [...describes,
|
|
119
|
+
ts.forEachChild(body, (child) => visit(child, [...titles, title], [...describes, mark]));
|
|
94
120
|
return;
|
|
95
121
|
}
|
|
96
122
|
}
|
package/dist/types/test.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export type TestCase = TestCaseBase;
|
|
|
21
21
|
/** `skip`: not run. `fixme`: not run, known to be broken. `only`: the only test that runs when any is focused */
|
|
22
22
|
export type Modifier = "skip" | "fixme" | "only";
|
|
23
23
|
|
|
24
|
+
/** The optional second argument of `test.skip`, `test.fixme`, `describe.skip` and `describe.fixme` */
|
|
25
|
+
export interface TestDetails {
|
|
26
|
+
/** Why the tests are not run; shown in the report and by `samurai list` */
|
|
27
|
+
reason?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
/** Runs before or after each test of a suite, in the test's browser, with the test's fixtures */
|
|
25
31
|
export type EachHook = (fixtures: TestFixtures) => Promise<void> | void;
|
|
26
32
|
|
|
@@ -39,6 +45,8 @@ export interface Suite {
|
|
|
39
45
|
title?: string;
|
|
40
46
|
parent?: Suite;
|
|
41
47
|
modifier?: Modifier;
|
|
48
|
+
/** The `{ reason }` of a `describe.skip` or `describe.fixme` */
|
|
49
|
+
reason?: string;
|
|
42
50
|
beforeEach?: EachHook[];
|
|
43
51
|
afterEach?: EachHook[];
|
|
44
52
|
beforeAll?: AllHook[];
|
|
@@ -54,6 +62,8 @@ export interface RegisteredTestCase extends TestCaseBase {
|
|
|
54
62
|
suite: Suite;
|
|
55
63
|
/** What applies to the test: its own modifier, or the one of a suite around it */
|
|
56
64
|
modifier?: Modifier;
|
|
65
|
+
/** The reason given with the `skip` or `fixme` that applies */
|
|
66
|
+
reason?: string;
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
export interface TestCaseBase {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itmetsam/samurai-framework",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.2",
|
|
4
4
|
"description": "Browser test framework over WebDriver BiDi: auto-waiting locators, environments and secrets, a recorder, and a command line.",
|
|
5
5
|
"main": "dist/api.js",
|
|
6
6
|
"exports": {
|