@itmetsam/samurai-framework 0.10.0 → 0.12.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 +3 -4
- package/dist/assert/assertion-error.d.ts +1 -1
- package/dist/assert/expect.d.ts +5 -50
- package/dist/assert/expect.js +5 -182
- package/dist/assert/locator-assertions.d.ts +22 -0
- package/dist/assert/locator-assertions.js +61 -0
- package/dist/assert/pending-assertions.d.ts +7 -0
- package/dist/assert/pending-assertions.js +40 -0
- package/dist/assert/text-match.d.ts +4 -0
- package/dist/assert/text-match.js +11 -0
- package/dist/assert/value-assertions.d.ts +23 -0
- package/dist/assert/value-assertions.js +82 -0
- package/dist/browser/browser-context.d.ts +0 -1
- package/dist/browser/browser-context.js +13 -5
- package/dist/browser/browser-finder.js +5 -9
- package/dist/browser/browser.d.ts +3 -31
- package/dist/browser/browser.js +36 -219
- package/dist/browser/chrome-launch.d.ts +2 -1
- package/dist/browser/dialog-handling.d.ts +32 -0
- package/dist/browser/dialog-handling.js +85 -0
- package/dist/browser/document-watcher.d.ts +44 -0
- package/dist/browser/document-watcher.js +160 -0
- package/dist/browser/download-folders.d.ts +0 -1
- package/dist/browser/download-folders.js +7 -15
- package/dist/browser/download.js +5 -10
- package/dist/browser/downloads-dir.js +2 -2
- package/dist/browser/emit.d.ts +7 -0
- package/dist/browser/emit.js +16 -0
- package/dist/browser/emulation.d.ts +1 -1
- package/dist/browser/emulation.js +54 -18
- package/dist/browser/file-chooser.js +4 -11
- package/dist/browser/history.d.ts +6 -0
- package/dist/browser/history.js +89 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +2 -0
- package/dist/browser/init-script.d.ts +2 -0
- package/dist/browser/init-script.js +16 -0
- package/dist/browser/launch-firefox.d.ts +20 -0
- package/dist/browser/launch-firefox.js +66 -0
- package/dist/browser/launch-flags.d.ts +18 -0
- package/dist/browser/launch-flags.js +100 -0
- package/dist/browser/lazy.d.ts +21 -0
- package/dist/browser/lazy.js +44 -0
- package/dist/browser/page-events.d.ts +44 -0
- package/dist/browser/page-events.js +58 -0
- package/dist/browser/page-logs.js +2 -9
- package/dist/browser/page-navigation.d.ts +58 -0
- package/dist/browser/page-navigation.js +108 -0
- package/dist/browser/page-network.d.ts +69 -0
- package/dist/browser/page-network.js +163 -0
- package/dist/browser/page-settings.d.ts +35 -0
- package/dist/browser/page-settings.js +51 -0
- package/dist/browser/page-transfers.d.ts +36 -0
- package/dist/browser/page-transfers.js +50 -0
- package/dist/browser/page.d.ts +39 -154
- package/dist/browser/page.js +134 -758
- package/dist/browser/pdf.d.ts +1 -1
- package/dist/browser/session.d.ts +16 -0
- package/dist/browser/session.js +32 -0
- package/dist/browser/viewport.d.ts +19 -0
- package/dist/browser/viewport.js +72 -0
- package/dist/browser/warm-up.d.ts +1 -1
- package/dist/browser/warm-up.js +2 -1
- package/dist/browsers/index.d.ts +1 -1
- package/dist/browsers/index.js +1 -1
- package/dist/browsers/pins.d.ts +0 -2
- package/dist/browsers/pins.js +0 -2
- package/dist/browsers/store.d.ts +0 -2
- package/dist/browsers/store.js +1 -2
- package/dist/cli/args.d.ts +13 -6
- package/dist/cli/args.js +13 -10
- package/dist/cli/browsers.d.ts +1 -2
- package/dist/cli/browsers.js +2 -2
- package/dist/cli/console-reporter.js +3 -2
- package/dist/cli/flow-reporter.js +2 -1
- package/dist/cli/flow.d.ts +1 -2
- package/dist/cli/flow.js +25 -22
- package/dist/cli/init.js +2 -7
- package/dist/cli/io.d.ts +10 -0
- package/dist/cli/io.js +1 -0
- package/dist/cli/main.d.ts +3 -10
- package/dist/cli/main.js +10 -143
- package/dist/cli/paint.d.ts +2 -0
- package/dist/cli/paint.js +4 -0
- package/dist/cli/record.d.ts +4 -0
- package/dist/cli/record.js +93 -0
- package/dist/cli/usage.d.ts +1 -0
- package/dist/cli/usage.js +58 -0
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.js +7 -0
- package/dist/config/browsers.d.ts +11 -0
- package/dist/config/browsers.js +32 -0
- package/dist/config/config.js +4 -1
- package/dist/config/mask.d.ts +1 -1
- package/dist/config/mask.js +7 -2
- package/dist/config/run-settings.d.ts +1 -2
- package/dist/config/run-settings.js +1 -6
- package/dist/config/timeouts.d.ts +2 -0
- package/dist/config/timeouts.js +13 -0
- package/dist/config/workers.d.ts +14 -0
- package/dist/config/workers.js +29 -0
- package/dist/flows/run/branch-context.d.ts +14 -0
- package/dist/flows/run/branch-context.js +35 -0
- package/dist/flows/run/handlers/condition.d.ts +1 -1
- package/dist/flows/run/handlers/end.d.ts +1 -1
- package/dist/flows/run/handlers/group.d.ts +1 -1
- package/dist/flows/run/handlers/index.d.ts +2 -2
- package/dist/flows/run/handlers/parallel.d.ts +1 -1
- package/dist/flows/run/handlers/start.d.ts +1 -1
- package/dist/flows/run/handlers/support.d.ts +3 -27
- package/dist/flows/run/handlers/test.d.ts +1 -1
- package/dist/flows/run/handlers/types.d.ts +27 -0
- package/dist/flows/run/handlers/types.js +1 -0
- package/dist/flows/run/index.d.ts +1 -1
- package/dist/flows/run/prepare-flow.d.ts +14 -0
- package/dist/flows/run/prepare-flow.js +44 -0
- package/dist/flows/run/project.d.ts +33 -2
- package/dist/flows/run/project.js +139 -57
- package/dist/flows/run/run.d.ts +3 -4
- package/dist/flows/run/run.js +23 -193
- package/dist/flows/run/walker.d.ts +56 -0
- package/dist/flows/run/walker.js +225 -0
- package/dist/flows/steps/catalog.d.ts +1 -1
- package/dist/flows/steps/handler.d.ts +1 -1
- package/dist/flows/steps/set.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/locator/actionability.d.ts +33 -0
- package/dist/locator/actionability.js +104 -0
- package/dist/locator/chain-resolver.d.ts +20 -0
- package/dist/locator/chain-resolver.js +102 -0
- package/dist/locator/document-swap.d.ts +1 -0
- package/dist/locator/document-swap.js +11 -0
- package/dist/locator/element-state.d.ts +3 -1
- package/dist/locator/element-state.js +11 -3
- package/dist/locator/file-actions.d.ts +35 -0
- package/dist/locator/file-actions.js +55 -0
- package/dist/{script/helpers.js → locator/helper-realm.js} +2 -2
- package/dist/locator/input-actions.d.ts +18 -0
- package/dist/locator/input-actions.js +80 -0
- package/dist/locator/label-locator.d.ts +1 -1
- package/dist/locator/label-locator.js +5 -12
- package/dist/locator/locator.d.ts +14 -37
- package/dist/locator/locator.js +68 -424
- package/dist/locator/page-scripts.d.ts +16 -0
- package/dist/locator/page-scripts.js +54 -0
- package/dist/locator/page-search.d.ts +10 -0
- package/dist/locator/page-search.js +19 -0
- package/dist/locator/selector-errors.d.ts +0 -4
- package/dist/locator/selector-errors.js +0 -7
- package/dist/locator/selector.d.ts +14 -13
- package/dist/locator/selector.js +10 -16
- package/dist/locator/text-locator.d.ts +1 -1
- package/dist/locator/text-locator.js +5 -9
- package/dist/logger/index.d.ts +6 -0
- package/dist/logger/index.js +14 -7
- package/dist/network/bidi-wire.d.ts +10 -0
- package/dist/network/bidi-wire.js +38 -0
- package/dist/network/intercept.d.ts +30 -0
- package/dist/network/intercept.js +130 -0
- package/dist/network/network-tracker.d.ts +10 -47
- package/dist/network/network-tracker.js +34 -68
- package/dist/network/network-types.d.ts +33 -0
- package/dist/network/network-types.js +1 -0
- package/dist/network/network-wait.d.ts +7 -2
- package/dist/network/network-wait.js +14 -4
- package/dist/network/response.d.ts +1 -1
- package/dist/network/response.js +1 -1
- package/dist/network/route.d.ts +92 -0
- package/dist/network/route.js +142 -0
- package/dist/network/router.d.ts +6 -91
- package/dist/network/router.js +25 -258
- package/dist/recorder/expectation.d.ts +5 -0
- package/dist/recorder/expectation.js +20 -0
- package/dist/recorder/files-recorder.d.ts +30 -0
- package/dist/recorder/files-recorder.js +88 -0
- package/dist/recorder/normalise.d.ts +17 -6
- package/dist/recorder/normalise.js +96 -91
- package/dist/recorder/options.d.ts +56 -0
- package/dist/recorder/options.js +1 -0
- package/dist/recorder/page-messages.d.ts +35 -0
- package/dist/recorder/page-messages.js +26 -0
- package/dist/recorder/ranking.js +1 -0
- package/dist/recorder/realms.d.ts +6 -0
- package/dist/recorder/realms.js +13 -0
- package/dist/recorder/recorder.d.ts +10 -74
- package/dist/recorder/recorder.js +39 -199
- package/dist/recorder/session-browser.d.ts +22 -0
- package/dist/recorder/session-browser.js +21 -0
- package/dist/recorder/session-secrets.d.ts +8 -0
- package/dist/recorder/session-secrets.js +45 -0
- package/dist/recorder/session.d.ts +5 -14
- package/dist/recorder/session.js +22 -120
- package/dist/recorder/spec-source.d.ts +39 -0
- package/dist/recorder/spec-source.js +84 -0
- package/dist/recorder/toolbar/action-guard.d.ts +21 -0
- package/dist/recorder/toolbar/action-guard.js +43 -0
- package/dist/recorder/toolbar/actions/assert.d.ts +4 -0
- package/dist/recorder/toolbar/actions/assert.js +52 -0
- package/dist/recorder/toolbar/actions/insert.d.ts +6 -0
- package/dist/recorder/toolbar/actions/insert.js +93 -0
- package/dist/recorder/toolbar/actions/pick.d.ts +8 -0
- package/dist/recorder/toolbar/actions/pick.js +26 -0
- package/dist/recorder/toolbar/actions/reply.d.ts +7 -0
- package/dist/recorder/toolbar/actions/reply.js +10 -0
- package/dist/recorder/toolbar/controller-fixture.d.ts +47 -0
- package/dist/recorder/toolbar/controller-fixture.js +129 -0
- package/dist/recorder/toolbar/controller.d.ts +12 -78
- package/dist/recorder/toolbar/controller.js +35 -247
- package/dist/recorder/toolbar/inspect.d.ts +1 -3
- package/dist/recorder/toolbar/inspect.js +2 -2
- package/dist/recorder/toolbar/page-scope.d.ts +19 -0
- package/dist/recorder/toolbar/page-scope.js +43 -0
- package/dist/recorder/toolbar/protocol.d.ts +2 -1
- package/dist/recorder/toolbar/source/attach.d.ts +2 -0
- package/dist/recorder/toolbar/source/attach.js +41 -0
- package/dist/recorder/toolbar/source/dom.d.ts +2 -0
- package/dist/recorder/toolbar/source/dom.js +47 -0
- package/dist/recorder/toolbar/source/drag.d.ts +2 -0
- package/dist/recorder/toolbar/source/drag.js +32 -0
- package/dist/recorder/toolbar/source/events-page.d.ts +2 -0
- package/dist/recorder/toolbar/source/events-page.js +67 -0
- package/dist/recorder/toolbar/source/events-toolbar.d.ts +2 -0
- package/dist/recorder/toolbar/source/events-toolbar.js +35 -0
- package/dist/recorder/toolbar/source/fields.d.ts +2 -0
- package/dist/recorder/toolbar/source/fields.js +44 -0
- package/dist/recorder/toolbar/source/handlers.d.ts +2 -0
- package/dist/recorder/toolbar/source/handlers.js +134 -0
- package/dist/recorder/toolbar/source/names.d.ts +2 -0
- package/dist/recorder/toolbar/source/names.js +12 -0
- package/dist/recorder/toolbar/source/picking.d.ts +2 -0
- package/dist/recorder/toolbar/source/picking.js +72 -0
- package/dist/recorder/toolbar/source/placement.d.ts +2 -0
- package/dist/recorder/toolbar/source/placement.js +45 -0
- package/dist/recorder/toolbar/source/recorder-side.d.ts +2 -0
- package/dist/recorder/toolbar/source/recorder-side.js +54 -0
- package/dist/recorder/toolbar/source/setup.d.ts +2 -0
- package/dist/recorder/toolbar/source/setup.js +50 -0
- package/dist/recorder/toolbar/source/views-panels.d.ts +2 -0
- package/dist/recorder/toolbar/source/views-panels.js +150 -0
- package/dist/recorder/toolbar/source/views-rail.d.ts +2 -0
- package/dist/recorder/toolbar/source/views-rail.js +40 -0
- package/dist/recorder/toolbar/source/views-render.d.ts +2 -0
- package/dist/recorder/toolbar/source/views-render.js +48 -0
- package/dist/recorder/toolbar/source.js +30 -856
- package/dist/recorder/toolbar/types.d.ts +70 -0
- package/dist/recorder/toolbar/types.js +1 -0
- package/dist/recorder/toolbar-bridge.d.ts +43 -0
- package/dist/recorder/toolbar-bridge.js +106 -0
- package/dist/runner/browsers.d.ts +0 -12
- package/dist/runner/browsers.js +1 -33
- package/dist/runner/options.d.ts +31 -0
- package/dist/runner/options.js +1 -0
- package/dist/runner/pooled-run.d.ts +43 -0
- package/dist/runner/pooled-run.js +75 -0
- package/dist/runner/ports.d.ts +2 -0
- package/dist/runner/ports.js +2 -0
- package/dist/runner/registry.d.ts +1 -1
- package/dist/runner/registry.js +1 -1
- package/dist/runner/reporter.d.ts +31 -10
- package/dist/runner/reporter.js +39 -6
- package/dist/runner/run-test.d.ts +16 -0
- package/dist/runner/run-test.js +178 -0
- package/dist/runner/run.d.ts +5 -3
- package/dist/runner/run.js +28 -29
- package/dist/runner/select.d.ts +24 -0
- package/dist/runner/select.js +77 -0
- package/dist/runner/test-dir.d.ts +13 -0
- package/dist/runner/test-dir.js +27 -0
- package/dist/runner/test-runner.d.ts +25 -56
- package/dist/runner/test-runner.js +81 -270
- package/dist/runner/worker-pool.d.ts +67 -0
- package/dist/runner/worker-pool.js +275 -0
- package/dist/runner/worker-process.d.ts +6 -0
- package/dist/runner/worker-process.js +54 -0
- package/dist/runner/worker-protocol.d.ts +67 -0
- package/dist/runner/worker-protocol.js +1 -0
- package/dist/runner/worker-session.d.ts +7 -0
- package/dist/runner/worker-session.js +60 -0
- package/dist/runner/worker.d.ts +26 -0
- package/dist/runner/worker.js +121 -0
- package/dist/runner/workers-option.d.ts +15 -0
- package/dist/runner/workers-option.js +22 -0
- package/dist/script/call-function.d.ts +1 -9
- package/dist/script/call-function.js +2 -19
- package/dist/script/element-handle.d.ts +1 -2
- package/dist/script/element-handle.js +1 -2
- package/dist/script/serialize.d.ts +3 -12
- package/dist/script/serialize.js +53 -62
- package/dist/steps/parse/call.d.ts +3 -0
- package/dist/steps/parse/call.js +81 -0
- package/dist/steps/parse/expectation.d.ts +5 -0
- package/dist/steps/parse/expectation.js +71 -0
- package/dist/steps/parse/file-entry.d.ts +4 -0
- package/dist/steps/parse/file-entry.js +74 -0
- package/dist/steps/parse/literals.d.ts +4 -0
- package/dist/steps/parse/literals.js +28 -0
- package/dist/steps/parse/step.d.ts +4 -0
- package/dist/steps/parse/step.js +81 -0
- package/dist/steps/parse.js +2 -323
- package/dist/transport/bidi-connection.d.ts +4 -15
- package/dist/transport/bidi-connection.js +9 -63
- package/dist/transport/log-redaction.d.ts +13 -0
- package/dist/transport/log-redaction.js +51 -0
- package/dist/transport/subscriptions.js +18 -13
- package/dist/transport/unsupported.d.ts +7 -0
- package/dist/transport/unsupported.js +13 -0
- package/dist/types/bidi-modules/browser.d.ts +1 -12
- package/dist/types/bidi-modules/browsing-context.d.ts +8 -18
- package/dist/types/bidi-modules/emulation.d.ts +29 -21
- package/dist/types/bidi-modules/input.d.ts +1 -9
- package/dist/types/bidi-modules/network.d.ts +29 -24
- package/dist/types/bidi-modules/script.d.ts +0 -9
- package/dist/types/bidi-modules/session.d.ts +0 -8
- package/dist/types/bidi-modules/storage.d.ts +0 -5
- package/dist/types/bidi.d.ts +7 -37
- package/dist/types/config.d.ts +12 -0
- package/dist/types/test.d.ts +8 -3
- package/dist/wait/wait-until.d.ts +1 -5
- package/dist/wait/wait-until.js +7 -16
- package/package.json +3 -2
- package/dist/config/default.d.ts +0 -2
- package/dist/config/default.js +0 -3
- package/dist/types/bidi-modules/web-extensions.d.ts +0 -9
- package/dist/types/bidi-protocols/command.d.ts +0 -7
- package/dist/types/bidi-protocols/event.d.ts +0 -17
- /package/dist/{script/helpers.d.ts → locator/helper-realm.d.ts} +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Handler } from "./types.js";
|
|
2
2
|
export declare const group: Handler;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Handler } from "./
|
|
2
|
-
export type { Handler, HandlerRun, Outcome } from "./
|
|
1
|
+
import type { Handler } from "./types.js";
|
|
2
|
+
export type { Handler, HandlerRun, Outcome } from "./types.js";
|
|
3
3
|
/** The kinds a run can execute, by kind: the closed ones and every built-in step */
|
|
4
4
|
export declare const HANDLERS: Readonly<Record<string, Handler>>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { Handler } from "./
|
|
1
|
+
import type { Handler } from "./types.js";
|
|
2
2
|
export declare const start: Handler;
|
|
@@ -1,30 +1,6 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { NodeResult, NodeTest } from "../events.js";
|
|
5
|
-
/** What a handler can use of the run */
|
|
6
|
-
export interface HandlerRun {
|
|
7
|
-
flow: FlowFile;
|
|
8
|
-
environment: {
|
|
9
|
-
name: string;
|
|
10
|
-
variables: Record<string, unknown>;
|
|
11
|
-
};
|
|
12
|
-
context: ExpressionContext;
|
|
13
|
-
nodeTests: Record<string, NodeTest[]>;
|
|
14
|
-
/** The browsers of the nodes that have their own (a Group node's group); the others use the project's */
|
|
15
|
-
nodeBrowsers?: Record<string, SupportedBrowser[]>;
|
|
16
|
-
signal: AbortSignal;
|
|
17
|
-
runTests: (tests: NodeTest[], onEvent: (e: RunEvent) => void, browsers?: SupportedBrowser[]) => Promise<"passed" | "failed" | "cancelled">;
|
|
18
|
-
sleep: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
19
|
-
onTestEvent: (nodeId: string, e: RunEvent) => void;
|
|
20
|
-
/** Definitions of kinds core doesn't have (steps), for expression scopes */
|
|
21
|
-
nodes: readonly AnyNodeDefinition[];
|
|
22
|
-
log: (nodeId: string, level: "info" | "warn" | "error", text: string) => void;
|
|
23
|
-
}
|
|
24
|
-
/** What a handler decides; the walker adds timing */
|
|
25
|
-
export type Outcome = Omit<NodeResult, "durationMs"> | "cancelled";
|
|
26
|
-
/** Runs one kind of node. A `branches` node names the branch it takes in `branch` */
|
|
27
|
-
export type Handler = (node: FlowNodeModel, run: HandlerRun) => Promise<Outcome>;
|
|
1
|
+
import { type FlowNodeModel } from "../../core/index.js";
|
|
2
|
+
import type { NodeTest } from "../events.js";
|
|
3
|
+
import type { HandlerRun, Outcome } from "./types.js";
|
|
28
4
|
export declare const fail: (e: unknown) => Outcome;
|
|
29
5
|
/** Runs `list` for the node and turns the result into an outcome */
|
|
30
6
|
export declare function runNodeTests(node: FlowNodeModel, run: HandlerRun, list: NodeTest[]): Promise<Outcome>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Handler } from "./types.js";
|
|
2
2
|
export declare const test: Handler;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AnyNodeDefinition, ExpressionContext, FlowFile, FlowNodeModel } from "../../core/index.js";
|
|
2
|
+
import type { RunEvent } from "../../../runner/reporter.js";
|
|
3
|
+
import type { SupportedBrowser } from "../../../types/browser.js";
|
|
4
|
+
import type { NodeResult, NodeTest } from "../events.js";
|
|
5
|
+
/** What a handler can use of the run */
|
|
6
|
+
export interface HandlerRun {
|
|
7
|
+
flow: FlowFile;
|
|
8
|
+
environment: {
|
|
9
|
+
name: string;
|
|
10
|
+
variables: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
context: ExpressionContext;
|
|
13
|
+
nodeTests: Record<string, NodeTest[]>;
|
|
14
|
+
/** The browsers of the nodes that have their own (a Group node's group); the others use the project's */
|
|
15
|
+
nodeBrowsers?: Record<string, SupportedBrowser[]>;
|
|
16
|
+
signal: AbortSignal;
|
|
17
|
+
runTests: (tests: NodeTest[], onEvent: (e: RunEvent) => void, browsers?: SupportedBrowser[]) => Promise<"passed" | "failed" | "cancelled">;
|
|
18
|
+
sleep: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
19
|
+
onTestEvent: (nodeId: string, e: RunEvent) => void;
|
|
20
|
+
/** Definitions of kinds core doesn't have (steps), for expression scopes */
|
|
21
|
+
nodes: readonly AnyNodeDefinition[];
|
|
22
|
+
log: (nodeId: string, level: "info" | "warn" | "error", text: string) => void;
|
|
23
|
+
}
|
|
24
|
+
/** What a handler decides; the walker adds timing */
|
|
25
|
+
export type Outcome = Omit<NodeResult, "durationMs"> | "cancelled";
|
|
26
|
+
/** Runs one kind of node. A `branches` node names the branch it takes in `branch` */
|
|
27
|
+
export type Handler = (node: FlowNodeModel, run: HandlerRun) => Promise<Outcome>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -6,4 +6,4 @@ export { runFlow, type RunFlowOptions } from "./run.js";
|
|
|
6
6
|
export { FLOW_SUFFIX, flowsDir, listFlows, readFlow, readFlowPath, readFlows, } from "./files.js";
|
|
7
7
|
export * from "./report.js";
|
|
8
8
|
export { projectSteps, type StepSet } from "../steps/set.js";
|
|
9
|
-
export { FlowCheckError, checkFlowInProject, chooseEnvironment, runFlowInProject, type RunFlowInProjectOptions, } from "./project.js";
|
|
9
|
+
export { FlowCheckError, checkFlowInProject, chooseEnvironment, runFlowInProject, type FlowRunOptions, type RunFlowInProjectOptions, } from "./project.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AnyNodeDefinition, type FlowFile } from "../core/index.js";
|
|
2
|
+
import type { Handler } from "./handlers/index.js";
|
|
3
|
+
/** The flow's shape can't be walked (no Start, a node reached twice, a branch that never meets): the run ends with this message */
|
|
4
|
+
export declare class ShapeError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export declare const shapeError: (message: string) => ShapeError;
|
|
7
|
+
/** Waits `ms`, or rejects at once when `signal` aborts */
|
|
8
|
+
export declare const defaultSleep: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
9
|
+
/** Whether a node of this kind has a list of branches that is only known at run time (a Parallel node) */
|
|
10
|
+
export declare const dynamicBranches: (def: AnyNodeDefinition) => boolean;
|
|
11
|
+
/** The definition of a kind: the project's own steps first, then the built-in kinds; undefined for a kind nobody knows */
|
|
12
|
+
export declare function definitionOf(nodes: readonly AnyNodeDefinition[], kind: string): AnyNodeDefinition | undefined;
|
|
13
|
+
/** Throws when the flow has a step or branching node whose kind has no handler: the run would not know what to do */
|
|
14
|
+
export declare function assertRunnable(flow: FlowFile, nodes: readonly AnyNodeDefinition[], handlers: Readonly<Record<string, Handler>>): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { nodeDef, } from "../core/index.js";
|
|
2
|
+
/** The flow's shape can't be walked (no Start, a node reached twice, a branch that never meets): the run ends with this message */
|
|
3
|
+
export class ShapeError extends Error {
|
|
4
|
+
}
|
|
5
|
+
export const shapeError = (message) => new ShapeError(`This flow's shape can't run: ${message}`);
|
|
6
|
+
/** Waits `ms`, or rejects at once when `signal` aborts */
|
|
7
|
+
export const defaultSleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
8
|
+
if (signal.aborted)
|
|
9
|
+
return reject(new Error("aborted"));
|
|
10
|
+
const onAbort = () => {
|
|
11
|
+
clearTimeout(timer);
|
|
12
|
+
reject(new Error("aborted"));
|
|
13
|
+
};
|
|
14
|
+
const timer = setTimeout(() => {
|
|
15
|
+
signal.removeEventListener("abort", onAbort);
|
|
16
|
+
resolve();
|
|
17
|
+
}, ms);
|
|
18
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
19
|
+
});
|
|
20
|
+
/** Whether a node of this kind has a list of branches that is only known at run time (a Parallel node) */
|
|
21
|
+
export const dynamicBranches = (def) => def.shape === "branches" && !!def.branches && !Array.isArray(def.branches);
|
|
22
|
+
/** The definition of a kind: the project's own steps first, then the built-in kinds; undefined for a kind nobody knows */
|
|
23
|
+
export function definitionOf(nodes, kind) {
|
|
24
|
+
const own = nodes.find((d) => d.kind === kind);
|
|
25
|
+
if (own)
|
|
26
|
+
return own;
|
|
27
|
+
try {
|
|
28
|
+
return nodeDef(kind);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Throws when the flow has a step or branching node whose kind has no handler: the run would not know what to do */
|
|
35
|
+
export function assertRunnable(flow, nodes, handlers) {
|
|
36
|
+
const problems = flow.nodes
|
|
37
|
+
.map((n) => ({ n, def: definitionOf(nodes, n.kind) }))
|
|
38
|
+
.filter(({ n, def }) => def &&
|
|
39
|
+
(def.shape === "step" || def.shape === "branches") &&
|
|
40
|
+
!handlers[n.kind])
|
|
41
|
+
.map(({ def }) => `${def.label} can't run yet.`);
|
|
42
|
+
if (problems.length)
|
|
43
|
+
throw new Error(`This flow can't run: ${[...new Set(problems)].join(" ")}`);
|
|
44
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type FlowFile, type FlowProblem } from "../core/index.js";
|
|
2
|
+
import { type ResolvedGroup } from "../../runner/groups.js";
|
|
2
3
|
import { type ProjectOptions } from "../../runner/project.js";
|
|
3
4
|
import { runTests } from "../../runner/run.js";
|
|
5
|
+
import { WorkerPool, type PoolOptions } from "../../runner/worker-pool.js";
|
|
4
6
|
import type { SamuraiTestConfig } from "../../types/config.js";
|
|
5
|
-
import type { FlowEvent, FlowSummary } from "./events.js";
|
|
7
|
+
import type { FlowEvent, FlowSummary, NodeTest } from "./events.js";
|
|
8
|
+
import type { SupportedBrowser } from "../../types/browser.js";
|
|
6
9
|
/** The flow has errors; nothing was run */
|
|
7
10
|
export declare class FlowCheckError extends Error {
|
|
8
11
|
readonly problems: FlowProblem[];
|
|
@@ -20,13 +23,39 @@ export interface RunFlowInProjectOptions extends ProjectOptions {
|
|
|
20
23
|
/** `"fail"` (default): a flow with a node that can't run is refused. `"skip"`: those nodes are skipped. */
|
|
21
24
|
unsupported?: "fail" | "skip";
|
|
22
25
|
port?: number;
|
|
26
|
+
/**
|
|
27
|
+
* How many worker processes the tests of the whole run share: a number, or a percentage like `"50%"`. Unset
|
|
28
|
+
* takes `SAMURAI_WORKERS` (`workersEnv`), then the config's `workers`, then half the CPUs. 1 runs each Test
|
|
29
|
+
* and Group node through `runTests` in this process; more starts one pool that every node, and every branch
|
|
30
|
+
* of a Parallel node, takes its workers from
|
|
31
|
+
*/
|
|
32
|
+
workers?: number | string;
|
|
33
|
+
/** The value of `SAMURAI_WORKERS`, when set */
|
|
34
|
+
workersEnv?: string;
|
|
35
|
+
/** @internal Replaces the worker pool (tests) */
|
|
36
|
+
createPool?: (options: PoolOptions) => Pick<WorkerPool, "run" | "dispose">;
|
|
23
37
|
/** @internal Replaces the runner of each Test and Group node (tests) */
|
|
24
38
|
testRunner?: typeof runTests;
|
|
25
39
|
/** @internal */
|
|
26
40
|
sleep?: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
27
41
|
}
|
|
42
|
+
/** What `runFlowInProject` takes when the flow itself is given separately: everything but `flow` and `flowId` */
|
|
43
|
+
export type FlowRunOptions = Omit<RunFlowInProjectOptions, "flow" | "flowId">;
|
|
28
44
|
/** The environment: the option, else the flow's `envDefault` (when the project has it), else the config's default, else the first, else "default" */
|
|
29
45
|
export declare function chooseEnvironment(config: SamuraiTestConfig, flow: FlowFile, option?: string): string;
|
|
46
|
+
/** A test of the project as flows see it */
|
|
47
|
+
interface ProjectTest {
|
|
48
|
+
id: string;
|
|
49
|
+
file: string;
|
|
50
|
+
name: string;
|
|
51
|
+
/** The spec file relative to `srcDir`, with `/` separators */
|
|
52
|
+
relative: string;
|
|
53
|
+
}
|
|
54
|
+
/** The tests, and the browsers, of each Test and Group node of a flow; a Test node uses the project's browsers */
|
|
55
|
+
export declare function nodeTestsOf(flow: FlowFile, tests: Pick<ProjectTest, "id" | "file" | "name">[], groups: Pick<ResolvedGroup, "name" | "testIds" | "browsers">[]): {
|
|
56
|
+
nodeTests: Record<string, NodeTest[]>;
|
|
57
|
+
nodeBrowsers: Record<string, SupportedBrowser[]>;
|
|
58
|
+
};
|
|
30
59
|
/**
|
|
31
60
|
* Checks a flow against the project without running it: its tests, groups and environment
|
|
32
61
|
* variables, and which kinds can run. Returns the flow (with keys) and every problem, warnings included.
|
|
@@ -38,6 +67,8 @@ export declare function checkFlowInProject(options: Pick<RunFlowInProjectOptions
|
|
|
38
67
|
/**
|
|
39
68
|
* Checks and runs a flow of a project: loads its config, lists its tests and groups, refuses to start
|
|
40
69
|
* when `checkFlow` finds errors (`FlowCheckError`), then walks the flow; each Test and Group node runs
|
|
41
|
-
* its tests through `runTests`, one after the other
|
|
70
|
+
* its tests through `runTests`, one after the other, or on one shared worker pool when `workers` is above 1.
|
|
71
|
+
* One at a time per process.
|
|
42
72
|
*/
|
|
43
73
|
export declare function runFlowInProject(options: RunFlowInProjectOptions): Promise<FlowSummary>;
|
|
74
|
+
export {};
|
|
@@ -2,9 +2,15 @@ import path from "node:path";
|
|
|
2
2
|
import { projectConfig } from "../../config/config.js";
|
|
3
3
|
import { checkFlow, withKeys, } from "../core/index.js";
|
|
4
4
|
import { DEFAULT_SRC_DIR, realPath, resolveGroups, testId, toPosix, } from "../../runner/groups.js";
|
|
5
|
+
import logger from "../../logger/index.js";
|
|
6
|
+
import { resolveWorkers } from "../../runner/workers-option.js";
|
|
5
7
|
import { withProject } from "../../runner/project.js";
|
|
8
|
+
import { browsersFor } from "../../runner/browsers.js";
|
|
9
|
+
import { DEFAULT_PORT } from "../../runner/ports.js";
|
|
6
10
|
import { runTests } from "../../runner/run.js";
|
|
7
11
|
import TestRunner from "../../runner/test-runner.js";
|
|
12
|
+
import { WorkerPool } from "../../runner/worker-pool.js";
|
|
13
|
+
import { processWorkerFactory } from "../../runner/worker-process.js";
|
|
8
14
|
import { readFlow } from "./files.js";
|
|
9
15
|
import { projectSteps } from "../steps/set.js";
|
|
10
16
|
import { HANDLERS } from "./handlers/index.js";
|
|
@@ -17,16 +23,66 @@ export class FlowCheckError extends Error {
|
|
|
17
23
|
this.name = "FlowCheckError";
|
|
18
24
|
}
|
|
19
25
|
}
|
|
26
|
+
/** Whether the project's config defines an environment of this name */
|
|
27
|
+
function hasEnvironment(config, name) {
|
|
28
|
+
return Object.prototype.hasOwnProperty.call(config.environments ?? {}, name);
|
|
29
|
+
}
|
|
20
30
|
/** The environment: the option, else the flow's `envDefault` (when the project has it), else the config's default, else the first, else "default" */
|
|
21
31
|
export function chooseEnvironment(config, flow, option) {
|
|
22
|
-
const names = Object.keys(config.environments ?? {});
|
|
23
32
|
if (option)
|
|
24
33
|
return option;
|
|
34
|
+
const names = Object.keys(config.environments ?? {});
|
|
25
35
|
if (flow.envDefault && names.includes(flow.envDefault))
|
|
26
36
|
return flow.envDefault;
|
|
27
37
|
return config.defaultEnvironment ?? names[0] ?? "default";
|
|
28
38
|
}
|
|
29
|
-
/**
|
|
39
|
+
/** The work items of a node: each test in each browser, the browsers one after the other */
|
|
40
|
+
function itemsOf(tests, browsers) {
|
|
41
|
+
return browsers
|
|
42
|
+
.flatMap((browser) => tests.map((t) => ({ file: t.file, testName: t.name, browser })))
|
|
43
|
+
.map((item, index) => ({ ...item, index }));
|
|
44
|
+
}
|
|
45
|
+
/** Runs the tests of a node on the pool and reports them as a run would */
|
|
46
|
+
async function runOnPool(pool, items, onEvent, signal) {
|
|
47
|
+
const results = await pool.run(items, {
|
|
48
|
+
signal,
|
|
49
|
+
onEvent: (event) => onEvent({
|
|
50
|
+
type: event.type,
|
|
51
|
+
name: event.item.testName,
|
|
52
|
+
file: event.item.file,
|
|
53
|
+
browser: event.item.browser,
|
|
54
|
+
...(event.type === "test-end" && { result: event.result }),
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
if (signal.aborted)
|
|
58
|
+
return "cancelled";
|
|
59
|
+
return results.every((r) => r.status === "success") ? "passed" : "failed";
|
|
60
|
+
}
|
|
61
|
+
/** The tests, and the browsers, of each Test and Group node of a flow; a Test node uses the project's browsers */
|
|
62
|
+
export function nodeTestsOf(flow, tests, groups) {
|
|
63
|
+
const byId = new Map(tests.map((t) => [t.id, t]));
|
|
64
|
+
const nodeTests = {};
|
|
65
|
+
const nodeBrowsers = {};
|
|
66
|
+
for (const node of flow.nodes) {
|
|
67
|
+
const group = node.kind === "group"
|
|
68
|
+
? groups.find((g) => g.name === node.ref?.group)
|
|
69
|
+
: undefined;
|
|
70
|
+
const ids = node.kind === "test"
|
|
71
|
+
? [node.ref?.testId ?? ""]
|
|
72
|
+
: node.kind === "group"
|
|
73
|
+
? (group?.testIds ?? [])
|
|
74
|
+
: undefined;
|
|
75
|
+
if (!ids)
|
|
76
|
+
continue;
|
|
77
|
+
if (group)
|
|
78
|
+
nodeBrowsers[node.id] = group.browsers;
|
|
79
|
+
nodeTests[node.id] = ids.flatMap((id) => {
|
|
80
|
+
const t = byId.get(id);
|
|
81
|
+
return t ? [{ file: t.file, name: t.name }] : [];
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return { nodeTests, nodeBrowsers };
|
|
85
|
+
}
|
|
30
86
|
async function prepare(options) {
|
|
31
87
|
const projectDir = path.resolve(options.projectDir ?? process.cwd());
|
|
32
88
|
if (!options.flow && !options.flowId)
|
|
@@ -40,7 +96,7 @@ async function prepare(options) {
|
|
|
40
96
|
const environment = {
|
|
41
97
|
name,
|
|
42
98
|
variables: {
|
|
43
|
-
...(
|
|
99
|
+
...(hasEnvironment(config, name)
|
|
44
100
|
? config.environments[name].variables
|
|
45
101
|
: {}),
|
|
46
102
|
},
|
|
@@ -99,72 +155,98 @@ export async function checkFlowInProject(options) {
|
|
|
99
155
|
/**
|
|
100
156
|
* Checks and runs a flow of a project: loads its config, lists its tests and groups, refuses to start
|
|
101
157
|
* when `checkFlow` finds errors (`FlowCheckError`), then walks the flow; each Test and Group node runs
|
|
102
|
-
* its tests through `runTests`, one after the other
|
|
158
|
+
* its tests through `runTests`, one after the other, or on one shared worker pool when `workers` is above 1.
|
|
159
|
+
* One at a time per process.
|
|
103
160
|
*/
|
|
104
161
|
export async function runFlowInProject(options) {
|
|
105
162
|
const { projectDir, flow, unsupported, config, steps, name, environment, tests, groups, problems, } = await prepare(options);
|
|
106
163
|
const errors = problems.filter((p) => p.level === "error");
|
|
107
164
|
if (errors.length)
|
|
108
165
|
throw new FlowCheckError(errors);
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (node.kind === "group") {
|
|
122
|
-
const browsers = groups.find((g) => g.name === node.ref?.group)?.browsers;
|
|
123
|
-
if (browsers)
|
|
124
|
-
nodeBrowsers[node.id] = browsers;
|
|
125
|
-
}
|
|
126
|
-
nodeTests[node.id] = ids.flatMap((id) => {
|
|
127
|
-
const t = byId.get(id);
|
|
128
|
-
return t ? [{ file: t.file, name: t.name }] : [];
|
|
166
|
+
const { nodeTests, nodeBrowsers } = nodeTestsOf(flow, tests, groups);
|
|
167
|
+
const run = options.testRunner ?? runTests;
|
|
168
|
+
// An injected runner (tests) stays in this process unless the workers are asked for
|
|
169
|
+
const asked = options.workers !== undefined ||
|
|
170
|
+
Boolean(options.workersEnv) ||
|
|
171
|
+
config.workers !== undefined;
|
|
172
|
+
let workers = options.testRunner && options.workers === undefined
|
|
173
|
+
? 1
|
|
174
|
+
: resolveWorkers({
|
|
175
|
+
flag: options.workers,
|
|
176
|
+
env: options.workersEnv,
|
|
177
|
+
config: config.workers,
|
|
129
178
|
});
|
|
179
|
+
// A worker reads `samurai.config.ts` from the project folder: a config given as an object stays in this process
|
|
180
|
+
if (options.config !== undefined && !options.createPool && workers > 1) {
|
|
181
|
+
if (asked)
|
|
182
|
+
logger.warn("workers needs samurai.config.ts in the project folder; running on one worker");
|
|
183
|
+
workers = 1;
|
|
130
184
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
unsupported,
|
|
141
|
-
handlers: { ...HANDLERS, ...steps.handlers },
|
|
142
|
-
nodes: steps.nodes,
|
|
143
|
-
runTests: async ({ tests, onEvent, signal, browsers }) => {
|
|
144
|
-
const summary = await run({
|
|
185
|
+
const files = [
|
|
186
|
+
...new Set(Object.values(nodeTests).flatMap((list) => list.map((t) => t.file))),
|
|
187
|
+
];
|
|
188
|
+
// One pool for the whole run: the nodes, and the branches of a Parallel node, share its workers
|
|
189
|
+
const pool = workers > 1
|
|
190
|
+
? (options.createPool ?? ((o) => new WorkerPool(o)))({
|
|
191
|
+
workers,
|
|
192
|
+
factory: processWorkerFactory(),
|
|
193
|
+
init: {
|
|
145
194
|
projectDir,
|
|
146
|
-
config,
|
|
147
195
|
...(options.dataDir !== undefined && { dataDir: options.dataDir }),
|
|
148
|
-
|
|
149
|
-
...(Object.prototype.hasOwnProperty.call(config.environments ?? {}, name)
|
|
150
|
-
? { environment: name }
|
|
151
|
-
: {}),
|
|
152
|
-
...(options.headless !== undefined && { headless: options.headless }),
|
|
196
|
+
...(hasEnvironment(config, name) && { environment: name }),
|
|
153
197
|
...(options.timeout !== undefined && { timeout: options.timeout }),
|
|
154
198
|
...(options.expectTimeout !== undefined && {
|
|
155
199
|
expectTimeout: options.expectTimeout,
|
|
156
200
|
}),
|
|
157
|
-
...(options.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
201
|
+
...(options.headless !== undefined && {
|
|
202
|
+
headless: options.headless,
|
|
203
|
+
}),
|
|
204
|
+
files,
|
|
205
|
+
basePort: options.port ?? DEFAULT_PORT,
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
: undefined;
|
|
209
|
+
try {
|
|
210
|
+
return await runFlow({
|
|
211
|
+
flow,
|
|
212
|
+
nodeTests,
|
|
213
|
+
nodeBrowsers,
|
|
214
|
+
environment,
|
|
215
|
+
...(options.signal && { signal: options.signal }),
|
|
216
|
+
...(options.onEvent && { onEvent: options.onEvent }),
|
|
217
|
+
...(options.sleep && { sleep: options.sleep }),
|
|
218
|
+
unsupported,
|
|
219
|
+
handlers: { ...HANDLERS, ...steps.handlers },
|
|
220
|
+
nodes: steps.nodes,
|
|
221
|
+
runTests: async ({ tests, onEvent, signal, browsers }) => {
|
|
222
|
+
if (pool)
|
|
223
|
+
return runOnPool(pool, itemsOf(tests, browsers ?? browsersFor({ project: config.browsers })), onEvent, signal);
|
|
224
|
+
const summary = await run({
|
|
225
|
+
projectDir,
|
|
226
|
+
config,
|
|
227
|
+
...(options.dataDir !== undefined && { dataDir: options.dataDir }),
|
|
228
|
+
// The environment the expressions see, whenever the project defines it
|
|
229
|
+
...(hasEnvironment(config, name) ? { environment: name } : {}),
|
|
230
|
+
...(options.headless !== undefined && { headless: options.headless }),
|
|
231
|
+
...(options.timeout !== undefined && { timeout: options.timeout }),
|
|
232
|
+
...(options.expectTimeout !== undefined && {
|
|
233
|
+
expectTimeout: options.expectTimeout,
|
|
234
|
+
}),
|
|
235
|
+
...(options.port !== undefined && { port: options.port }),
|
|
236
|
+
...(browsers && { browsers }),
|
|
237
|
+
files: [...new Set(tests.map((t) => t.file))],
|
|
238
|
+
testNames: tests.map((t) => t.name),
|
|
239
|
+
reportPath: false,
|
|
240
|
+
signal,
|
|
241
|
+
onEvent,
|
|
242
|
+
});
|
|
243
|
+
if (signal.aborted)
|
|
244
|
+
return "cancelled";
|
|
245
|
+
return summary.status === "success" ? "passed" : "failed";
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
await pool?.dispose();
|
|
251
|
+
}
|
|
170
252
|
}
|
package/dist/flows/run/run.d.ts
CHANGED
|
@@ -39,9 +39,8 @@ export interface RunFlowOptions {
|
|
|
39
39
|
nodes?: readonly AnyNodeDefinition[];
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* fill order; an end stops. Branches meet again at `meetOf`.
|
|
42
|
+
* Runs a flow: sets up what its nodes share (expression context, handler access to the tests), walks it from
|
|
43
|
+
* Start (see `FlowWalker`) and reports how it ended. A flow whose shape can't run ends with an `error`; a flow
|
|
44
|
+
* with a kind that has no handler throws before it starts, unless `unsupported` is `"skip"`.
|
|
46
45
|
*/
|
|
47
46
|
export declare function runFlow(options: RunFlowOptions): Promise<FlowSummary>;
|