@itmetsam/samurai-framework 0.15.2 → 0.17.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/dist/browser/browser.js +2 -1
- package/dist/browser/page-network.js +3 -2
- package/dist/browser/page-settings.js +2 -5
- package/dist/browser/page.js +2 -1
- package/dist/browser/session.d.ts +1 -1
- package/dist/browser/session.js +1 -1
- package/dist/browser/viewport.d.ts +0 -5
- package/dist/browser/viewport.js +0 -2
- package/dist/capabilities.d.ts +36 -0
- package/dist/capabilities.js +34 -0
- package/dist/{runner/browsers.js → config/browsers-for.js} +1 -2
- package/dist/config/config.d.ts +5 -1
- package/dist/config/config.js +18 -12
- package/dist/config/defaults.d.ts +41 -0
- package/dist/config/defaults.js +38 -0
- package/dist/config/resolved-config.d.ts +134 -0
- package/dist/config/resolved-config.js +135 -0
- package/dist/config/run-settings.d.ts +2 -0
- package/dist/config/run-settings.js +2 -3
- package/dist/config/timeouts.js +1 -2
- package/dist/{runner → config}/workers-option.js +1 -1
- package/dist/flows/run/project-options.d.ts +2 -0
- package/dist/flows/run/project.js +11 -4
- package/dist/network/data-collector.js +1 -2
- package/dist/network/router.js +1 -2
- package/dist/project/files-store.js +2 -1
- package/dist/project/index.d.ts +1 -0
- package/dist/project/index.js +1 -0
- package/dist/recorder/session-browser.js +1 -1
- package/dist/recorder/session.d.ts +5 -2
- package/dist/recorder/session.js +18 -3
- package/dist/runner/groups.d.ts +4 -5
- package/dist/runner/groups.js +2 -5
- package/dist/runner/options.d.ts +7 -1
- package/dist/runner/output.d.ts +6 -0
- package/dist/runner/output.js +14 -0
- package/dist/runner/page-logs-report.js +6 -3
- package/dist/runner/project.js +2 -2
- package/dist/runner/retries-option.js +2 -1
- package/dist/runner/run-test.js +2 -5
- package/dist/runner/run.d.ts +12 -2
- package/dist/runner/run.js +21 -7
- package/dist/runner/select.js +4 -4
- package/dist/runner/test-dir.js +2 -1
- package/dist/runner/test-runner.d.ts +8 -2
- package/dist/runner/test-runner.js +16 -10
- package/dist/runner/worker-protocol.d.ts +2 -0
- package/dist/runner/worker-session.js +3 -0
- package/dist/steps/edit.d.ts +10 -0
- package/dist/steps/edit.js +4 -0
- package/dist/steps/index.d.ts +2 -2
- package/dist/steps/index.js +1 -1
- package/dist/steps/model.d.ts +17 -0
- package/dist/steps/parse.d.ts +6 -1
- package/dist/steps/parse.js +54 -10
- package/dist/transport/bidi-connection.d.ts +0 -2
- package/dist/transport/bidi-connection.js +1 -2
- package/package.json +6 -2
- /package/dist/{runner/browsers.d.ts → config/browsers-for.d.ts} +0 -0
- /package/dist/{runner → config}/workers-option.d.ts +0 -0
package/dist/steps/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { parseSpec } from "./parse.js";
|
|
1
|
+
export { parseSpec, parseSpecFile } from "./parse.js";
|
|
2
2
|
export { applyEdit, type StepEdit } from "./edit.js";
|
|
3
3
|
export { stepToSource, locatorToSource, callToSource, filesToSource, valueToSource, } from "./emit.js";
|
|
4
4
|
export { formatSize, humanSize, parseSize, sizeFromSource } from "./files.js";
|
|
5
5
|
export { locatorFromSpec } from "./build.js";
|
|
6
|
-
export type { Expectation, FileEntry, GeneratedFileSpec, LocatorCall, LocatorSpec, ParsedStep, ParsedTest, Step, TextMatcher, TextValue, } from "./model.js";
|
|
6
|
+
export type { Expectation, FileEntry, GeneratedFileSpec, LocatorCall, LocatorSpec, ParsedStep, ParsedTest, Step, TextMatcher, TextValue, UnparsedTest, } from "./model.js";
|
package/dist/steps/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { parseSpec } from "./parse.js";
|
|
1
|
+
export { parseSpec, parseSpecFile } from "./parse.js";
|
|
2
2
|
export { applyEdit } from "./edit.js";
|
|
3
3
|
export { stepToSource, locatorToSource, callToSource, filesToSource, valueToSource, } from "./emit.js";
|
|
4
4
|
export { formatSize, humanSize, parseSize, sizeFromSource } from "./files.js";
|
package/dist/steps/model.d.ts
CHANGED
|
@@ -146,6 +146,15 @@ export interface ParsedTest {
|
|
|
146
146
|
/** Offset just after the `{` of the test body, and of its closing `}` */
|
|
147
147
|
bodyStart: number;
|
|
148
148
|
bodyEnd: number;
|
|
149
|
+
/** Where the whole test starts: the full start of its statement, so the comments and blank line above are included */
|
|
150
|
+
start: number;
|
|
151
|
+
/** Where the whole test ends: the end of its statement, after the `;` */
|
|
152
|
+
end: number;
|
|
153
|
+
/**
|
|
154
|
+
* False when the test call isn't a statement of its own (a loop or `if` body without braces, an arrow's
|
|
155
|
+
* expression body), so it can't be removed without breaking the file
|
|
156
|
+
*/
|
|
157
|
+
removable: boolean;
|
|
149
158
|
/**
|
|
150
159
|
* The fixtures the test's callback destructures, and the offset where another one goes: after the last one
|
|
151
160
|
* (`list`), inside an empty `{}` (`empty`) or inside the empty `()` of a callback without parameters (`none`).
|
|
@@ -161,3 +170,11 @@ export interface ParsedTest {
|
|
|
161
170
|
/** The `{ reason }` written with the `skip` or `fixme` that applies, when it is a string literal */
|
|
162
171
|
reason?: string;
|
|
163
172
|
}
|
|
173
|
+
/** A `test` or `describe` call the codec can't read: its title isn't a plain string, or its function isn't written inline */
|
|
174
|
+
export interface UnparsedTest {
|
|
175
|
+
kind: "test" | "describe";
|
|
176
|
+
/** The statement's range, as for `ParsedTest` */
|
|
177
|
+
start: number;
|
|
178
|
+
end: number;
|
|
179
|
+
reason: "dynamic-title" | "not-inline";
|
|
180
|
+
}
|
package/dist/steps/parse.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import type { ParsedTest } from "./model.js";
|
|
1
|
+
import type { ParsedTest, UnparsedTest } from "./model.js";
|
|
2
|
+
/** The tests in a spec file, with their steps and where each statement sits, and the tests and describes it can't read */
|
|
3
|
+
export declare function parseSpecFile(source: string): {
|
|
4
|
+
tests: ParsedTest[];
|
|
5
|
+
unparsed: UnparsedTest[];
|
|
6
|
+
};
|
|
2
7
|
/** The tests in a spec file, with their steps and where each statement sits */
|
|
3
8
|
export declare function parseSpec(source: string): ParsedTest[];
|
package/dist/steps/parse.js
CHANGED
|
@@ -85,24 +85,64 @@ function effectiveMark(own, describes) {
|
|
|
85
85
|
};
|
|
86
86
|
return chain.some((m) => m.modifier === "only") ? { modifier: "only" } : {};
|
|
87
87
|
}
|
|
88
|
-
/** The
|
|
89
|
-
|
|
88
|
+
/** The range of a whole test: its statement with the comments above it, or the call alone when it isn't a statement */
|
|
89
|
+
function wholeRange(call) {
|
|
90
|
+
const statement = ts.isExpressionStatement(call.parent) ? call.parent : call;
|
|
91
|
+
return { start: statement.getFullStart(), end: statement.end };
|
|
92
|
+
}
|
|
93
|
+
/** Whether the call is a statement directly inside a block, a module block or the file, so removing its range leaves valid code */
|
|
94
|
+
function isRemovable(call) {
|
|
95
|
+
const statement = call.parent;
|
|
96
|
+
if (!ts.isExpressionStatement(statement))
|
|
97
|
+
return false;
|
|
98
|
+
const container = statement.parent;
|
|
99
|
+
return (ts.isBlock(container) ||
|
|
100
|
+
ts.isSourceFile(container) ||
|
|
101
|
+
ts.isModuleBlock(container));
|
|
102
|
+
}
|
|
103
|
+
/** A test or describe the codec can't read, with where its statement sits */
|
|
104
|
+
function unreadable(node, kind, reason) {
|
|
105
|
+
return { kind, reason, ...wholeRange(node) };
|
|
106
|
+
}
|
|
107
|
+
/** `test.skip(condition, reason)` inside a body: it takes a condition where a test takes a title, so it is neither a test nor unparsed */
|
|
108
|
+
function isConditionForm(node, callee) {
|
|
109
|
+
const [first] = node.arguments;
|
|
110
|
+
return ((callee.modifier === "skip" || callee.modifier === "fixme") &&
|
|
111
|
+
!(first &&
|
|
112
|
+
(ts.isStringLiteral(first) ||
|
|
113
|
+
ts.isNoSubstitutionTemplateLiteral(first) ||
|
|
114
|
+
ts.isTemplateExpression(first))));
|
|
115
|
+
}
|
|
116
|
+
/** The tests in a spec file, with their steps and where each statement sits, and the tests and describes it can't read */
|
|
117
|
+
export function parseSpecFile(source) {
|
|
90
118
|
const sourceFile = ts.createSourceFile("spec.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
91
119
|
const tests = [];
|
|
120
|
+
const unparsed = [];
|
|
92
121
|
const visit = (node, titles, describes) => {
|
|
93
122
|
const callee = ts.isCallExpression(node)
|
|
94
123
|
? calleeOf(node.expression)
|
|
95
124
|
: undefined;
|
|
96
|
-
if (ts.isCallExpression(node) &&
|
|
125
|
+
if (ts.isCallExpression(node) &&
|
|
126
|
+
callee &&
|
|
127
|
+
(callee.name === "test" || callee.name === "describe") &&
|
|
128
|
+
!(callee.name === "test" && isConditionForm(node, callee))) {
|
|
129
|
+
const kind = callee.name;
|
|
97
130
|
const title = stringOf(node.arguments[0]);
|
|
98
131
|
const { callback, reason } = callbackOf(node, callee.modifier);
|
|
99
132
|
const body = callbackBody(callback);
|
|
133
|
+
if (title === undefined) {
|
|
134
|
+
unparsed.push(unreadable(node, kind, "dynamic-title"));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (!body) {
|
|
138
|
+
unparsed.push(unreadable(node, kind, "not-inline"));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
100
141
|
const mark = {
|
|
101
142
|
...(callee.modifier && { modifier: callee.modifier }),
|
|
102
143
|
...(reason !== undefined && { reason }),
|
|
103
144
|
};
|
|
104
|
-
if (
|
|
105
|
-
// `test.skip(condition, reason)` has no title and no body, so it stays a step of the test it is in
|
|
145
|
+
if (kind === "test") {
|
|
106
146
|
const titlePath = [...titles, title];
|
|
107
147
|
tests.push({
|
|
108
148
|
titlePath,
|
|
@@ -110,18 +150,22 @@ export function parseSpec(source) {
|
|
|
110
150
|
steps: body.statements.map((statement) => parseStatement(source, statement, sourceFile)),
|
|
111
151
|
bodyStart: body.getStart(sourceFile) + 1,
|
|
112
152
|
bodyEnd: body.end - 1,
|
|
153
|
+
...wholeRange(node),
|
|
154
|
+
removable: isRemovable(node),
|
|
113
155
|
fixtures: callbackFixtures(callback, sourceFile),
|
|
114
156
|
...effectiveMark(mark, describes),
|
|
115
157
|
});
|
|
116
158
|
return;
|
|
117
159
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
160
|
+
ts.forEachChild(body, (child) => visit(child, [...titles, title], [...describes, mark]));
|
|
161
|
+
return;
|
|
122
162
|
}
|
|
123
163
|
ts.forEachChild(node, (child) => visit(child, titles, describes));
|
|
124
164
|
};
|
|
125
165
|
visit(sourceFile, [], []);
|
|
126
|
-
return tests;
|
|
166
|
+
return { tests, unparsed };
|
|
167
|
+
}
|
|
168
|
+
/** The tests in a spec file, with their steps and where each statement sits */
|
|
169
|
+
export function parseSpec(source) {
|
|
170
|
+
return parseSpecFile(source).tests;
|
|
127
171
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { BiDiCommands, BiDiEvents } from "../types/bidi.js";
|
|
2
2
|
import { type EventName, type Subscription, type SubscribeOptions } from "./subscriptions.js";
|
|
3
|
-
/** Time (ms) a command may wait for its reply before it fails with code "timeout" */
|
|
4
|
-
export declare const DEFAULT_COMMAND_TIMEOUT = 30000;
|
|
5
3
|
export interface ConnectorOptions {
|
|
6
4
|
/** @default DEFAULT_COMMAND_TIMEOUT */
|
|
7
5
|
commandTimeout?: number;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import EventEmitter from "node:events";
|
|
2
|
+
import { DEFAULT_COMMAND_TIMEOUT } from "../config/defaults.js";
|
|
2
3
|
import logger from "../logger/index.js";
|
|
3
4
|
import { WaitTimeoutError } from "../wait/wait-until.js";
|
|
4
5
|
import { BiDiError } from "./bidi-error.js";
|
|
5
6
|
import { forLog } from "./log-redaction.js";
|
|
6
7
|
import { SubscriptionManager, } from "./subscriptions.js";
|
|
7
|
-
/** Time (ms) a command may wait for its reply before it fails with code "timeout" */
|
|
8
|
-
export const DEFAULT_COMMAND_TIMEOUT = 30000;
|
|
9
8
|
/**
|
|
10
9
|
* The connection to the browser is gone (the browser exited or was closed, or the socket dropped). Commands that
|
|
11
10
|
* were waiting fail with it, and so does every command sent afterwards: a closed socket would swallow them silently.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itmetsam/samurai-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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": {
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"types": "./dist/project/index.d.ts",
|
|
49
49
|
"default": "./dist/project/index.js"
|
|
50
50
|
},
|
|
51
|
+
"./capabilities": {
|
|
52
|
+
"types": "./dist/capabilities.d.ts",
|
|
53
|
+
"default": "./dist/capabilities.js"
|
|
54
|
+
},
|
|
51
55
|
"./package.json": "./package.json"
|
|
52
56
|
},
|
|
53
57
|
"scripts": {
|
|
@@ -55,7 +59,7 @@
|
|
|
55
59
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/copy-types.mjs",
|
|
56
60
|
"prepack": "npm run build",
|
|
57
61
|
"test": "SAMURAI_LOG_LEVEL=${SAMURAI_LOG_LEVEL:-warn} tsx --import ./scripts/test-tmp.mjs --test --test-timeout=10000 \"src/**/*.test.ts\"",
|
|
58
|
-
"test:browser": "SAMURAI_LOG_LEVEL=${SAMURAI_LOG_LEVEL:-warn} tsx --import ./scripts/test-tmp.mjs --test --test-concurrency=1 --test-timeout=60000 \"src/**/*.browser-test.ts\"",
|
|
62
|
+
"test:browser": "SAMURAI_LOG_LEVEL=${SAMURAI_LOG_LEVEL:-warn} tsx --import ./scripts/test-tmp.mjs --test --test-concurrency=1 --test-timeout=60000 ${SAMURAI_TEST_SHARD:+--test-shard=$SAMURAI_TEST_SHARD} \"src/**/*.browser-test.ts\"",
|
|
59
63
|
"test:browser:chrome": "SAMURAI_TEST_BROWSER=chrome npm run test:browser",
|
|
60
64
|
"test:cli": "tsx --import ./scripts/test-tmp.mjs --test --test-concurrency=1 \"src/**/*.cli-test.ts\""
|
|
61
65
|
},
|
|
File without changes
|
|
File without changes
|