@itmetsam/samurai-framework 0.22.0 → 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 +3 -3
- 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-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 +6 -9
- package/dist/browser/page.js +31 -63
- package/dist/browser/screenshot.d.ts +6 -0
- package/dist/browser/screenshot.js +14 -0
- package/dist/config/config.js +2 -1
- package/dist/config/fixture-use.d.ts +19 -0
- package/dist/config/fixture-use.js +44 -0
- package/dist/config/group-use.d.ts +4 -2
- package/dist/config/group-use.js +30 -20
- package/dist/config/use-options.js +5 -1
- package/dist/runner/fixture-defs.d.ts +2 -1
- package/dist/runner/fixture-defs.js +51 -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/prepare-run.js +5 -0
- package/dist/runner/registry.js +15 -5
- package/dist/runner/reporter.d.ts +3 -1
- package/dist/runner/reporter.js +1 -0
- package/dist/runner/run-test.d.ts +3 -0
- package/dist/runner/run-test.js +16 -1
- package/dist/runner/run.d.ts +7 -0
- package/dist/runner/run.js +9 -0
- package/dist/runner/test-function.d.ts +2 -2
- package/dist/runner/test-runner.js +6 -1
- package/dist/runner/use-options.d.ts +16 -2
- package/dist/runner/use-options.js +28 -8
- package/dist/runner/worker-session.js +6 -0
- package/dist/types/config.d.ts +35 -22
- package/dist/types/extend.d.ts +54 -2
- package/dist/types/test.d.ts +24 -0
- package/dist/types/use.d.ts +14 -0
- package/package.json +1 -1
package/dist/runner/run-test.js
CHANGED
|
@@ -20,6 +20,7 @@ import { buildTestFixtures } from "./fixtures.js";
|
|
|
20
20
|
import { FixtureScope } from "./fixture-scope.js";
|
|
21
21
|
import { RequestFixture } from "./request-fixture.js";
|
|
22
22
|
import { effectiveUse } from "./use-options.js";
|
|
23
|
+
import { effectiveFixtureUse } from "./fixture-use.js";
|
|
23
24
|
import { beginOutputs, endOutputs } from "../wait/output-sink.js";
|
|
24
25
|
/**
|
|
25
26
|
* The state of one test run. A test ends once, whichever of finishing, failing, timing out, an abort or a
|
|
@@ -38,6 +39,8 @@ class TestOutcome {
|
|
|
38
39
|
this.browserClosed = false;
|
|
39
40
|
/** The test's inputs and outputs, as its report entry lists them when it ends */
|
|
40
41
|
this.io = () => ({});
|
|
42
|
+
/** The fixtures the test set up, as they stand when it ends */
|
|
43
|
+
this.fixtures = () => [];
|
|
41
44
|
}
|
|
42
45
|
get isEnded() {
|
|
43
46
|
return this.ended;
|
|
@@ -65,6 +68,7 @@ class TestOutcome {
|
|
|
65
68
|
screenshots: this.evidence?.screenshots,
|
|
66
69
|
...this.info?.reportExtras(),
|
|
67
70
|
...this.io(),
|
|
71
|
+
fixtures: this.fixtures(),
|
|
68
72
|
});
|
|
69
73
|
}
|
|
70
74
|
}
|
|
@@ -119,6 +123,9 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
119
123
|
// The `beforeAll` hooks come first, before a browser exists
|
|
120
124
|
await resources.allHooks?.ensure(test, browserName);
|
|
121
125
|
const use = await effectiveUse(test);
|
|
126
|
+
const fixtureUse = test.extension
|
|
127
|
+
? await effectiveFixtureUse(test)
|
|
128
|
+
: undefined;
|
|
122
129
|
const launched = await Browser.launch(browserName, {
|
|
123
130
|
port: resources.port ?? options.port ?? DEFAULT_PORT,
|
|
124
131
|
...(resources.profileDir && { profileDir: resources.profileDir }),
|
|
@@ -177,9 +184,17 @@ export async function runOneTest(test, browserName, run, options, srcDir, report
|
|
|
177
184
|
});
|
|
178
185
|
// A test written with `test.extend()` gets its custom fixtures set up on demand, and torn down below
|
|
179
186
|
const custom = test.extension
|
|
180
|
-
? 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
|
+
})
|
|
181
194
|
: undefined;
|
|
182
195
|
customFixtures = custom;
|
|
196
|
+
if (custom)
|
|
197
|
+
outcome.fixtures = () => custom.report();
|
|
183
198
|
const fixtures = custom?.fixtures ?? built;
|
|
184
199
|
let failure;
|
|
185
200
|
let failed = false;
|
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,6 +46,12 @@ 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";
|
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,6 +69,13 @@ 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";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AllHook, SuiteMode, TestCaseBase, TestDetails, TestInfo, TestOptions } from "../types/test.js";
|
|
2
|
-
import type { UseOptions } from "../types/use.js";
|
|
2
|
+
import type { FixtureUse, UseOptions } from "../types/use.js";
|
|
3
3
|
import type { FixtureDefinitions, FixturesOf, MergeFixtures } from "../types/extend.js";
|
|
4
4
|
/** What the registry keeps of a test body; the fixtures it gets are those of the test it was written for */
|
|
5
5
|
export type Body = TestCaseBase["function"];
|
|
@@ -46,7 +46,7 @@ export interface TestFunction<X = NoFixtures> {
|
|
|
46
46
|
* the whole file at the top level, whether before or after the tests. An inner block wins over an outer one, and
|
|
47
47
|
* both win over config `use`.
|
|
48
48
|
*/
|
|
49
|
-
use: (options: UseOptions) => void;
|
|
49
|
+
use: (options: UseOptions & FixtureUse) => void;
|
|
50
50
|
/** `describe`, under the name other frameworks use */
|
|
51
51
|
describe: DescribeFunction;
|
|
52
52
|
/** `beforeEach`, as `test.beforeEach` */
|
|
@@ -6,6 +6,7 @@ import { loadRawConfig, projectDir, readConfig } from "../config/config.js";
|
|
|
6
6
|
import { forbidsOnly } from "../config/forbid-only.js";
|
|
7
7
|
import logger from "../logger/index.js";
|
|
8
8
|
import { AllHooks } from "./all-hooks.js";
|
|
9
|
+
import { WorkerFixtures } from "./fixture-worker.js";
|
|
9
10
|
import { assertNoOnly, narrowToOnly } from "./focus.js";
|
|
10
11
|
import { DEFAULT_SRC_DIR, DEFAULT_TEST_MATCH } from "../config/defaults.js";
|
|
11
12
|
import { DEFAULT_PORT } from "./ports.js";
|
|
@@ -149,11 +150,13 @@ export default class TestRunner {
|
|
|
149
150
|
timeout: this.run.settings.timeout,
|
|
150
151
|
fixtures: (browser) => allHookFixtures(this.run, browser),
|
|
151
152
|
});
|
|
153
|
+
// The worker-scoped fixtures of the run: torn down when the last test is done
|
|
154
|
+
const workerFixtures = new WorkerFixtures(this.run.settings.timeout);
|
|
152
155
|
try {
|
|
153
156
|
for (const browser of browsers) {
|
|
154
157
|
const forBrowser = selected.filter((test) => runsIn(test, browser));
|
|
155
158
|
for (const chunk of chunkBySerialBlock(forBrowser)) {
|
|
156
|
-
const runTest = (test, sink, attempt) => runOneTest(test, browser, this.run, this.options, loaded.srcDir, sink, { allHooks, attempt });
|
|
159
|
+
const runTest = (test, sink, attempt) => runOneTest(test, browser, this.run, this.options, loaded.srcDir, sink, { allHooks, workerFixtures, attempt });
|
|
157
160
|
if (chunk.block) {
|
|
158
161
|
const { suite } = chunk.block;
|
|
159
162
|
await serialBlockRun({
|
|
@@ -192,6 +195,8 @@ export default class TestRunner {
|
|
|
192
195
|
finally {
|
|
193
196
|
for (const error of await allHooks.closeAll())
|
|
194
197
|
logger.error("%s", error.message);
|
|
198
|
+
for (const error of await workerFixtures.closeAll())
|
|
199
|
+
logger.error("%s", error.message);
|
|
195
200
|
}
|
|
196
201
|
return reporter.onEnd();
|
|
197
202
|
}
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import type { GroupUse } from "../types/config.js";
|
|
2
2
|
import type { RegisteredTestCase } from "../types/test.js";
|
|
3
|
+
/** The `use` objects that apply to one test, as written, lowest layer first */
|
|
4
|
+
export interface UseLayers {
|
|
5
|
+
/** Config `use` */
|
|
6
|
+
config: object;
|
|
7
|
+
/** `environments.<name>.use` of the run's environment */
|
|
8
|
+
environment: object;
|
|
9
|
+
/** `use` of the group the test runs for */
|
|
10
|
+
group: object;
|
|
11
|
+
/** The `test.use()` calls around the test, outermost first */
|
|
12
|
+
tests: object[];
|
|
13
|
+
}
|
|
14
|
+
/** The `use` layers of a test: config, then the run's environment, then the group it runs for, then `test.use()` */
|
|
15
|
+
export declare function useLayers(test: RegisteredTestCase): Promise<UseLayers>;
|
|
3
16
|
/**
|
|
4
|
-
* The `use` options one test runs with: config `use`, then the `use` of the
|
|
5
|
-
* the `test.use()` calls around the test, outermost first, a later one
|
|
17
|
+
* The `use` options one test runs with: config `use`, then the `use` of the run's environment, then the `use` of
|
|
18
|
+
* the group the test runs for (if any), then the `test.use()` calls around the test, outermost first, a later one
|
|
19
|
+
* winning key by key. The fixture keys (`fixtures`, `orderOptions`) are for the fixtures: see `effectiveFixtureUse`.
|
|
6
20
|
*/
|
|
7
21
|
export declare function effectiveUse(test: RegisteredTestCase): Promise<GroupUse>;
|
|
@@ -1,25 +1,45 @@
|
|
|
1
1
|
import { readConfig } from "../config/config.js";
|
|
2
|
+
import { omitFixtureUse } from "../config/fixture-use.js";
|
|
2
3
|
import { groupUseOf } from "../config/group-use.js";
|
|
4
|
+
import { peekRunSettings } from "../config/run-settings.js";
|
|
3
5
|
import { mergeUse, useOptionsOf } from "../config/use-options.js";
|
|
4
6
|
import logger from "../logger/index.js";
|
|
5
7
|
import { useOf } from "./suite.js";
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
* the `test.use()` calls around the test, outermost first, a later one winning key by key
|
|
9
|
-
*/
|
|
10
|
-
export async function effectiveUse(test) {
|
|
8
|
+
/** The `use` layers of a test: config, then the run's environment, then the group it runs for, then `test.use()` */
|
|
9
|
+
export async function useLayers(test) {
|
|
11
10
|
let config;
|
|
12
11
|
let groups;
|
|
12
|
+
let environments;
|
|
13
13
|
try {
|
|
14
14
|
config = await readConfig("use");
|
|
15
15
|
groups = await readConfig("groups");
|
|
16
|
+
environments = await readConfig("environments");
|
|
16
17
|
}
|
|
17
18
|
catch (err) {
|
|
18
19
|
logger.debug("Could not read use config, using defaults", { err });
|
|
19
20
|
}
|
|
21
|
+
const environment = peekRunSettings()?.environment;
|
|
22
|
+
return {
|
|
23
|
+
config: config ?? {},
|
|
24
|
+
environment: (environment !== undefined &&
|
|
25
|
+
Object.prototype.hasOwnProperty.call(environments ?? {}, environment) &&
|
|
26
|
+
environments?.[environment]?.use) ||
|
|
27
|
+
{},
|
|
28
|
+
group: test.group === undefined ? {} : groupUseOf(groups, test.group),
|
|
29
|
+
tests: useOf(test.suite),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The `use` options one test runs with: config `use`, then the `use` of the run's environment, then the `use` of
|
|
34
|
+
* the group the test runs for (if any), then the `test.use()` calls around the test, outermost first, a later one
|
|
35
|
+
* winning key by key. The fixture keys (`fixtures`, `orderOptions`) are for the fixtures: see `effectiveFixtureUse`.
|
|
36
|
+
*/
|
|
37
|
+
export async function effectiveUse(test) {
|
|
38
|
+
const layers = await useLayers(test);
|
|
20
39
|
return mergeUse([
|
|
21
|
-
useOptionsOf(config),
|
|
22
|
-
|
|
23
|
-
|
|
40
|
+
useOptionsOf(layers.config),
|
|
41
|
+
omitFixtureUse(layers.environment),
|
|
42
|
+
omitFixtureUse(layers.group),
|
|
43
|
+
...layers.tests.map((layer) => omitFixtureUse(layer)),
|
|
24
44
|
]);
|
|
25
45
|
}
|
|
@@ -3,6 +3,7 @@ import logger from "../logger/index.js";
|
|
|
3
3
|
import { withProject } from "./project.js";
|
|
4
4
|
import TestReporter from "./reporter.js";
|
|
5
5
|
import { AllHooks } from "./all-hooks.js";
|
|
6
|
+
import { WorkerFixtures } from "./fixture-worker.js";
|
|
6
7
|
import { allHookFixtures } from "./fixtures.js";
|
|
7
8
|
import { runOneTest } from "./run-test.js";
|
|
8
9
|
import { runWithRetries } from "./retry.js";
|
|
@@ -37,6 +38,8 @@ export function openSession(init) {
|
|
|
37
38
|
timeout: run.settings.timeout,
|
|
38
39
|
fixtures: (browser) => allHookFixtures(run, browser, workerIndex),
|
|
39
40
|
});
|
|
41
|
+
// The worker-scoped fixtures this worker set up: torn down when it closes
|
|
42
|
+
const workerFixtures = new WorkerFixtures(run.settings.timeout);
|
|
40
43
|
resolve({
|
|
41
44
|
tests: loaded.all,
|
|
42
45
|
async runTest(test, browser, signal, onEvent, perTest = {}) {
|
|
@@ -63,12 +66,15 @@ export function openSession(init) {
|
|
|
63
66
|
profileDir: workerProfileDir(browser, workerIndex),
|
|
64
67
|
workerIndex,
|
|
65
68
|
allHooks,
|
|
69
|
+
workerFixtures,
|
|
66
70
|
attempt,
|
|
67
71
|
}), reporter);
|
|
68
72
|
},
|
|
69
73
|
async close() {
|
|
70
74
|
for (const error of await allHooks.closeAll())
|
|
71
75
|
logger.error("%s", error.message);
|
|
76
|
+
for (const error of await workerFixtures.closeAll())
|
|
77
|
+
logger.error("%s", error.message);
|
|
72
78
|
release();
|
|
73
79
|
await finished;
|
|
74
80
|
},
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StepDefinition } from "../flows/steps/define.js";
|
|
2
2
|
import type { SupportedBrowser } from "./browser.js";
|
|
3
|
-
import type { UseOptions } from "./use.js";
|
|
3
|
+
import type { FixtureUse, UseOptions } from "./use.js";
|
|
4
4
|
import type { ResolvedConfig } from "../config/resolved-config.js";
|
|
5
5
|
|
|
6
6
|
interface SamuraiTest {
|
|
@@ -39,7 +39,7 @@ export interface SamuraiGroup {
|
|
|
39
39
|
* as config `use` that make sense per group (`locale`, `isMobile`, `viewport`, ...). They apply when the group is
|
|
40
40
|
* selected (`--group`); a run without `--group` ignores them. The way to port a Playwright project.
|
|
41
41
|
*/
|
|
42
|
-
use?: GroupUse;
|
|
42
|
+
use?: GroupUse & FixtureUse;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/** The options of a group's `use`: those of `test.use()`, and the page's `viewport` */
|
|
@@ -105,6 +105,12 @@ export interface SamuraiEnvironment {
|
|
|
105
105
|
headless?: boolean;
|
|
106
106
|
/** Test data, used in steps as ${name}. Never put secrets here. */
|
|
107
107
|
variables?: Record<string, string | number | boolean>;
|
|
108
|
+
/**
|
|
109
|
+
* `use` options for every test run in this environment, over config `use` and under a group's `use` and
|
|
110
|
+
* `test.use()`. `fixtures: { order: false }` turns a fixture off here for good: a test that needs it is skipped,
|
|
111
|
+
* whatever a group or test says.
|
|
112
|
+
*/
|
|
113
|
+
use?: GroupUse & FixtureUse;
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
export interface SamuraiTestConfig {
|
|
@@ -199,26 +205,27 @@ export interface SamuraiTestConfig {
|
|
|
199
205
|
*/
|
|
200
206
|
filesDir?: string;
|
|
201
207
|
/** How pages are opened, and what the browser pretends: the options of `test.use()` apply to every test */
|
|
202
|
-
use?: UseOptions &
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
208
|
+
use?: UseOptions &
|
|
209
|
+
FixtureUse & {
|
|
210
|
+
/**
|
|
211
|
+
* Size of the page's viewport, so screenshots and layout are the same on every machine.
|
|
212
|
+
* `null` keeps the browser's own size
|
|
213
|
+
* @default { width: 1280, height: 720 }
|
|
214
|
+
*/
|
|
215
|
+
viewport?: { width: number; height: number } | null;
|
|
216
|
+
/**
|
|
217
|
+
* Run the browser without a window. Needed on machines without a display, such as CI runners.
|
|
218
|
+
* Left out, a run is headless when the `CI` environment variable is set and shows a window otherwise
|
|
219
|
+
*/
|
|
220
|
+
headless?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Make an action or read on a locator that matches several elements throw
|
|
223
|
+
* `name(): strict mode violation, N elements match ...` instead of using the first one. Narrow the locator
|
|
224
|
+
* (`first()`, `nth()`, `filter()`) or turn it off for one locator with `locator.strict(false)`
|
|
225
|
+
* @default false
|
|
226
|
+
*/
|
|
227
|
+
strictSelectors?: boolean;
|
|
228
|
+
};
|
|
222
229
|
/** What to do with the browser's console output and uncaught page exceptions */
|
|
223
230
|
logs?: {
|
|
224
231
|
/**
|
|
@@ -293,6 +300,12 @@ export interface SamuraiTestConfig {
|
|
|
293
300
|
globalSetup?: string | GlobalSetupFunction;
|
|
294
301
|
/** Module (path relative to the project folder) whose default export runs once after the tests; or the function itself */
|
|
295
302
|
globalTeardown?: string | GlobalTeardownFunction;
|
|
303
|
+
/**
|
|
304
|
+
* The tests made with `test.extend()` whose fixtures the app, the groups and `use.fixtures` can name. The
|
|
305
|
+
* fixtures are read from the list without running a test; a name defined twice, or not matching
|
|
306
|
+
* `/^[a-z][A-Za-z0-9]*$/`, refuses the run.
|
|
307
|
+
*/
|
|
308
|
+
fixtures?: { extend: (...args: never[]) => unknown }[];
|
|
296
309
|
/** Keyed by name: 'dev', 'staging', 'production' */
|
|
297
310
|
environments?: Record<string, SamuraiEnvironment>;
|
|
298
311
|
/** Used when no environment is chosen with --env or SAMURAI_ENV */
|
package/dist/types/extend.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Field } from "../flows/core/index.js";
|
|
1
2
|
import type { TestFixtures } from "./test.js";
|
|
2
3
|
|
|
3
4
|
/** What a test sees when it is built with `test.extend()`: the built-in fixtures, a custom one of the same name replacing it */
|
|
@@ -6,12 +7,63 @@ export type FixturesOf<X> = Omit<TestFixtures, keyof X> & X;
|
|
|
6
7
|
/** `B` on top of `A`: a key in both takes the type from `B` */
|
|
7
8
|
export type MergeFixtures<A, B> = Omit<A, keyof B> & B;
|
|
8
9
|
|
|
10
|
+
/** One key of the value a fixture sets up, listed for the app and the report */
|
|
11
|
+
export interface FixtureOutput {
|
|
12
|
+
name: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
/** The test gets the key, but the report and the app never do */
|
|
15
|
+
secret?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* One setting of an option fixture, as data for a form: the flows field types, with paths relative to the option
|
|
20
|
+
* object. `secret` stores the name of a secret and `variable` the name of a variable; the fixture receives the
|
|
21
|
+
* resolved value.
|
|
22
|
+
*/
|
|
23
|
+
export type FixtureField =
|
|
24
|
+
| Extract<
|
|
25
|
+
Field,
|
|
26
|
+
{
|
|
27
|
+
type:
|
|
28
|
+
| "text"
|
|
29
|
+
| "code"
|
|
30
|
+
| "expression"
|
|
31
|
+
| "number"
|
|
32
|
+
| "select"
|
|
33
|
+
| "segmented"
|
|
34
|
+
| "switch";
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
| {
|
|
38
|
+
path: string;
|
|
39
|
+
label?: string;
|
|
40
|
+
type: "secret" | "variable";
|
|
41
|
+
default?: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
9
44
|
/** The options of a fixture written as `[fixture, options]` */
|
|
10
45
|
export interface FixtureOptions {
|
|
11
46
|
/** Set the fixture up for every test, whether or not the test asks for it */
|
|
12
47
|
auto?: boolean;
|
|
13
|
-
/**
|
|
14
|
-
|
|
48
|
+
/**
|
|
49
|
+
* `"test"`: set up for each test (the default). `"worker"`: set up once per worker for the tests that use it with
|
|
50
|
+
* the same options and environment, and torn down when the worker is done. A worker fixture gets no `page`.
|
|
51
|
+
*/
|
|
52
|
+
scope?: "test" | "worker";
|
|
53
|
+
/** The name in the app's catalog */
|
|
54
|
+
label?: string;
|
|
55
|
+
/** A design-system icon name */
|
|
56
|
+
icon?: string;
|
|
57
|
+
/** One sentence for the catalog */
|
|
58
|
+
description?: string;
|
|
59
|
+
/** The keys of the value the fixture sets up, when it is a flat record of strings, numbers and booleans */
|
|
60
|
+
outputs?: FixtureOutput[];
|
|
61
|
+
/** Milliseconds a setup or a teardown may take. @default the test timeout */
|
|
62
|
+
timeout?: number;
|
|
63
|
+
/** The fixture is the options of the fixture `<name without "Options">`: a value that `use` overrides key by key */
|
|
64
|
+
option?: boolean;
|
|
65
|
+
/** The form of an option fixture */
|
|
66
|
+
fields?: FixtureField[];
|
|
15
67
|
}
|
|
16
68
|
|
|
17
69
|
/** A value, or a function that sets the value up, calls `use(value)` and cleans up once `use` returns */
|
package/dist/types/test.d.ts
CHANGED
|
@@ -74,6 +74,26 @@ export interface TestStepEntry {
|
|
|
74
74
|
steps?: TestStepEntry[];
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/** How a fixture's setup or teardown went in one test */
|
|
78
|
+
export interface TestFixturePhase {
|
|
79
|
+
/** `"skipped"`: a worker fixture another test of this worker already set up */
|
|
80
|
+
status: "passed" | "failed" | "skipped";
|
|
81
|
+
/** Milliseconds */
|
|
82
|
+
durationMs: number;
|
|
83
|
+
error?: TestError;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A fixture that set up for a test (hand-written `test.extend` ones too), as the report lists it */
|
|
87
|
+
export interface TestFixtureEntry {
|
|
88
|
+
name: string;
|
|
89
|
+
scope: "test" | "worker";
|
|
90
|
+
setup: TestFixturePhase;
|
|
91
|
+
/** Absent for a worker fixture: it is torn down when the worker is done, after the test's result is written */
|
|
92
|
+
teardown?: Omit<TestFixturePhase, "status"> & { status: "passed" | "failed" };
|
|
93
|
+
/** The declared outputs that are not secret */
|
|
94
|
+
outputs?: Record<string, string | number | boolean>;
|
|
95
|
+
}
|
|
96
|
+
|
|
77
97
|
/** What `testInfo` and `test.info()` tell about the running test (hooks included) */
|
|
78
98
|
export interface TestInfo {
|
|
79
99
|
/** The test's own title */
|
|
@@ -245,6 +265,8 @@ interface TestResultSuccess extends TestResultIdentity, TestRetries {
|
|
|
245
265
|
annotations?: TestAnnotation[];
|
|
246
266
|
/** The steps the test ran with `test.step`; absent when it ran none */
|
|
247
267
|
steps?: TestStepEntry[];
|
|
268
|
+
/** The fixtures the test set up and how each went; absent when it used none */
|
|
269
|
+
fixtures?: TestFixtureEntry[];
|
|
248
270
|
}
|
|
249
271
|
|
|
250
272
|
/** The error sits flat on the entry, as in the report: `message`, `type`, `stack`, and for assertions `expected` and `actual` */
|
|
@@ -265,6 +287,8 @@ interface TestResultFailed extends TestResultIdentity, TestError, TestRetries {
|
|
|
265
287
|
annotations?: TestAnnotation[];
|
|
266
288
|
/** The steps the test ran with `test.step`; absent when it ran none */
|
|
267
289
|
steps?: TestStepEntry[];
|
|
290
|
+
/** The fixtures the test set up and how each went; absent when it used none */
|
|
291
|
+
fixtures?: TestFixtureEntry[];
|
|
268
292
|
}
|
|
269
293
|
|
|
270
294
|
/** What a result says about the retries of its test; absent when it passed or failed on the first attempt */
|
package/dist/types/use.d.ts
CHANGED
|
@@ -38,6 +38,20 @@ export interface UseOptions {
|
|
|
38
38
|
colorScheme?: ColorScheme;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* What a `use` that is layered over config, environment, group and `test.use()` can also say about fixtures. Not
|
|
43
|
+
* part of `UseOptions`: `page.use()` and the browser know nothing of fixtures.
|
|
44
|
+
*/
|
|
45
|
+
export interface FixtureUse {
|
|
46
|
+
/**
|
|
47
|
+
* Fixtures to attach by name (`true`: set up before `beforeEach`, like an `auto` fixture) or to remove (`false`).
|
|
48
|
+
* An environment's `false` wins over a group's or test's `true`.
|
|
49
|
+
*/
|
|
50
|
+
fixtures?: Record<string, boolean>;
|
|
51
|
+
/** The values of an option fixture (`orderOptions: { items: 2 }`), merged key by key with the other layers */
|
|
52
|
+
[option: `${string}Options`]: Record<string, unknown> | undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
/** The options `page.use()` and `context.use()` take: those that can change while the browser runs */
|
|
42
56
|
export type RuntimeUseOptions = Pick<
|
|
43
57
|
UseOptions,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itmetsam/samurai-framework",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.1",
|
|
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": {
|