@itmetsam/samurai-framework 0.2.2 → 0.3.0
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/README.md +5 -0
- package/bin/samurai.mjs +7 -5
- package/dist/cli/args.d.ts +5 -1
- package/dist/cli/args.js +6 -1
- package/dist/cli/flow-reporter.d.ts +23 -0
- package/dist/cli/flow-reporter.js +97 -0
- package/dist/cli/flow.d.ts +4 -0
- package/dist/cli/flow.js +240 -0
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.js +14 -0
- package/dist/flows/core/check.d.ts +42 -0
- package/dist/flows/core/check.js +202 -0
- package/dist/flows/core/expression/check.d.ts +21 -0
- package/dist/flows/core/expression/check.js +95 -0
- package/dist/flows/core/expression/evaluate.d.ts +22 -0
- package/dist/flows/core/expression/evaluate.js +141 -0
- package/dist/flows/core/expression/help.d.ts +25 -0
- package/dist/flows/core/expression/help.js +75 -0
- package/dist/flows/core/expression/index.d.ts +5 -0
- package/dist/flows/core/expression/index.js +5 -0
- package/dist/flows/core/expression/parse.d.ts +61 -0
- package/dist/flows/core/expression/parse.js +317 -0
- package/dist/flows/core/expression/scope.d.ts +7 -0
- package/dist/flows/core/expression/scope.js +25 -0
- package/dist/flows/core/graph.d.ts +11 -0
- package/dist/flows/core/graph.js +65 -0
- package/dist/flows/core/index.d.ts +16 -0
- package/dist/flows/core/index.js +16 -0
- package/dist/flows/core/keys.d.ts +8 -0
- package/dist/flows/core/keys.js +46 -0
- package/dist/flows/core/nodes/api.d.ts +9 -0
- package/dist/flows/core/nodes/api.js +12 -0
- package/dist/flows/core/nodes/condition.d.ts +7 -0
- package/dist/flows/core/nodes/condition.js +21 -0
- package/dist/flows/core/nodes/database.d.ts +9 -0
- package/dist/flows/core/nodes/database.js +12 -0
- package/dist/flows/core/nodes/define.d.ts +128 -0
- package/dist/flows/core/nodes/define.js +21 -0
- package/dist/flows/core/nodes/email.d.ts +9 -0
- package/dist/flows/core/nodes/email.js +12 -0
- package/dist/flows/core/nodes/end.d.ts +1 -0
- package/dist/flows/core/nodes/end.js +7 -0
- package/dist/flows/core/nodes/group.d.ts +5 -0
- package/dist/flows/core/nodes/group.js +18 -0
- package/dist/flows/core/nodes/index.d.ts +107 -0
- package/dist/flows/core/nodes/index.js +81 -0
- package/dist/flows/core/nodes/parallel.d.ts +1 -0
- package/dist/flows/core/nodes/parallel.js +11 -0
- package/dist/flows/core/nodes/path.d.ts +5 -0
- package/dist/flows/core/nodes/path.js +21 -0
- package/dist/flows/core/nodes/script.d.ts +9 -0
- package/dist/flows/core/nodes/script.js +12 -0
- package/dist/flows/core/nodes/set-variable.d.ts +13 -0
- package/dist/flows/core/nodes/set-variable.js +39 -0
- package/dist/flows/core/nodes/start.d.ts +1 -0
- package/dist/flows/core/nodes/start.js +7 -0
- package/dist/flows/core/nodes/test.d.ts +1 -0
- package/dist/flows/core/nodes/test.js +18 -0
- package/dist/flows/core/nodes/wait.d.ts +15 -0
- package/dist/flows/core/nodes/wait.js +18 -0
- package/dist/flows/core/schema.d.ts +55 -0
- package/dist/flows/core/schema.js +33 -0
- package/dist/flows/run/events.d.ts +43 -0
- package/dist/flows/run/events.js +1 -0
- package/dist/flows/run/files.d.ts +12 -0
- package/dist/flows/run/files.js +54 -0
- package/dist/flows/run/handlers/condition.d.ts +2 -0
- package/dist/flows/run/handlers/condition.js +17 -0
- package/dist/flows/run/handlers/end.d.ts +2 -0
- package/dist/flows/run/handlers/end.js +1 -0
- package/dist/flows/run/handlers/group.d.ts +2 -0
- package/dist/flows/run/handlers/group.js +7 -0
- package/dist/flows/run/handlers/index.d.ts +6 -0
- package/dist/flows/run/handlers/index.js +22 -0
- package/dist/flows/run/handlers/parallel.d.ts +3 -0
- package/dist/flows/run/handlers/parallel.js +2 -0
- package/dist/flows/run/handlers/set-variable.d.ts +2 -0
- package/dist/flows/run/handlers/set-variable.js +22 -0
- package/dist/flows/run/handlers/start.d.ts +2 -0
- package/dist/flows/run/handlers/start.js +1 -0
- package/dist/flows/run/handlers/support.d.ts +26 -0
- package/dist/flows/run/handlers/support.js +22 -0
- package/dist/flows/run/handlers/test.d.ts +2 -0
- package/dist/flows/run/handlers/test.js +7 -0
- package/dist/flows/run/handlers/wait.d.ts +2 -0
- package/dist/flows/run/handlers/wait.js +10 -0
- package/dist/flows/run/index.d.ts +8 -0
- package/dist/flows/run/index.js +7 -0
- package/dist/flows/run/project.d.ts +43 -0
- package/dist/flows/run/project.js +163 -0
- package/dist/flows/run/report.d.ts +39 -0
- package/dist/flows/run/report.js +46 -0
- package/dist/flows/run/run.d.ts +42 -0
- package/dist/flows/run/run.js +244 -0
- package/dist/locator/locator.d.ts +8 -0
- package/dist/locator/locator.js +46 -0
- package/dist/recorder/capture.d.ts +2 -0
- package/dist/recorder/capture.js +14 -0
- package/dist/recorder/normalise.d.ts +5 -0
- package/dist/recorder/normalise.js +12 -0
- package/dist/recorder/recorder.js +20 -18
- package/dist/runner/groups.d.ts +39 -0
- package/dist/runner/groups.js +58 -0
- package/dist/runner/run.d.ts +4 -0
- package/dist/runner/run.js +12 -0
- package/dist/runner/test-runner.d.ts +12 -2
- package/dist/runner/test-runner.js +36 -6
- package/dist/steps/emit.js +2 -0
- package/dist/steps/model.d.ts +6 -0
- package/dist/steps/parse.js +4 -0
- package/package.json +9 -1
|
@@ -2,6 +2,7 @@ import type { RegisteredTestCase } from "../types/test.js";
|
|
|
2
2
|
import type { PreparedRun } from "./prepare-run.js";
|
|
3
3
|
import { type RunEvent } from "./reporter.js";
|
|
4
4
|
import type { SamuraiGroup } from "../types/config.js";
|
|
5
|
+
import type { ResolvedGroup } from "./groups.js";
|
|
5
6
|
/** What decides which tests of the found files run, and how the browser starts */
|
|
6
7
|
export interface RunnerOptions {
|
|
7
8
|
/** Spec files to run, absolute or relative to the project folder. Default: every `*.spec.ts` under `srcDir` */
|
|
@@ -10,6 +11,8 @@ export interface RunnerOptions {
|
|
|
10
11
|
grep?: string | RegExp;
|
|
11
12
|
/** Only tests with exactly one of these full names (`describe` titles joined with " > ") */
|
|
12
13
|
testNames?: string[];
|
|
14
|
+
/** Only the tests of this group of the config's `groups` (unknown name: an error). Combines with the other filters */
|
|
15
|
+
group?: string;
|
|
13
16
|
/** Run the browser without a window. @default false */
|
|
14
17
|
headless?: boolean;
|
|
15
18
|
/** Remote debugging port of the browser. @default 9223 */
|
|
@@ -30,12 +33,19 @@ export default class TestRunner {
|
|
|
30
33
|
private options;
|
|
31
34
|
constructor(testFiles: string[], run: PreparedRun, group?: SamuraiGroup, options?: RunnerOptions);
|
|
32
35
|
static init(run: PreparedRun, group?: SamuraiGroup, options?: RunnerOptions): Promise<TestRunner>;
|
|
33
|
-
/** Runs the selected tests and returns the summary that was also written to the report */
|
|
34
36
|
/**
|
|
35
|
-
* Imports the spec files and returns
|
|
37
|
+
* Imports the spec files and returns every test they register. A fresh registry and a fresh import of each
|
|
36
38
|
* file, so a second run in this process registers its tests again (and sees edited specs, for files loaded as
|
|
37
39
|
* ES modules; CommonJS files stay cached until the process ends)
|
|
38
40
|
*/
|
|
41
|
+
private registerAll;
|
|
42
|
+
/** Id of a registered test: its spec file relative to `srcDir`, then its name */
|
|
43
|
+
private idOf;
|
|
44
|
+
/** The config's groups, resolved against the tests the specs register */
|
|
45
|
+
private resolveAll;
|
|
46
|
+
/** The groups of the config with the tests each holds; see `listGroups` */
|
|
47
|
+
groups(): Promise<ResolvedGroup[]>;
|
|
48
|
+
/** Imports the spec files and returns the tests the options select: by `group`, `testNames` and `grep` */
|
|
39
49
|
register(): Promise<RegisteredTestCase[]>;
|
|
40
50
|
/** Runs the selected tests and returns the summary that was also written to the report */
|
|
41
51
|
start(): Promise<import("../types/test.js").TestSummary>;
|
|
@@ -3,7 +3,7 @@ import { glob } from "node:fs/promises";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { pathToFileURL } from "url";
|
|
5
5
|
import { Browser } from "../browser/browser.js";
|
|
6
|
-
import { projectDir, readConfig } from "../config/config.js";
|
|
6
|
+
import { loadConfig, projectDir, readConfig } from "../config/config.js";
|
|
7
7
|
import logger from "../logger/index.js";
|
|
8
8
|
import { assertModuleProject } from "./module-type.js";
|
|
9
9
|
import { clearRegistry, registeredTests } from "./registry.js";
|
|
@@ -14,6 +14,7 @@ import Page from "../browser/page.js";
|
|
|
14
14
|
import { takePendingAssertions } from "../assert/expect.js";
|
|
15
15
|
import { toTestError } from "./test-error.js";
|
|
16
16
|
import { ConnectionClosedError } from "../transport/bidi-connection.js";
|
|
17
|
+
import { DEFAULT_SRC_DIR, findGroup, resolveGroups, testId, toPosix, } from "./groups.js";
|
|
17
18
|
import { judgePageLogs } from "./page-logs-report.js";
|
|
18
19
|
/** Whether a test with this full name is selected by the options */
|
|
19
20
|
export function isSelected(name, { grep, testNames }) {
|
|
@@ -57,13 +58,12 @@ export default class TestRunner {
|
|
|
57
58
|
logger.debug("Found %d tests in srcDir", testFiles.length);
|
|
58
59
|
return new TestRunner(testFiles.map((file) => path.join(cwd, file)), run, group, options);
|
|
59
60
|
}
|
|
60
|
-
/** Runs the selected tests and returns the summary that was also written to the report */
|
|
61
61
|
/**
|
|
62
|
-
* Imports the spec files and returns
|
|
62
|
+
* Imports the spec files and returns every test they register. A fresh registry and a fresh import of each
|
|
63
63
|
* file, so a second run in this process registers its tests again (and sees edited specs, for files loaded as
|
|
64
64
|
* ES modules; CommonJS files stay cached until the process ends)
|
|
65
65
|
*/
|
|
66
|
-
async
|
|
66
|
+
async registerAll() {
|
|
67
67
|
clearRegistry();
|
|
68
68
|
const stamp = `?run=${Date.now().toString(36)}`;
|
|
69
69
|
for (const file of this.testFiles)
|
|
@@ -72,8 +72,38 @@ export default class TestRunner {
|
|
|
72
72
|
logger.verbose("Trying to register file: %s", file);
|
|
73
73
|
await import(pathToFileURL(file).href + stamp);
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
return [...registeredTests()];
|
|
76
|
+
}
|
|
77
|
+
/** Id of a registered test: its spec file relative to `srcDir`, then its name */
|
|
78
|
+
idOf(test, srcDir) {
|
|
79
|
+
return testId(toPosix(path.relative(srcDir, test.file)), test.name);
|
|
80
|
+
}
|
|
81
|
+
/** The config's groups, resolved against the tests the specs register */
|
|
82
|
+
async resolveAll(tests) {
|
|
83
|
+
const config = await loadConfig();
|
|
84
|
+
const dir = projectDir();
|
|
85
|
+
const srcDir = path.resolve(dir, config.srcDir ?? DEFAULT_SRC_DIR);
|
|
86
|
+
const groups = resolveGroups(config, tests.map(({ file, name }) => ({
|
|
87
|
+
file: toPosix(path.relative(srcDir, file)),
|
|
88
|
+
name,
|
|
89
|
+
})), dir, srcDir);
|
|
90
|
+
return { groups, srcDir };
|
|
91
|
+
}
|
|
92
|
+
/** The groups of the config with the tests each holds; see `listGroups` */
|
|
93
|
+
async groups() {
|
|
94
|
+
return (await this.resolveAll(await this.registerAll())).groups;
|
|
95
|
+
}
|
|
96
|
+
/** Imports the spec files and returns the tests the options select: by `group`, `testNames` and `grep` */
|
|
97
|
+
async register() {
|
|
98
|
+
const all = await this.registerAll();
|
|
99
|
+
const { group } = this.options;
|
|
100
|
+
let inGroup = () => true;
|
|
101
|
+
if (group !== undefined) {
|
|
102
|
+
const { groups, srcDir } = await this.resolveAll(all);
|
|
103
|
+
const members = new Set(findGroup(groups, group).testIds);
|
|
104
|
+
inGroup = (test) => members.has(this.idOf(test, srcDir));
|
|
105
|
+
}
|
|
106
|
+
return all.filter((test) => inGroup(test) && isSelected(test.name, this.options));
|
|
77
107
|
}
|
|
78
108
|
/** Runs the selected tests and returns the summary that was also written to the report */
|
|
79
109
|
async start() {
|
package/dist/steps/emit.js
CHANGED
|
@@ -63,6 +63,8 @@ export function stepToSource(step) {
|
|
|
63
63
|
return `await ${locatorToSource(step.locator)}.click();`;
|
|
64
64
|
case "fill":
|
|
65
65
|
return `await ${locatorToSource(step.locator)}.fill(${valueToSource(step.value)});`;
|
|
66
|
+
case "press":
|
|
67
|
+
return `await ${locatorToSource(step.locator)}.press(${str(step.key)});`;
|
|
66
68
|
case "expect":
|
|
67
69
|
return `await expect(${locatorToSource(step.locator)})${step.not ? ".not" : ""}.${expectationToSource(step.expectation)};`;
|
|
68
70
|
case "waitForNetworkIdle":
|
package/dist/steps/model.d.ts
CHANGED
|
@@ -75,6 +75,12 @@ export type Step = {
|
|
|
75
75
|
locator: LocatorSpec;
|
|
76
76
|
not: boolean;
|
|
77
77
|
expectation: Expectation;
|
|
78
|
+
}
|
|
79
|
+
/** A key pressed while the element has focus, e.g. `Enter` to submit a field. Named as Playwright names keys */
|
|
80
|
+
| {
|
|
81
|
+
kind: "press";
|
|
82
|
+
locator: LocatorSpec;
|
|
83
|
+
key: string;
|
|
78
84
|
} | {
|
|
79
85
|
kind: "waitForNetworkIdle";
|
|
80
86
|
}
|
package/dist/steps/parse.js
CHANGED
|
@@ -214,6 +214,10 @@ function readStep(statement) {
|
|
|
214
214
|
return undefined;
|
|
215
215
|
if (name.text === "click" && args.length === 0)
|
|
216
216
|
return { kind: "click", locator };
|
|
217
|
+
if (name.text === "press" && args.length === 1) {
|
|
218
|
+
const key = stringOf(args[0]);
|
|
219
|
+
return key === undefined ? undefined : { kind: "press", locator, key };
|
|
220
|
+
}
|
|
217
221
|
if (name.text === "fill" && args.length === 1) {
|
|
218
222
|
const value = readValue(args[0]);
|
|
219
223
|
return value ? { kind: "fill", locator, value } : undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itmetsam/samurai-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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": {
|
|
@@ -28,6 +28,14 @@
|
|
|
28
28
|
"types": "./dist/browser/index.d.ts",
|
|
29
29
|
"default": "./dist/browser/index.js"
|
|
30
30
|
},
|
|
31
|
+
"./flows": {
|
|
32
|
+
"types": "./dist/flows/core/index.d.ts",
|
|
33
|
+
"default": "./dist/flows/core/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./flows/run": {
|
|
36
|
+
"types": "./dist/flows/run/index.d.ts",
|
|
37
|
+
"default": "./dist/flows/run/index.js"
|
|
38
|
+
},
|
|
31
39
|
"./package.json": "./package.json"
|
|
32
40
|
},
|
|
33
41
|
"scripts": {
|