@itmetsam/samurai-framework 0.21.5 → 0.22.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.
- package/dist/api.d.ts +8 -3
- package/dist/api.js +1 -0
- package/dist/browser/browser-context.d.ts +18 -6
- package/dist/browser/browser-context.js +25 -7
- package/dist/browser/browser.d.ts +4 -4
- package/dist/browser/browser.js +11 -8
- package/dist/browser/chrome-launch.js +9 -1
- package/dist/browser/context-cookie-store.d.ts +17 -0
- package/dist/browser/context-cookie-store.js +90 -0
- package/dist/browser/index.d.ts +3 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/keyboard.d.ts +35 -0
- package/dist/browser/keyboard.js +83 -0
- package/dist/browser/mouse.d.ts +42 -0
- package/dist/browser/mouse.js +66 -0
- package/dist/browser/page-content.d.ts +4 -0
- package/dist/browser/page-content.js +12 -0
- package/dist/browser/page-events.d.ts +11 -0
- package/dist/browser/page-events.js +23 -0
- package/dist/browser/page-logging.d.ts +24 -0
- package/dist/browser/page-logging.js +43 -0
- package/dist/browser/page-navigation.d.ts +0 -2
- package/dist/browser/page-navigation.js +1 -6
- package/dist/browser/page-settings.d.ts +1 -1
- package/dist/browser/page-viewport.d.ts +21 -0
- package/dist/browser/page-viewport.js +33 -0
- package/dist/browser/page.d.ts +23 -16
- package/dist/browser/page.js +48 -71
- package/dist/browser/screenshot.d.ts +6 -0
- package/dist/browser/screenshot.js +14 -0
- package/dist/browser/storage-state.d.ts +0 -2
- package/dist/browser/storage-state.js +0 -20
- package/dist/browser/use-applier.d.ts +16 -5
- package/dist/browser/use-applier.js +44 -17
- package/dist/browser/use-commands.d.ts +36 -0
- package/dist/browser/use-commands.js +120 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +8 -5
- package/dist/cli/console-reporter.js +5 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +4 -1
- package/dist/config/base-url.d.ts +4 -0
- package/dist/config/base-url.js +6 -0
- package/dist/config/config.js +7 -0
- package/dist/config/fixture-use.d.ts +19 -0
- package/dist/config/fixture-use.js +44 -0
- package/dist/config/fully-parallel.d.ts +3 -0
- package/dist/config/fully-parallel.js +6 -0
- package/dist/config/group-use.d.ts +10 -0
- package/dist/config/group-use.js +51 -0
- package/dist/config/resolved-config.d.ts +2 -0
- package/dist/config/resolved-config.js +3 -0
- package/dist/config/storage-state-file.d.ts +3 -0
- package/dist/config/storage-state-file.js +20 -0
- package/dist/config/use-options.d.ts +3 -1
- package/dist/config/use-options.js +74 -14
- package/dist/config/web-server-options.d.ts +7 -0
- package/dist/config/web-server-options.js +111 -0
- package/dist/locator/check-actions.js +1 -1
- package/dist/locator/drag-actions.d.ts +17 -0
- package/dist/locator/drag-actions.js +80 -0
- package/dist/locator/element-actions.d.ts +10 -4
- package/dist/locator/element-actions.js +23 -16
- package/dist/locator/element-state.d.ts +5 -0
- package/dist/locator/element-state.js +2 -1
- package/dist/locator/event-actions.d.ts +10 -0
- package/dist/locator/event-actions.js +81 -0
- package/dist/locator/input-actions.d.ts +2 -11
- package/dist/locator/input-actions.js +3 -56
- package/dist/locator/key-actions.d.ts +11 -0
- package/dist/locator/key-actions.js +52 -0
- package/dist/locator/key-map.d.ts +16 -0
- package/dist/locator/key-map.js +76 -0
- package/dist/locator/locator.d.ts +35 -5
- package/dist/locator/locator.js +70 -16
- package/dist/locator/page-scripts.d.ts +2 -0
- package/dist/locator/page-scripts.js +7 -0
- package/dist/locator/pointer-actions.d.ts +44 -0
- package/dist/locator/pointer-actions.js +117 -0
- package/dist/locator/pointer-element-actions.d.ts +21 -0
- package/dist/locator/pointer-element-actions.js +42 -0
- package/dist/request/api-request-context.d.ts +65 -0
- package/dist/request/api-request-context.js +198 -0
- package/dist/request/api-response.d.ts +34 -0
- package/dist/request/api-response.js +57 -0
- package/dist/request/cookie-jar.d.ts +48 -0
- package/dist/request/cookie-jar.js +164 -0
- package/dist/request/http-transport.d.ts +31 -0
- package/dist/request/http-transport.js +113 -0
- package/dist/request/redirect.d.ts +10 -0
- package/dist/request/redirect.js +21 -0
- package/dist/request/request-body.d.ts +27 -0
- package/dist/request/request-body.js +71 -0
- package/dist/request/request.d.ts +16 -0
- package/dist/request/request.js +20 -0
- package/dist/runner/all-hooks.d.ts +7 -1
- package/dist/runner/all-hooks.js +17 -1
- package/dist/runner/fixture-defs.d.ts +2 -1
- package/dist/runner/fixture-defs.js +52 -18
- package/dist/runner/fixture-meta.d.ts +20 -0
- package/dist/runner/fixture-meta.js +109 -0
- package/dist/runner/fixture-options.d.ts +8 -0
- package/dist/runner/fixture-options.js +35 -0
- package/dist/runner/fixture-outputs.d.ts +11 -0
- package/dist/runner/fixture-outputs.js +28 -0
- package/dist/runner/fixture-registry.d.ts +35 -0
- package/dist/runner/fixture-registry.js +73 -0
- package/dist/runner/fixture-scope.d.ts +39 -9
- package/dist/runner/fixture-scope.js +139 -70
- package/dist/runner/fixture-start.d.ts +27 -0
- package/dist/runner/fixture-start.js +76 -0
- package/dist/runner/fixture-use.d.ts +23 -0
- package/dist/runner/fixture-use.js +64 -0
- package/dist/runner/fixture-worker.d.ts +26 -0
- package/dist/runner/fixture-worker.js +46 -0
- package/dist/runner/fixtures.d.ts +4 -1
- package/dist/runner/fixtures.js +3 -2
- package/dist/runner/global-hooks.d.ts +13 -0
- package/dist/runner/global-hooks.js +66 -0
- package/dist/runner/options.d.ts +13 -2
- package/dist/runner/output-tail.d.ts +14 -0
- package/dist/runner/output-tail.js +30 -0
- package/dist/runner/pool-schedule.d.ts +22 -0
- package/dist/runner/pool-schedule.js +55 -0
- package/dist/runner/pool-units.d.ts +34 -0
- package/dist/runner/pool-units.js +85 -0
- package/dist/runner/pooled-run.d.ts +7 -5
- package/dist/runner/pooled-run.js +19 -9
- package/dist/runner/prepare-run.js +5 -0
- package/dist/runner/registry.js +21 -7
- package/dist/runner/reporter.d.ts +13 -1
- package/dist/runner/reporter.js +13 -2
- package/dist/runner/request-fixture.d.ts +14 -0
- package/dist/runner/request-fixture.js +25 -0
- package/dist/runner/run-hooks.d.ts +16 -0
- package/dist/runner/run-hooks.js +52 -0
- package/dist/runner/run-test.d.ts +3 -0
- package/dist/runner/run-test.js +23 -3
- package/dist/runner/run.d.ts +8 -0
- package/dist/runner/run.js +10 -0
- package/dist/runner/select.d.ts +15 -4
- package/dist/runner/select.js +38 -12
- package/dist/runner/serial-run.d.ts +23 -0
- package/dist/runner/serial-run.js +88 -0
- package/dist/runner/serial.d.ts +34 -0
- package/dist/runner/serial.js +63 -0
- package/dist/runner/shard.d.ts +22 -0
- package/dist/runner/shard.js +73 -0
- package/dist/runner/suite.d.ts +3 -3
- package/dist/runner/suite.js +4 -3
- package/dist/runner/test-function.d.ts +15 -3
- package/dist/runner/test-info.js +2 -1
- package/dist/runner/test-runner.d.ts +1 -0
- package/dist/runner/test-runner.js +67 -18
- package/dist/runner/use-options.d.ts +18 -4
- package/dist/runner/use-options.js +33 -6
- package/dist/runner/wait-for-url.d.ts +20 -0
- package/dist/runner/wait-for-url.js +65 -0
- package/dist/runner/web-server.d.ts +16 -0
- package/dist/runner/web-server.js +165 -0
- package/dist/runner/worker-pool.d.ts +13 -5
- package/dist/runner/worker-pool.js +85 -51
- package/dist/runner/worker-protocol.d.ts +8 -0
- package/dist/runner/worker-session.js +9 -1
- package/dist/runner/worker.d.ts +2 -0
- package/dist/runner/worker.js +7 -1
- package/dist/types/config.d.ts +117 -21
- package/dist/types/extend.d.ts +54 -2
- package/dist/types/test.d.ts +42 -0
- package/dist/types/use.d.ts +59 -7
- package/package.json +1 -1
- package/dist/browser/emulation.d.ts +0 -61
- package/dist/browser/emulation.js +0 -180
|
@@ -2,11 +2,16 @@ import { isShortSecret, registerSecret } from "../config/mask.js";
|
|
|
2
2
|
import { resolveRunSettings, setRunSettings, } from "../config/run-settings.js";
|
|
3
3
|
import { loadSecrets } from "../config/secrets.js";
|
|
4
4
|
import logger from "../logger/index.js";
|
|
5
|
+
import { fixtureCatalog } from "./fixture-registry.js";
|
|
6
|
+
import { checkFixtureUseNames } from "./fixture-use.js";
|
|
5
7
|
/**
|
|
6
8
|
* Starts a run: picks the environment, loads its secrets and registers every value for masking
|
|
7
9
|
* (all of them, not only the ones a test reads), then makes the settings active.
|
|
8
10
|
*/
|
|
9
11
|
export function prepareRun(config, overrides, options = {}) {
|
|
12
|
+
// A fixture name defined twice refuses the run before any test starts
|
|
13
|
+
const catalog = fixtureCatalog(config.fixtures ?? []);
|
|
14
|
+
checkFixtureUseNames(config, catalog);
|
|
10
15
|
const settings = resolveRunSettings(config, overrides);
|
|
11
16
|
const secrets = loadSecrets(settings.environment, options);
|
|
12
17
|
for (const [name, value] of secrets) {
|
package/dist/runner/registry.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import logger from "../logger/index.js";
|
|
3
3
|
import { extendLayers } from "./fixture-defs.js";
|
|
4
|
+
import { rememberLayers } from "./fixture-registry.js";
|
|
5
|
+
import { checkTestFixtureUse } from "./fixture-use.js";
|
|
4
6
|
import { validateUseOptions } from "../config/use-options.js";
|
|
5
7
|
import { currentStepLog, currentTestInfo, infoFor, skipFromCondition, } from "./test-info.js";
|
|
6
8
|
import { runStep } from "./steps.js";
|
|
7
9
|
import { markTests } from "./test-annotations.js";
|
|
8
10
|
import { validateTestIO } from "./test-io.js";
|
|
9
11
|
import { addHook, addUse, currentSuite, enterSuite, leaveSuite, modifierOf, resetSuites, } from "./suite.js";
|
|
12
|
+
import { configureSuite } from "./serial.js";
|
|
10
13
|
const registered = [];
|
|
11
14
|
/** Runs `fn` as the `describe` block `title`, under `modifier` when there is one. `fn` runs immediately and must be synchronous. */
|
|
12
|
-
function openDescribe(file, title, fn, modifier, reason) {
|
|
13
|
-
enterSuite(file, title, modifier, reason);
|
|
15
|
+
function openDescribe(file, title, fn, modifier, reason, mode) {
|
|
16
|
+
enterSuite(file, title, modifier, reason, mode);
|
|
14
17
|
try {
|
|
15
18
|
const result = fn();
|
|
16
19
|
if (result instanceof Promise) {
|
|
@@ -129,6 +132,9 @@ export const describe = Object.assign((title, fn) => openDescribe(callerFile(),
|
|
|
129
132
|
skip: describeSkipping("skip"),
|
|
130
133
|
fixme: describeSkipping("fixme"),
|
|
131
134
|
only: (title, fn) => openDescribe(callerFile(), title, fn, "only"),
|
|
135
|
+
configure: (options) => configureSuite(currentSuite(callerFile()), options),
|
|
136
|
+
serial: (title, fn) => openDescribe(callerFile(), title, fn, undefined, undefined, "serial"),
|
|
137
|
+
parallel: (title, fn) => openDescribe(callerFile(), title, fn, undefined, undefined, "parallel"),
|
|
132
138
|
});
|
|
133
139
|
/** Runs before each test of the `describe` block it is written in (of the file, at the top level) */
|
|
134
140
|
export function beforeEach(hook) {
|
|
@@ -146,16 +152,21 @@ export function beforeAll(hook) {
|
|
|
146
152
|
export function afterAll(hook) {
|
|
147
153
|
addHook(currentSuite(callerFile()), "afterAll", hook);
|
|
148
154
|
}
|
|
149
|
-
/** `test.use(options)`: checked now, applied when each test of the scope runs */
|
|
150
|
-
function
|
|
151
|
-
|
|
155
|
+
/** `test.use(options)` of a test with the fixtures `extension`: checked now, applied when each test of the scope runs */
|
|
156
|
+
function usingFor(extension) {
|
|
157
|
+
return (options) => {
|
|
158
|
+
const checked = validateUseOptions(options);
|
|
159
|
+
// `fixtures` and option fixtures may only name what this test's `test.extend()` defines
|
|
160
|
+
checkTestFixtureUse(checked, extension);
|
|
161
|
+
addUse(currentSuite(callerFile()), checked);
|
|
162
|
+
};
|
|
152
163
|
}
|
|
153
164
|
/**
|
|
154
165
|
* A `test` that registers its tests with the custom fixtures `extension`. The aliases are the same functions as
|
|
155
166
|
* the named exports: they find the spec file from the stack, so they must not be wrapped.
|
|
156
167
|
*/
|
|
157
168
|
function makeTest(extension) {
|
|
158
|
-
|
|
169
|
+
const made = Object.assign(registering("test", undefined, extension), {
|
|
159
170
|
skip: skipping("skip", extension),
|
|
160
171
|
fixme: skipping("fixme", extension),
|
|
161
172
|
fail: failing(extension),
|
|
@@ -164,7 +175,7 @@ function makeTest(extension) {
|
|
|
164
175
|
step: (title, body, options) => runStep(currentStepLog(), title, body, options),
|
|
165
176
|
only: registering("test.only", "only", extension),
|
|
166
177
|
info: currentTestInfo,
|
|
167
|
-
use,
|
|
178
|
+
use: usingFor(extension),
|
|
168
179
|
describe,
|
|
169
180
|
beforeEach,
|
|
170
181
|
afterEach,
|
|
@@ -172,6 +183,9 @@ function makeTest(extension) {
|
|
|
172
183
|
afterAll,
|
|
173
184
|
extend: (fixtures) => makeTest(extendLayers(extension, fixtures)),
|
|
174
185
|
});
|
|
186
|
+
if (extension)
|
|
187
|
+
rememberLayers(made, extension);
|
|
188
|
+
return made;
|
|
175
189
|
}
|
|
176
190
|
export const test = makeTest();
|
|
177
191
|
export function registeredTests() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { TestAnnotation, TestStepEntry, TestAttachmentEntry, RegisteredTestCase, TestError, TestLogEntry, TestResult, TestRetries, TestSummary } from "../types/test.js";
|
|
1
|
+
import type { TestAnnotation, TestFixtureEntry, TestStepEntry, TestAttachmentEntry, RegisteredTestCase, TestError, TestLogEntry, TestResult, TestRetries, TestSummary } from "../types/test.js";
|
|
2
2
|
import type { SupportedBrowser } from "../types/browser.js";
|
|
3
|
+
import type { Shard } from "./shard.js";
|
|
3
4
|
/** What a run reports while it happens */
|
|
4
5
|
export type RunEvent = {
|
|
5
6
|
type: "run-start";
|
|
@@ -9,11 +10,15 @@ export type RunEvent = {
|
|
|
9
10
|
browsers: SupportedBrowser[];
|
|
10
11
|
/** How many tests run at the same time; absent when they run one after the other */
|
|
11
12
|
workers?: number;
|
|
13
|
+
/** The slice of the selected tests this run holds, when it is a shard */
|
|
14
|
+
shard?: Shard;
|
|
12
15
|
} | {
|
|
13
16
|
type: "test-start";
|
|
14
17
|
name: string;
|
|
15
18
|
file: string;
|
|
16
19
|
browser: SupportedBrowser;
|
|
20
|
+
/** The group the test runs for, when the run selected groups; absent otherwise */
|
|
21
|
+
group?: string;
|
|
17
22
|
/** The attempt, counting from 1, when the test is run again after a failure; absent for the first */
|
|
18
23
|
retry?: number;
|
|
19
24
|
} | {
|
|
@@ -21,6 +26,8 @@ export type RunEvent = {
|
|
|
21
26
|
name: string;
|
|
22
27
|
file: string;
|
|
23
28
|
browser: SupportedBrowser;
|
|
29
|
+
/** The group the test ran for, when the run selected groups; absent otherwise */
|
|
30
|
+
group?: string;
|
|
24
31
|
result: TestResult;
|
|
25
32
|
} | {
|
|
26
33
|
type: "run-end";
|
|
@@ -33,6 +40,8 @@ export interface ReporterOptions {
|
|
|
33
40
|
browsers: SupportedBrowser[];
|
|
34
41
|
/** Where the report is written. @default <cwd>/result/report.json */
|
|
35
42
|
output?: string | false;
|
|
43
|
+
/** The slice of the selected tests this run holds; recorded in the report */
|
|
44
|
+
shard?: Shard;
|
|
36
45
|
/** Called with every event, in order. A throwing listener is ignored */
|
|
37
46
|
onEvent?: (event: RunEvent) => void;
|
|
38
47
|
}
|
|
@@ -66,6 +75,8 @@ export interface TestEndExtras extends TestRetries {
|
|
|
66
75
|
annotations?: TestAnnotation[];
|
|
67
76
|
/** The steps the test ran with `test.step` */
|
|
68
77
|
steps?: TestStepEntry[];
|
|
78
|
+
/** The fixtures the test set up, when it set any up */
|
|
79
|
+
fixtures?: TestFixtureEntry[];
|
|
69
80
|
}
|
|
70
81
|
export default class TestReporter implements TestSink {
|
|
71
82
|
private testResults;
|
|
@@ -74,6 +85,7 @@ export default class TestReporter implements TestSink {
|
|
|
74
85
|
private browsers;
|
|
75
86
|
private output;
|
|
76
87
|
private listener;
|
|
88
|
+
private shard;
|
|
77
89
|
/** Keys of the run's tests in the order the report lists them; unset: the order they started in */
|
|
78
90
|
private order;
|
|
79
91
|
constructor(options: ReporterOptions);
|
package/dist/runner/reporter.js
CHANGED
|
@@ -2,10 +2,12 @@ import { mkdir, writeFile } from "fs/promises";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { projectDir } from "../config/config.js";
|
|
4
4
|
import { maskDeep } from "../config/mask.js";
|
|
5
|
-
/** Results are keyed by file, full title and
|
|
5
|
+
/** Results are keyed by file, full title, browser and group, so equal titles in different files or describe blocks, and the same test in two browsers or for two groups, stay apart */
|
|
6
6
|
function keyOf(test, browser) {
|
|
7
|
-
return `${test.file}::${test.name}::${browser}`;
|
|
7
|
+
return `${test.file}::${test.name}::${browser}${test.group === undefined ? "" : `::${test.group}`}`;
|
|
8
8
|
}
|
|
9
|
+
/** The `group` of a test's report entry and events: nothing when no group was selected */
|
|
10
|
+
const groupOf = (test) => test.group === undefined ? {} : { group: test.group };
|
|
9
11
|
export default class TestReporter {
|
|
10
12
|
constructor(options) {
|
|
11
13
|
this.testResults = new Map();
|
|
@@ -14,6 +16,7 @@ export default class TestReporter {
|
|
|
14
16
|
this.output =
|
|
15
17
|
options.output ?? path.join(projectDir(), "result/report.json");
|
|
16
18
|
this.listener = options.onEvent;
|
|
19
|
+
this.shard = options.shard;
|
|
17
20
|
}
|
|
18
21
|
emit(event) {
|
|
19
22
|
try {
|
|
@@ -43,6 +46,7 @@ export default class TestReporter {
|
|
|
43
46
|
total,
|
|
44
47
|
browsers: this.browsers,
|
|
45
48
|
...(workers > 1 && { workers }),
|
|
49
|
+
...(this.shard && { shard: this.shard }),
|
|
46
50
|
});
|
|
47
51
|
}
|
|
48
52
|
async onEnd() {
|
|
@@ -61,6 +65,7 @@ export default class TestReporter {
|
|
|
61
65
|
duration,
|
|
62
66
|
environment: this.environment,
|
|
63
67
|
browsers: this.browsers,
|
|
68
|
+
...(this.shard && { shard: this.shard }),
|
|
64
69
|
tests,
|
|
65
70
|
status: tests.every((r) => r.status === "success" || r.status === "skipped")
|
|
66
71
|
? "success"
|
|
@@ -82,6 +87,7 @@ export default class TestReporter {
|
|
|
82
87
|
name: test.name,
|
|
83
88
|
file: test.file,
|
|
84
89
|
browser,
|
|
90
|
+
...groupOf(test),
|
|
85
91
|
status: "started",
|
|
86
92
|
startTime: t.startTime,
|
|
87
93
|
});
|
|
@@ -90,6 +96,7 @@ export default class TestReporter {
|
|
|
90
96
|
name: test.name,
|
|
91
97
|
file: test.file,
|
|
92
98
|
browser,
|
|
99
|
+
...groupOf(test),
|
|
93
100
|
...(retry ? { retry } : {}),
|
|
94
101
|
});
|
|
95
102
|
}
|
|
@@ -111,6 +118,7 @@ export default class TestReporter {
|
|
|
111
118
|
name: test.name,
|
|
112
119
|
file: test.file,
|
|
113
120
|
browser,
|
|
121
|
+
...groupOf(test),
|
|
114
122
|
result,
|
|
115
123
|
});
|
|
116
124
|
}
|
|
@@ -131,6 +139,7 @@ export default class TestReporter {
|
|
|
131
139
|
name: test.name,
|
|
132
140
|
file: test.file,
|
|
133
141
|
browser,
|
|
142
|
+
...groupOf(test),
|
|
134
143
|
result: ended,
|
|
135
144
|
});
|
|
136
145
|
}
|
|
@@ -151,6 +160,7 @@ export default class TestReporter {
|
|
|
151
160
|
...(extras?.attachments && { attachments: extras.attachments }),
|
|
152
161
|
...(extras?.annotations && { annotations: extras.annotations }),
|
|
153
162
|
...(extras?.steps && { steps: extras.steps }),
|
|
163
|
+
...(extras?.fixtures?.length && { fixtures: extras.fixtures }),
|
|
154
164
|
...(extras?.retry && { retry: extras.retry }),
|
|
155
165
|
...(extras?.flaky && { flaky: true }),
|
|
156
166
|
...(extras?.previousAttempts?.length && {
|
|
@@ -163,6 +173,7 @@ export default class TestReporter {
|
|
|
163
173
|
name: test.name,
|
|
164
174
|
file: test.file,
|
|
165
175
|
browser,
|
|
176
|
+
...groupOf(test),
|
|
166
177
|
result,
|
|
167
178
|
});
|
|
168
179
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { APIRequestContext } from "../request/api-request-context.js";
|
|
2
|
+
import type { UseOptions } from "../types/use.js";
|
|
3
|
+
/**
|
|
4
|
+
* The `request` fixture of one test: an `APIRequestContext` of its own (its own cookies), made when the test first
|
|
5
|
+
* reads it, from the run's `baseURL` and the `use` options, and disposed when the test is over
|
|
6
|
+
*/
|
|
7
|
+
export declare class RequestFixture {
|
|
8
|
+
private readonly baseURL;
|
|
9
|
+
private readonly use;
|
|
10
|
+
private context;
|
|
11
|
+
constructor(baseURL: string | undefined, use: UseOptions);
|
|
12
|
+
get(): APIRequestContext;
|
|
13
|
+
dispose(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createRequestContext } from "../request/request.js";
|
|
2
|
+
/**
|
|
3
|
+
* The `request` fixture of one test: an `APIRequestContext` of its own (its own cookies), made when the test first
|
|
4
|
+
* reads it, from the run's `baseURL` and the `use` options, and disposed when the test is over
|
|
5
|
+
*/
|
|
6
|
+
export class RequestFixture {
|
|
7
|
+
constructor(baseURL, use) {
|
|
8
|
+
this.baseURL = baseURL;
|
|
9
|
+
this.use = use;
|
|
10
|
+
}
|
|
11
|
+
get() {
|
|
12
|
+
const { use } = this;
|
|
13
|
+
return (this.context ??= createRequestContext({
|
|
14
|
+
baseURL: this.baseURL,
|
|
15
|
+
extraHTTPHeaders: use.extraHTTPHeaders,
|
|
16
|
+
ignoreHTTPSErrors: use.acceptInsecureCerts,
|
|
17
|
+
...(use.storageState !== undefined && {
|
|
18
|
+
storageState: use.storageState,
|
|
19
|
+
}),
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
async dispose() {
|
|
23
|
+
await this.context?.dispose();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RunSettings } from "../config/run-settings.js";
|
|
2
|
+
import type { SamuraiTestConfig } from "../types/config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Runs `work` between the config's run-level steps: web servers start, then `globalSetup`, then `work`, then
|
|
5
|
+
* `globalTeardown`, then the servers stop. The teardown runs when the work or the setup throws (not when a server
|
|
6
|
+
* failed to start, since nothing was set up), and the servers are stopped whatever happens. When the config has no
|
|
7
|
+
* `baseURL` for the run, the first server's address becomes `settings.baseURL`.
|
|
8
|
+
* Errors: a failed start is `webServer(): ...`, a failed setup `globalSetup(): ...`; the work's own error wins over
|
|
9
|
+
* a teardown error, which is logged then.
|
|
10
|
+
*/
|
|
11
|
+
export declare function withRunHooks<T>(run: {
|
|
12
|
+
config: SamuraiTestConfig;
|
|
13
|
+
settings: RunSettings;
|
|
14
|
+
projectDir: string;
|
|
15
|
+
signal?: AbortSignal | undefined;
|
|
16
|
+
}, work: () => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolveConfig } from "../config/resolved-config.js";
|
|
2
|
+
import { webServersOf } from "../config/web-server-options.js";
|
|
3
|
+
import logger from "../logger/index.js";
|
|
4
|
+
import { globalHooks } from "./global-hooks.js";
|
|
5
|
+
import { startWebServers } from "./web-server.js";
|
|
6
|
+
/**
|
|
7
|
+
* Runs `work` between the config's run-level steps: web servers start, then `globalSetup`, then `work`, then
|
|
8
|
+
* `globalTeardown`, then the servers stop. The teardown runs when the work or the setup throws (not when a server
|
|
9
|
+
* failed to start, since nothing was set up), and the servers are stopped whatever happens. When the config has no
|
|
10
|
+
* `baseURL` for the run, the first server's address becomes `settings.baseURL`.
|
|
11
|
+
* Errors: a failed start is `webServer(): ...`, a failed setup `globalSetup(): ...`; the work's own error wins over
|
|
12
|
+
* a teardown error, which is logged then.
|
|
13
|
+
*/
|
|
14
|
+
export async function withRunHooks(run, work) {
|
|
15
|
+
const { config, settings, projectDir, signal } = run;
|
|
16
|
+
const servers = webServersOf(config);
|
|
17
|
+
if (servers.length === 0 &&
|
|
18
|
+
config.globalSetup === undefined &&
|
|
19
|
+
config.globalTeardown === undefined)
|
|
20
|
+
return work();
|
|
21
|
+
const running = await startWebServers(servers, { projectDir, signal });
|
|
22
|
+
let outcome;
|
|
23
|
+
try {
|
|
24
|
+
if (settings.baseURL === undefined && running.baseURL !== undefined)
|
|
25
|
+
settings.baseURL = running.baseURL;
|
|
26
|
+
const hooks = globalHooks(config, {
|
|
27
|
+
...resolveConfig(config, { projectDir, env: process.env }),
|
|
28
|
+
environment: settings.environment,
|
|
29
|
+
...(settings.baseURL !== undefined && { baseURL: settings.baseURL }),
|
|
30
|
+
}, projectDir);
|
|
31
|
+
try {
|
|
32
|
+
await hooks.setup();
|
|
33
|
+
outcome = { value: await work() };
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
outcome = { error };
|
|
37
|
+
}
|
|
38
|
+
const teardownError = await hooks.teardown();
|
|
39
|
+
if (teardownError) {
|
|
40
|
+
if ("error" in outcome)
|
|
41
|
+
logger.error("%s", teardownError.message);
|
|
42
|
+
else
|
|
43
|
+
outcome = { error: teardownError };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await running.stop();
|
|
48
|
+
}
|
|
49
|
+
if (outcome && "error" in outcome)
|
|
50
|
+
throw outcome.error;
|
|
51
|
+
return outcome.value;
|
|
52
|
+
}
|
|
@@ -4,6 +4,7 @@ import type { RunnerOptions } from "./options.js";
|
|
|
4
4
|
import type { AllHooks } from "./all-hooks.js";
|
|
5
5
|
import type { PreparedRun } from "./prepare-run.js";
|
|
6
6
|
import type { TestSink } from "./reporter.js";
|
|
7
|
+
import type { WorkerFixtures } from "./fixture-worker.js";
|
|
7
8
|
/** What a worker gives its tests that the main process does not: its own port and profile, and its number */
|
|
8
9
|
export interface WorkerResources {
|
|
9
10
|
/** The browser's debugging port. @default `options.port`, else DEFAULT_PORT */
|
|
@@ -16,6 +17,8 @@ export interface WorkerResources {
|
|
|
16
17
|
attempt?: number;
|
|
17
18
|
/** The `beforeAll` / `afterAll` hooks of this worker: kept across tests, closed when the worker is done */
|
|
18
19
|
allHooks?: AllHooks;
|
|
20
|
+
/** The worker-scoped fixtures of this worker: kept across tests, closed when the worker is done */
|
|
21
|
+
workerFixtures?: WorkerFixtures;
|
|
19
22
|
}
|
|
20
23
|
/** Runs one test in one browser and reports it: launch, run the body, judge the page's logs, close the browser */
|
|
21
24
|
export declare function runOneTest(test: RegisteredTestCase, browserName: SupportedBrowser, run: PreparedRun, options: RunnerOptions, srcDir: string, reporter: TestSink, resources?: WorkerResources): Promise<void>;
|
package/dist/runner/run-test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { takePendingAssertions } from "../assert/expect.js";
|
|
3
3
|
import { Browser } from "../browser/browser.js";
|
|
4
|
-
import { Evidence } from "../browser/evidence.js";
|
|
4
|
+
import { cleanName, Evidence } from "../browser/evidence.js";
|
|
5
5
|
import { projectDir, readConfig } from "../config/config.js";
|
|
6
6
|
import logger from "../logger/index.js";
|
|
7
7
|
import { ConnectionClosedError } from "../transport/bidi-connection.js";
|
|
@@ -18,7 +18,9 @@ import { TestTimeout } from "./test-timeout.js";
|
|
|
18
18
|
import { ioOfAttempt, missingOutputs } from "./test-io.js";
|
|
19
19
|
import { buildTestFixtures } from "./fixtures.js";
|
|
20
20
|
import { FixtureScope } from "./fixture-scope.js";
|
|
21
|
+
import { RequestFixture } from "./request-fixture.js";
|
|
21
22
|
import { effectiveUse } from "./use-options.js";
|
|
23
|
+
import { effectiveFixtureUse } from "./fixture-use.js";
|
|
22
24
|
import { beginOutputs, endOutputs } from "../wait/output-sink.js";
|
|
23
25
|
/**
|
|
24
26
|
* The state of one test run. A test ends once, whichever of finishing, failing, timing out, an abort or a
|
|
@@ -37,6 +39,8 @@ class TestOutcome {
|
|
|
37
39
|
this.browserClosed = false;
|
|
38
40
|
/** The test's inputs and outputs, as its report entry lists them when it ends */
|
|
39
41
|
this.io = () => ({});
|
|
42
|
+
/** The fixtures the test set up, as they stand when it ends */
|
|
43
|
+
this.fixtures = () => [];
|
|
40
44
|
}
|
|
41
45
|
get isEnded() {
|
|
42
46
|
return this.ended;
|
|
@@ -64,6 +68,7 @@ class TestOutcome {
|
|
|
64
68
|
screenshots: this.evidence?.screenshots,
|
|
65
69
|
...this.info?.reportExtras(),
|
|
66
70
|
...this.io(),
|
|
71
|
+
fixtures: this.fixtures(),
|
|
67
72
|
});
|
|
68
73
|
}
|
|
69
74
|
}
|
|
@@ -84,6 +89,7 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
84
89
|
let browser;
|
|
85
90
|
let page;
|
|
86
91
|
let customFixtures;
|
|
92
|
+
let requestFixture;
|
|
87
93
|
let onRunAborted;
|
|
88
94
|
const timeoutController = new AbortController();
|
|
89
95
|
let browserGone = () => { };
|
|
@@ -117,6 +123,9 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
117
123
|
// The `beforeAll` hooks come first, before a browser exists
|
|
118
124
|
await resources.allHooks?.ensure(test, browserName);
|
|
119
125
|
const use = await effectiveUse(test);
|
|
126
|
+
const fixtureUse = test.extension
|
|
127
|
+
? await effectiveFixtureUse(test)
|
|
128
|
+
: undefined;
|
|
120
129
|
const launched = await Browser.launch(browserName, {
|
|
121
130
|
port: resources.port ?? options.port ?? DEFAULT_PORT,
|
|
122
131
|
...(resources.profileDir && { profileDir: resources.profileDir }),
|
|
@@ -142,7 +151,7 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
142
151
|
const applied = Object.keys(use).length > 0
|
|
143
152
|
? await launched.browser.setUse(use, projectDir())
|
|
144
153
|
: undefined;
|
|
145
|
-
const testFolder = `${browserName}/${testDirOf(test, srcDir)}${resources.attempt ? `/retry-${resources.attempt}` : ""}`;
|
|
154
|
+
const testFolder = `${browserName}${test.group === undefined ? "" : `/${cleanName(test.group)}`}/${testDirOf(test, srcDir)}${resources.attempt ? `/retry-${resources.attempt}` : ""}`;
|
|
146
155
|
outcome.evidence = new Evidence(resultDir, testFolder);
|
|
147
156
|
launched.page.setEvidence(outcome.evidence);
|
|
148
157
|
const info = new TestInfoImpl({
|
|
@@ -157,7 +166,9 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
157
166
|
});
|
|
158
167
|
outcome.info = info;
|
|
159
168
|
applyDeclaredMarks(info, test);
|
|
169
|
+
requestFixture = new RequestFixture(settings.baseURL, use);
|
|
160
170
|
const built = buildTestFixtures({
|
|
171
|
+
request: requestFixture,
|
|
161
172
|
info,
|
|
162
173
|
launched,
|
|
163
174
|
browserName,
|
|
@@ -173,9 +184,17 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
173
184
|
});
|
|
174
185
|
// A test written with `test.extend()` gets its custom fixtures set up on demand, and torn down below
|
|
175
186
|
const custom = test.extension
|
|
176
|
-
? new FixtureScope(test.extension, built
|
|
187
|
+
? new FixtureScope(test.extension, built, {
|
|
188
|
+
...fixtureUse,
|
|
189
|
+
environment: settings.environment,
|
|
190
|
+
...(resources.workerFixtures && {
|
|
191
|
+
workers: resources.workerFixtures,
|
|
192
|
+
}),
|
|
193
|
+
})
|
|
177
194
|
: undefined;
|
|
178
195
|
customFixtures = custom;
|
|
196
|
+
if (custom)
|
|
197
|
+
outcome.fixtures = () => custom.report();
|
|
179
198
|
const fixtures = custom?.fixtures ?? built;
|
|
180
199
|
let failure;
|
|
181
200
|
let failed = false;
|
|
@@ -246,6 +265,7 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
246
265
|
const late = await customFixtures?.teardown(timeout);
|
|
247
266
|
if (late)
|
|
248
267
|
logger.debug("A fixture failed after the test ended", { late });
|
|
268
|
+
await requestFixture?.dispose();
|
|
249
269
|
endOutputs();
|
|
250
270
|
}
|
|
251
271
|
testTimeout?.stop();
|
package/dist/runner/run.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Modifier, TestSummary } from "../types/test.js";
|
|
2
2
|
import { type ProjectOptions } from "./project.js";
|
|
3
3
|
import { type ResolvedGroup } from "./groups.js";
|
|
4
|
+
import { type FixtureCatalogEntry } from "./fixture-registry.js";
|
|
4
5
|
import type { RunnerOptions } from "./options.js";
|
|
5
6
|
export interface RunTestsOptions extends RunnerOptions, ProjectOptions {
|
|
6
7
|
}
|
|
@@ -45,9 +46,16 @@ export interface FoundTest {
|
|
|
45
46
|
export declare function listTests(options?: RunTestsOptions): Promise<FoundTest[]>;
|
|
46
47
|
/** Imports the project's specs without running anything and lists the config's groups with the tests each holds */
|
|
47
48
|
export declare function listGroups(options?: RunTestsOptions): Promise<ResolvedGroup[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Lists the fixtures of the extended tests in the config's `fixtures`, with their label, icon, scope, option form
|
|
51
|
+
* and declared outputs, without running a test. Throws for a name defined twice or one that is not allowed.
|
|
52
|
+
*/
|
|
53
|
+
export declare function listFixtures(options?: ProjectOptions): Promise<FixtureCatalogEntry[]>;
|
|
54
|
+
export type { FixtureCatalogEntry } from "./fixture-registry.js";
|
|
48
55
|
export { BROWSER_NAMES, checkBrowserList } from "../config/browsers.js";
|
|
49
56
|
export { parseWorkers } from "../config/workers.js";
|
|
50
57
|
export { parseRetries } from "../config/retries.js";
|
|
58
|
+
export { parseShard, type Shard } from "./shard.js";
|
|
51
59
|
export type { RunEvent } from "./reporter.js";
|
|
52
60
|
export type { Modifier, TestError, TestResult, TestSummary, } from "../types/test.js";
|
|
53
61
|
export type { ResolvedGroup } from "./groups.js";
|
package/dist/runner/run.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { withProject } from "./project.js";
|
|
3
3
|
import { testId, toPosix } from "./groups.js";
|
|
4
|
+
import { projectConfig } from "../config/config.js";
|
|
5
|
+
import { fixtureCatalog, } from "./fixture-registry.js";
|
|
4
6
|
import TestRunner from "./test-runner.js";
|
|
5
7
|
/**
|
|
6
8
|
* Sets the project up (config, environment, secrets), builds a runner from the rest of the options and hands both to
|
|
@@ -67,7 +69,15 @@ export async function listTests(options = {}) {
|
|
|
67
69
|
export async function listGroups(options = {}) {
|
|
68
70
|
return inProject(options, (runner) => runner.groups());
|
|
69
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Lists the fixtures of the extended tests in the config's `fixtures`, with their label, icon, scope, option form
|
|
74
|
+
* and declared outputs, without running a test. Throws for a name defined twice or one that is not allowed.
|
|
75
|
+
*/
|
|
76
|
+
export async function listFixtures(options = {}) {
|
|
77
|
+
return fixtureCatalog((await projectConfig(options)).fixtures ?? []);
|
|
78
|
+
}
|
|
70
79
|
export { BROWSER_NAMES, checkBrowserList } from "../config/browsers.js";
|
|
71
80
|
export { parseWorkers } from "../config/workers.js";
|
|
72
81
|
export { parseRetries } from "../config/retries.js";
|
|
82
|
+
export { parseShard } from "./shard.js";
|
|
73
83
|
export { DEFAULT_PORT } from "./ports.js";
|
package/dist/runner/select.d.ts
CHANGED
|
@@ -15,10 +15,21 @@ export declare function isSelected(name: string, { grep, testNames }: Pick<Runne
|
|
|
15
15
|
export declare function idOf(test: RegisteredTestCase, srcDir: string): string;
|
|
16
16
|
/** Imports the spec files once and resolves the config's groups against what they registered */
|
|
17
17
|
export declare function loadSpecs(testFiles: string[]): Promise<LoadedSpecs>;
|
|
18
|
-
/** The
|
|
18
|
+
/** The group names the options select, once each and in the order given; none when no group is selected */
|
|
19
|
+
export declare function groupNamesOf(group: RunnerOptions["group"]): string[];
|
|
20
|
+
/** The tests the options select: by `group` (in any of them), `testNames` and `grep`; each test once */
|
|
19
21
|
export declare function selectTests({ all, groups, srcDir }: LoadedSpecs, options: RunnerOptions): RegisteredTestCase[];
|
|
20
22
|
/**
|
|
21
|
-
* The
|
|
22
|
-
*
|
|
23
|
+
* The runs of the selected tests: without a selected group, the tests as they are; else one copy per selected group
|
|
24
|
+
* that holds the test (its `group` set), the first group's tests first
|
|
23
25
|
*/
|
|
24
|
-
export declare function
|
|
26
|
+
export declare function expandByGroup(selected: RegisteredTestCase[], { groups, srcDir }: LoadedSpecs, options: RunnerOptions): RegisteredTestCase[];
|
|
27
|
+
/**
|
|
28
|
+
* The browsers a run of a test uses: the options' (`--browser`), else its group's, else the project's, else Firefox
|
|
29
|
+
*/
|
|
30
|
+
export declare function browserPlan(groups: ResolvedGroup[], options: RunnerOptions): Promise<{
|
|
31
|
+
/** Every browser of the run, in the order they run */
|
|
32
|
+
browsers: SupportedBrowser[];
|
|
33
|
+
/** The browsers one run of a test uses */
|
|
34
|
+
browsersOf(test: RegisteredTestCase): SupportedBrowser[];
|
|
35
|
+
}>;
|
package/dist/runner/select.js
CHANGED
|
@@ -53,25 +53,51 @@ export async function loadSpecs(testFiles) {
|
|
|
53
53
|
const all = await registerAll(testFiles);
|
|
54
54
|
return { all, ...(await resolveAll(all)) };
|
|
55
55
|
}
|
|
56
|
-
/** The
|
|
56
|
+
/** The group names the options select, once each and in the order given; none when no group is selected */
|
|
57
|
+
export function groupNamesOf(group) {
|
|
58
|
+
return [...new Set(group === undefined ? [] : [group].flat())];
|
|
59
|
+
}
|
|
60
|
+
/** The tests the options select: by `group` (in any of them), `testNames` and `grep`; each test once */
|
|
57
61
|
export function selectTests({ all, groups, srcDir }, options) {
|
|
58
|
-
const
|
|
62
|
+
const names = groupNamesOf(options.group);
|
|
59
63
|
let inGroup = () => true;
|
|
60
|
-
if (
|
|
61
|
-
const members = new Set(findGroup(groups,
|
|
64
|
+
if (names.length > 0) {
|
|
65
|
+
const members = new Set(names.flatMap((name) => findGroup(groups, name).testIds));
|
|
62
66
|
inGroup = (test) => members.has(idOf(test, srcDir));
|
|
63
67
|
}
|
|
64
68
|
return all.filter((test) => inGroup(test) && isSelected(test.name, options));
|
|
65
69
|
}
|
|
66
70
|
/**
|
|
67
|
-
* The
|
|
68
|
-
*
|
|
71
|
+
* The runs of the selected tests: without a selected group, the tests as they are; else one copy per selected group
|
|
72
|
+
* that holds the test (its `group` set), the first group's tests first
|
|
73
|
+
*/
|
|
74
|
+
export function expandByGroup(selected, { groups, srcDir }, options) {
|
|
75
|
+
const names = groupNamesOf(options.group);
|
|
76
|
+
if (names.length === 0)
|
|
77
|
+
return selected;
|
|
78
|
+
return names.flatMap((name) => {
|
|
79
|
+
const members = new Set(findGroup(groups, name).testIds);
|
|
80
|
+
return selected
|
|
81
|
+
.filter((test) => members.has(idOf(test, srcDir)))
|
|
82
|
+
.map((test) => ({ ...test, group: name }));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The browsers a run of a test uses: the options' (`--browser`), else its group's, else the project's, else Firefox
|
|
69
87
|
*/
|
|
70
|
-
export async function
|
|
71
|
-
const { browsers: flag
|
|
88
|
+
export async function browserPlan(groups, options) {
|
|
89
|
+
const { browsers: flag } = options;
|
|
72
90
|
const config = await loadRawConfig();
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
const names = groupNamesOf(options.group);
|
|
92
|
+
const flagged = flag && flag.length > 0;
|
|
93
|
+
const ofGroup = new Map(names.map((name) => [name, findGroup(groups, name).browsers]));
|
|
94
|
+
const project = browsersFor({ flag, project: config.browsers });
|
|
95
|
+
const forGroup = (name) => flagged ? project : (ofGroup.get(name) ?? project);
|
|
96
|
+
const browsers = [
|
|
97
|
+
...new Set(names.length > 0 ? names.flatMap(forGroup) : project),
|
|
98
|
+
];
|
|
99
|
+
return {
|
|
100
|
+
browsers,
|
|
101
|
+
browsersOf: (test) => test.group === undefined ? project : forGroup(test.group),
|
|
102
|
+
};
|
|
77
103
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SupportedBrowser } from "../types/browser.js";
|
|
2
|
+
import type { RegisteredTestCase } from "../types/test.js";
|
|
3
|
+
import type { TestSink } from "./reporter.js";
|
|
4
|
+
/** One attempt at one test of the block, reporting to `sink` */
|
|
5
|
+
export type BlockTest = (test: RegisteredTestCase, sink: TestSink, attempt: number) => Promise<void>;
|
|
6
|
+
export interface SerialBlockRun {
|
|
7
|
+
tests: RegisteredTestCase[];
|
|
8
|
+
browser: SupportedBrowser;
|
|
9
|
+
retries: number;
|
|
10
|
+
signal: AbortSignal | undefined;
|
|
11
|
+
runTest: BlockTest;
|
|
12
|
+
/** Called before the block starts again after a failure: closes what the block's tests share (`afterAll`) */
|
|
13
|
+
restart(): Promise<void>;
|
|
14
|
+
sink: TestSink;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Runs the tests of a serial block in order. After a failure the rest of the block is reported as skipped; with
|
|
18
|
+
* `retries`, the whole block then runs again from its first test (after `restart`), up to `retries` times.
|
|
19
|
+
* Without retries every test is reported as it ends. With them the ends are held until the block's last attempt is
|
|
20
|
+
* known, as `runWithRetries` does for one test: each test ends once, with `retry` saying which attempt that was.
|
|
21
|
+
* An aborted run is never run again.
|
|
22
|
+
*/
|
|
23
|
+
export declare function serialBlockRun(run: SerialBlockRun): Promise<void>;
|