@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
package/dist/browser/pdf.d.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type BiDiConnector } from "../transport/bidi-connection.js";
|
|
2
|
+
/** session.new got no reply in time */
|
|
3
|
+
export declare class BrowserStartTimeoutError extends Error {
|
|
4
|
+
constructor(label: string, timeout: number);
|
|
5
|
+
}
|
|
6
|
+
/** Sends session.new with its own, longer timeout; `label` names the browser in the timeout error */
|
|
7
|
+
export declare function startSession(connector: Pick<BiDiConnector, "send">, label: string, commandTimeout: number | undefined): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Stops what a failed launch started. A browser left running holds the profile (the next launch
|
|
10
|
+
* fails with "already open") and keeps the test process alive.
|
|
11
|
+
*/
|
|
12
|
+
export declare function abandonLaunch(browserProc: {
|
|
13
|
+
kill(): boolean;
|
|
14
|
+
}, biDiConnector: {
|
|
15
|
+
kill(): void;
|
|
16
|
+
} | undefined): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DEFAULT_COMMAND_TIMEOUT, } from "../transport/bidi-connection.js";
|
|
2
|
+
import { BiDiError } from "../transport/bidi-error.js";
|
|
3
|
+
import { SESSION_CAPABILITIES } from "./session-capabilities.js";
|
|
4
|
+
/** session.new waits at least this long (ms): the first start after an install can take a while (macOS checks the new app) */
|
|
5
|
+
const SESSION_START_TIMEOUT = 120_000;
|
|
6
|
+
/** session.new got no reply in time */
|
|
7
|
+
export class BrowserStartTimeoutError extends Error {
|
|
8
|
+
constructor(label, timeout) {
|
|
9
|
+
super(`${label} did not finish starting within ${Math.round(timeout / 1000)}s. The first start after an install can be slow; run again.`);
|
|
10
|
+
this.name = "BrowserStartTimeoutError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Sends session.new with its own, longer timeout; `label` names the browser in the timeout error */
|
|
14
|
+
export async function startSession(connector, label, commandTimeout) {
|
|
15
|
+
const timeout = Math.max(commandTimeout ?? DEFAULT_COMMAND_TIMEOUT, SESSION_START_TIMEOUT);
|
|
16
|
+
try {
|
|
17
|
+
await connector.send("session.new", { capabilities: SESSION_CAPABILITIES }, { timeout });
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
if (err instanceof BiDiError && err.code === "timeout")
|
|
21
|
+
throw new BrowserStartTimeoutError(label, timeout);
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Stops what a failed launch started. A browser left running holds the profile (the next launch
|
|
27
|
+
* fails with "already open") and keeps the test process alive.
|
|
28
|
+
*/
|
|
29
|
+
export function abandonLaunch(browserProc, biDiConnector) {
|
|
30
|
+
biDiConnector?.kill();
|
|
31
|
+
browserProc.kill();
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BiDiConnector } from "../transport/bidi-connection.js";
|
|
2
|
+
/** The size a page gets unless config `use.viewport` says otherwise */
|
|
3
|
+
export declare const DEFAULT_VIEWPORT: {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
};
|
|
7
|
+
/** A viewport as `page.setViewport` takes it: a size and optionally a device pixel ratio */
|
|
8
|
+
export interface Viewport {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
devicePixelRatio?: number;
|
|
12
|
+
}
|
|
13
|
+
/** Throws RangeError when the size or the ratio is not usable, before anything is sent */
|
|
14
|
+
export declare function validateViewport({ width, height, devicePixelRatio, }: Viewport): void;
|
|
15
|
+
/**
|
|
16
|
+
* Gives the context this size (and optionally this device pixel ratio); `null` puts the browser's own size back
|
|
17
|
+
* and waits until the page has really got it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function applyViewport(connector: BiDiConnector, context: string, viewport: Viewport | null): Promise<void>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { callFunction } from "../script/call-function.js";
|
|
2
|
+
/** The size a page gets unless config `use.viewport` says otherwise */
|
|
3
|
+
export const DEFAULT_VIEWPORT = { width: 1280, height: 720 };
|
|
4
|
+
/** Time (ms) without a `resize` event after which a viewport reset counts as done */
|
|
5
|
+
const RESIZE_QUIET_TIME = 50;
|
|
6
|
+
/** Time (ms) a viewport reset waits for a `resize` event that may never come (the size did not change) */
|
|
7
|
+
const RESIZE_MAX_WAIT = 300;
|
|
8
|
+
/** Throws RangeError when the size or the ratio is not usable, before anything is sent */
|
|
9
|
+
export function validateViewport({ width, height, devicePixelRatio, }) {
|
|
10
|
+
for (const [name, value] of [
|
|
11
|
+
["width", width],
|
|
12
|
+
["height", height],
|
|
13
|
+
]) {
|
|
14
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
15
|
+
throw new RangeError(`setViewport(): ${name} must be a positive integer, got ${value}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (devicePixelRatio !== undefined &&
|
|
19
|
+
!(devicePixelRatio > 0 && Number.isFinite(devicePixelRatio))) {
|
|
20
|
+
throw new RangeError(`setViewport(): devicePixelRatio must be a positive number, got ${devicePixelRatio}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Gives the context this size (and optionally this device pixel ratio); `null` puts the browser's own size back
|
|
25
|
+
* and waits until the page has really got it.
|
|
26
|
+
*/
|
|
27
|
+
export async function applyViewport(connector, context, viewport) {
|
|
28
|
+
if (viewport === null) {
|
|
29
|
+
await untilResized(connector, context, () => connector.send("browsingContext.setViewport", {
|
|
30
|
+
context,
|
|
31
|
+
viewport: null,
|
|
32
|
+
devicePixelRatio: null,
|
|
33
|
+
}));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
validateViewport(viewport);
|
|
37
|
+
const { width, height, devicePixelRatio } = viewport;
|
|
38
|
+
await connector.send("browsingContext.setViewport", {
|
|
39
|
+
context,
|
|
40
|
+
viewport: { width, height },
|
|
41
|
+
...(devicePixelRatio !== undefined && { devicePixelRatio }),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Runs `change`, then waits until the page has stopped resizing. Chrome answers a viewport reset before the window
|
|
46
|
+
* has its own size back, so a read right after it can still show the old size. The wait ends `RESIZE_QUIET_TIME`
|
|
47
|
+
* after the last `resize` event, and after `RESIZE_MAX_WAIT` when the size does not change at all (no event
|
|
48
|
+
* comes). Never fails: a page that cannot be watched is simply not waited for.
|
|
49
|
+
*/
|
|
50
|
+
async function untilResized(connector, context, change) {
|
|
51
|
+
const sandbox = { sandbox: "samurai-viewport" };
|
|
52
|
+
const watching = await callFunction(connector, context, `() => {
|
|
53
|
+
globalThis.__resized = new Promise((resolve) => {
|
|
54
|
+
let timer;
|
|
55
|
+
const finish = () => {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
removeEventListener("resize", onResize);
|
|
58
|
+
resolve();
|
|
59
|
+
};
|
|
60
|
+
const onResize = () => {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
timer = setTimeout(finish, ${RESIZE_QUIET_TIME});
|
|
63
|
+
};
|
|
64
|
+
addEventListener("resize", onResize);
|
|
65
|
+
timer = setTimeout(finish, ${RESIZE_MAX_WAIT});
|
|
66
|
+
});
|
|
67
|
+
}`, [], { ...sandbox, awaitPromise: false }).then(() => true, () => false);
|
|
68
|
+
await change();
|
|
69
|
+
if (!watching)
|
|
70
|
+
return;
|
|
71
|
+
await callFunction(connector, context, "() => globalThis.__resized", [], sandbox).catch(() => undefined);
|
|
72
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ResolvedBrowser } from "../browsers/resolve.js";
|
|
2
2
|
import type { SupportedBrowser } from "../types/browser.js";
|
|
3
|
-
import {
|
|
3
|
+
import type { BrowserLaunchOptions } from "./launch-flags.js";
|
|
4
4
|
/** Written into a managed build's folder once it started there; its first start can be slow (macOS checks the new app) */
|
|
5
5
|
export declare const LAUNCHED_STAMP = ".samurai-launched";
|
|
6
6
|
/**
|
package/dist/browser/warm-up.js
CHANGED
|
@@ -2,7 +2,8 @@ import { existsSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { projectBrowser } from "../browsers/resolve.js";
|
|
4
4
|
import logger from "../logger/index.js";
|
|
5
|
-
import { Browser
|
|
5
|
+
import { Browser } from "./browser.js";
|
|
6
|
+
import { BrowserStartTimeoutError } from "./session.js";
|
|
6
7
|
/** Written into a managed build's folder once it started there; its first start can be slow (macOS checks the new app) */
|
|
7
8
|
export const LAUNCHED_STAMP = ".samurai-launched";
|
|
8
9
|
/**
|
package/dist/browsers/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { browsersCacheDir } from "./cache-dir.js";
|
|
2
2
|
export type { CachedBuild, Downloader } from "./downloader.js";
|
|
3
3
|
export { ENV_CHROMEDRIVER_PATH, ENV_PATH, type Override } from "./overrides.js";
|
|
4
|
-
export {
|
|
4
|
+
export { MANAGED_BROWSERS, PINNED, isManagedBrowser, type ManagedBrowser, } from "./pins.js";
|
|
5
5
|
export { browserStatus, projectBrowser, projectExecutable, resolveBrowser, resolveExecutable, type ResolvedBrowser, } from "./resolve.js";
|
|
6
6
|
export { BrowserNotInstalledError, installBrowser, listInstalled, managedBuildDir, managedChromedriver, managedExecutable, uninstallBrowser, type BrowserStatus, type InstalledBuild, type StoreOptions, } from "./store.js";
|
package/dist/browsers/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { browsersCacheDir } from "./cache-dir.js";
|
|
2
2
|
export { ENV_CHROMEDRIVER_PATH, ENV_PATH } from "./overrides.js";
|
|
3
|
-
export {
|
|
3
|
+
export { MANAGED_BROWSERS, PINNED, isManagedBrowser, } from "./pins.js";
|
|
4
4
|
export { browserStatus, projectBrowser, projectExecutable, resolveBrowser, resolveExecutable, } from "./resolve.js";
|
|
5
5
|
export { BrowserNotInstalledError, installBrowser, listInstalled, managedBuildDir, managedChromedriver, managedExecutable, uninstallBrowser, } from "./store.js";
|
package/dist/browsers/pins.d.ts
CHANGED
|
@@ -11,6 +11,4 @@ export declare const PINNED: {
|
|
|
11
11
|
};
|
|
12
12
|
export type ManagedBrowser = keyof typeof PINNED;
|
|
13
13
|
export declare const MANAGED_BROWSERS: ManagedBrowser[];
|
|
14
|
-
/** The managed browsers the framework can launch (Chrome through its chromedriver) */
|
|
15
|
-
export declare const LAUNCHABLE: readonly ManagedBrowser[];
|
|
16
14
|
export declare function isManagedBrowser(name: string): name is ManagedBrowser;
|
package/dist/browsers/pins.js
CHANGED
|
@@ -7,8 +7,6 @@ export const PINNED = {
|
|
|
7
7
|
},
|
|
8
8
|
};
|
|
9
9
|
export const MANAGED_BROWSERS = Object.keys(PINNED);
|
|
10
|
-
/** The managed browsers the framework can launch (Chrome through its chromedriver) */
|
|
11
|
-
export const LAUNCHABLE = ["firefox", "chrome"];
|
|
12
10
|
export function isManagedBrowser(name) {
|
|
13
11
|
return Object.prototype.hasOwnProperty.call(PINNED, name);
|
|
14
12
|
}
|
package/dist/browsers/store.d.ts
CHANGED
|
@@ -20,8 +20,6 @@ export interface BrowserStatus {
|
|
|
20
20
|
/** unavailable: no download exists for this OS and architecture */
|
|
21
21
|
state: "installed" | "missing" | "unavailable";
|
|
22
22
|
executablePath?: string;
|
|
23
|
-
/** Whether the framework can launch it yet */
|
|
24
|
-
launchable: boolean;
|
|
25
23
|
/** A path set on purpose, which launches use instead of the managed build */
|
|
26
24
|
override?: Override;
|
|
27
25
|
}
|
package/dist/browsers/store.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { browsersCacheDir } from "./cache-dir.js";
|
|
4
4
|
import { COMPLETE_MARKER, puppeteerDownloader, } from "./downloader.js";
|
|
5
5
|
import { overrideOf, } from "./overrides.js";
|
|
6
|
-
import { isManagedBrowser,
|
|
6
|
+
import { isManagedBrowser, PINNED } from "./pins.js";
|
|
7
7
|
export { COMPLETE_MARKER };
|
|
8
8
|
/** Each install downloads into its own `<cache>/.staging-<random>/` and moves the finished build into place */
|
|
9
9
|
const STAGING_PREFIX = ".staging-";
|
|
@@ -107,7 +107,6 @@ export function statusOf(name, options = {}) {
|
|
|
107
107
|
name,
|
|
108
108
|
label: pin.label,
|
|
109
109
|
buildId: pin.buildId,
|
|
110
|
-
launchable: LAUNCHABLE.includes(name),
|
|
111
110
|
...(override && { override }),
|
|
112
111
|
};
|
|
113
112
|
if (!downloader.platform())
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type ProjectOptions, type RunnerOptions } from "../runner/run.js";
|
|
2
2
|
/** `firefox` or `chrome` */
|
|
3
3
|
type SupportedBrowser = NonNullable<RunnerOptions["browsers"]>[number];
|
|
4
|
-
/** The values a command line can override for one run */
|
|
5
|
-
type
|
|
4
|
+
/** The values a command line can override for one run: the environment and the two timeouts */
|
|
5
|
+
type EnvAndTimeouts = Pick<ProjectOptions, "environment" | "timeout" | "expectTimeout">;
|
|
6
6
|
/** Flags and positional arguments of a command line; an unknown flag is an error */
|
|
7
7
|
export declare function parseCommandLine(argv: string[]): {
|
|
8
8
|
values: {
|
|
@@ -11,6 +11,7 @@ export declare function parseCommandLine(argv: string[]): {
|
|
|
11
11
|
"expect-timeout"?: string | undefined;
|
|
12
12
|
headless?: boolean | undefined;
|
|
13
13
|
port?: string | undefined;
|
|
14
|
+
workers?: string | undefined;
|
|
14
15
|
grep?: string | undefined;
|
|
15
16
|
group?: string | undefined;
|
|
16
17
|
browser?: string[] | undefined;
|
|
@@ -29,18 +30,24 @@ export declare function parseCommandLine(argv: string[]): {
|
|
|
29
30
|
};
|
|
30
31
|
positionals: string[];
|
|
31
32
|
};
|
|
33
|
+
/** What `parseCommandLine` returns */
|
|
34
|
+
export type ParsedCommandLine = ReturnType<typeof parseCommandLine>;
|
|
35
|
+
/** The flag values of a command line, parsed once by the caller or here from `argv` */
|
|
36
|
+
export type CommandValues = ParsedCommandLine["values"];
|
|
32
37
|
/** How the command line says tests are selected and the browser starts */
|
|
33
38
|
export interface RunnerFlags {
|
|
34
39
|
headless?: boolean;
|
|
35
40
|
port?: number;
|
|
41
|
+
/** `--workers`: a whole number or a percentage like `50%`, as typed */
|
|
42
|
+
workers?: string;
|
|
36
43
|
grep?: string;
|
|
37
44
|
group?: string;
|
|
38
45
|
files?: string[];
|
|
39
46
|
/** `--browser`, repeated for more than one; replaces the config's `browsers` for this run */
|
|
40
47
|
browsers?: SupportedBrowser[];
|
|
41
48
|
}
|
|
42
|
-
/** Reads `--headless`, `--port <n>`, `--grep <text>`, `--group <name>`, `--file <spec>` and `--browser <name>` (both repeatable) from `argv
|
|
43
|
-
export declare function parseRunnerFlags(
|
|
44
|
-
/** Reads `--env`, `--timeout` and `--expect-timeout` from `argv
|
|
45
|
-
export declare function parseRunOverrides(
|
|
49
|
+
/** Reads `--headless`, `--port <n>`, `--workers <n|n%>`, `--grep <text>`, `--group <name>`, `--file <spec>` and `--browser <name>` (both repeatable) from `argv`, or from values that were parsed already */
|
|
50
|
+
export declare function parseRunnerFlags(source: string[] | CommandValues): RunnerFlags;
|
|
51
|
+
/** Reads `--env`, `--timeout` and `--expect-timeout` from `argv` (or values parsed already); the environment falls back to SAMURAI_ENV */
|
|
52
|
+
export declare function parseRunOverrides(source: string[] | CommandValues, env?: Partial<NodeJS.ProcessEnv>): EnvAndTimeouts;
|
|
46
53
|
export {};
|
package/dist/cli/args.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
|
-
import { checkBrowserList, } from "../runner/run.js";
|
|
2
|
+
import { checkBrowserList, parseWorkers, } from "../runner/run.js";
|
|
3
3
|
const FLAGS = {
|
|
4
4
|
env: { type: "string" },
|
|
5
5
|
timeout: { type: "string" },
|
|
6
6
|
"expect-timeout": { type: "string" },
|
|
7
7
|
headless: { type: "boolean" },
|
|
8
8
|
port: { type: "string" },
|
|
9
|
+
workers: { type: "string" },
|
|
9
10
|
grep: { type: "string" },
|
|
10
11
|
group: { type: "string" },
|
|
11
12
|
browser: { type: "string", multiple: true },
|
|
@@ -32,12 +33,10 @@ export function parseCommandLine(argv) {
|
|
|
32
33
|
allowPositionals: true,
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export function parseRunnerFlags(argv) {
|
|
40
|
-
const values = parseFlags(argv);
|
|
36
|
+
const valuesOf = (source) => Array.isArray(source) ? parseCommandLine(source).values : source;
|
|
37
|
+
/** Reads `--headless`, `--port <n>`, `--workers <n|n%>`, `--grep <text>`, `--group <name>`, `--file <spec>` and `--browser <name>` (both repeatable) from `argv`, or from values that were parsed already */
|
|
38
|
+
export function parseRunnerFlags(source) {
|
|
39
|
+
const values = valuesOf(source);
|
|
41
40
|
const flags = {};
|
|
42
41
|
if (values.headless !== undefined)
|
|
43
42
|
flags.headless = values.headless;
|
|
@@ -48,6 +47,10 @@ export function parseRunnerFlags(argv) {
|
|
|
48
47
|
}
|
|
49
48
|
flags.port = port;
|
|
50
49
|
}
|
|
50
|
+
if (values.workers !== undefined) {
|
|
51
|
+
parseWorkers(values.workers, "--workers");
|
|
52
|
+
flags.workers = values.workers;
|
|
53
|
+
}
|
|
51
54
|
if (values.grep !== undefined)
|
|
52
55
|
flags.grep = values.grep;
|
|
53
56
|
if (values.group !== undefined)
|
|
@@ -60,9 +63,9 @@ export function parseRunnerFlags(argv) {
|
|
|
60
63
|
}
|
|
61
64
|
return flags;
|
|
62
65
|
}
|
|
63
|
-
/** Reads `--env`, `--timeout` and `--expect-timeout` from `argv
|
|
64
|
-
export function parseRunOverrides(
|
|
65
|
-
const values =
|
|
66
|
+
/** Reads `--env`, `--timeout` and `--expect-timeout` from `argv` (or values parsed already); the environment falls back to SAMURAI_ENV */
|
|
67
|
+
export function parseRunOverrides(source, env = {}) {
|
|
68
|
+
const values = valuesOf(source);
|
|
66
69
|
const overrides = {};
|
|
67
70
|
const environment = values.env ?? env.SAMURAI_ENV;
|
|
68
71
|
if (environment)
|
package/dist/cli/browsers.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type StoreOptions } from "../browsers/index.js";
|
|
2
|
-
import type { Io } from "./
|
|
3
|
-
export declare const BROWSERS_USAGE = "Usage:\n samurai browsers [list] The pinned browsers and every build in the cache\n samurai browsers install [firefox|chrome|all] Download the pinned builds (default: all)\n samurai browsers uninstall <name> [--build <id>]\n Remove a build (default: the pinned one)\n samurai browsers uninstall --unused Remove builds this framework version doesn't pin\n";
|
|
2
|
+
import type { Io } from "./io.js";
|
|
4
3
|
export declare function formatBytes(n: number): string;
|
|
5
4
|
/** `samurai browsers …`; `options` is for tests. The cache folder follows `io.env` */
|
|
6
5
|
export declare function browsersCommand(argv: string[], io: Io, options?: StoreOptions): Promise<number>;
|
package/dist/cli/browsers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { browsersCacheDir, browserStatus, installBrowser, isManagedBrowser, listInstalled, MANAGED_BROWSERS, PINNED, uninstallBrowser, } from "../browsers/index.js";
|
|
2
2
|
import { parseCommandLine } from "./args.js";
|
|
3
|
-
|
|
3
|
+
const BROWSERS_USAGE = `Usage:
|
|
4
4
|
samurai browsers [list] The pinned browsers and every build in the cache
|
|
5
5
|
samurai browsers install [firefox|chrome|all] Download the pinned builds (default: all)
|
|
6
6
|
samurai browsers uninstall <name> [--build <id>]
|
|
@@ -96,7 +96,7 @@ export async function browsersCommand(argv, io, options = {}) {
|
|
|
96
96
|
return 0;
|
|
97
97
|
}
|
|
98
98
|
if (target === undefined || target === "all") {
|
|
99
|
-
io.err(`Which browser
|
|
99
|
+
io.err(`Which browser?\n\n${BROWSERS_USAGE}`);
|
|
100
100
|
return 2;
|
|
101
101
|
}
|
|
102
102
|
const [name] = names(target);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { painter } from "./paint.js";
|
|
1
2
|
const seconds = (ms) => `${(ms / 1000).toFixed(1)}s`;
|
|
2
3
|
/** Prints a run for a person: one line per test as it ends, then every failure in full and a count */
|
|
3
4
|
export class ConsoleReporter {
|
|
@@ -5,13 +6,13 @@ export class ConsoleReporter {
|
|
|
5
6
|
/** Whether the run has more than one browser: only then is each test labelled with its browser */
|
|
6
7
|
this.labelled = false;
|
|
7
8
|
this.write = write;
|
|
8
|
-
this.paint = (
|
|
9
|
+
this.paint = painter(color);
|
|
9
10
|
}
|
|
10
11
|
handle(event) {
|
|
11
12
|
switch (event.type) {
|
|
12
13
|
case "run-start":
|
|
13
14
|
this.labelled = event.browsers.length > 1;
|
|
14
|
-
this.write(`Running ${event.total} ${event.total === 1 ? "test" : "tests"} against ${event.environment}${this.labelled ? ` in ${event.browsers.join(", ")}` : ""}\n`);
|
|
15
|
+
this.write(`Running ${event.total} ${event.total === 1 ? "test" : "tests"}${event.workers ? ` with ${event.workers} workers` : ""} against ${event.environment}${this.labelled ? ` in ${event.browsers.join(", ")}` : ""}\n`);
|
|
15
16
|
return;
|
|
16
17
|
case "test-end":
|
|
17
18
|
this.write(` ${this.line(event.name, event.result, event.browser)}\n`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { nodeDef, } from "../flows/core/index.js";
|
|
2
2
|
import { maskSecrets as maskText, } from "../flows/run/index.js";
|
|
3
3
|
import { STEP_NODES } from "../flows/steps/index.js";
|
|
4
|
+
import { painter } from "./paint.js";
|
|
4
5
|
const took = (ms) => ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;
|
|
5
6
|
const SKIPPED_BY_SHAPE = new Set(["start", "end"]);
|
|
6
7
|
/** Prints a flow run for a person: one line per node as it ends, then a count. Start and End are not listed. */
|
|
@@ -10,7 +11,7 @@ export class FlowReporter {
|
|
|
10
11
|
this.steps = steps ?? STEP_NODES;
|
|
11
12
|
this.flow = flow;
|
|
12
13
|
this.write = write;
|
|
13
|
-
this.paint = (
|
|
14
|
+
this.paint = painter(color);
|
|
14
15
|
this.nodes = new Map(flow.nodes.map((n) => [n.id, n]));
|
|
15
16
|
}
|
|
16
17
|
shapeOf(node) {
|
package/dist/cli/flow.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Io } from "./
|
|
2
|
-
export declare const FLOW_USAGE = "Usage:\n samurai flow list [--json] List the flows in ./flows\n samurai flow check [<flow>...] [options] Check flows without running them (all flows when none is given)\n samurai flow run <flow>... [options] Run flows, in the order given\n samurai flow run --all [options] Run every flow in ./flows, in file name order\n\nA flow is an id (flows/<id>.flow.json) or a path to a .flow.json file.\n\nOptions for check and run:\n --env <name> Environment to use (or SAMURAI_ENV)\n --allow-unsupported Skip nodes whose kind has no handler instead of refusing the flow (every built-in kind runs)\n --json Machine-readable output: JSON lines for run, one array for check and list\n\nOptions for run:\n --timeout <ms> Time one test may take\n --expect-timeout <ms> Time actions and assertions retry\n --headless, --no-headless Run the browser without a window, or with one\n --port <n> Browser debugging port (default 9223)\n\nEach run writes result/flows/<id>.json.\nExit code: 0 when every node that should run passed, 1 when a node failed or the run was cancelled,\n2 for a usage, configuration or flow-file error, or a flow that has errors (nothing ran).\n";
|
|
1
|
+
import type { Io } from "./io.js";
|
|
3
2
|
/** `samurai flow ...`: `argv` is what follows `flow`. Returns the exit code */
|
|
4
3
|
export declare function flowCommand(argv: string[], io: Io): Promise<number>;
|
package/dist/cli/flow.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { parseCommandLine, parseRunnerFlags, parseRunOverrides, } from "./args.js";
|
|
3
3
|
import { FlowReporter } from "./flow-reporter.js";
|
|
4
|
+
import { painter } from "./paint.js";
|
|
4
5
|
import { projectSteps } from "../flows/steps/index.js";
|
|
5
6
|
import {} from "../flows/core/index.js";
|
|
6
7
|
import { FLOW_SUFFIX, FlowCheckError, FlowReportBuilder, checkFlowInProject, flowsDir, listFlows, readFlow, readFlowPath, runFlowInProject, writeFlowReport, } from "../flows/run/index.js";
|
|
7
|
-
|
|
8
|
+
import { DEFAULT_PORT } from "../runner/run.js";
|
|
9
|
+
const FLOW_USAGE = `Usage:
|
|
8
10
|
samurai flow list [--json] List the flows in ./flows
|
|
9
11
|
samurai flow check [<flow>...] [options] Check flows without running them (all flows when none is given)
|
|
10
12
|
samurai flow run <flow>... [options] Run flows, in the order given
|
|
@@ -21,7 +23,8 @@ Options for run:
|
|
|
21
23
|
--timeout <ms> Time one test may take
|
|
22
24
|
--expect-timeout <ms> Time actions and assertions retry
|
|
23
25
|
--headless, --no-headless Run the browser without a window, or with one
|
|
24
|
-
--port <n> Browser debugging port (default
|
|
26
|
+
--port <n> Browser debugging port (default ${DEFAULT_PORT})
|
|
27
|
+
--workers <n|n%> Worker processes the tests share (or SAMURAI_WORKERS; default half the CPUs)
|
|
25
28
|
|
|
26
29
|
Each run writes result/flows/<id>.json.
|
|
27
30
|
Exit code: 0 when every node that should run passed, 1 when a node failed or the run was cancelled,
|
|
@@ -38,11 +41,8 @@ const describe = (flow, p) => {
|
|
|
38
41
|
...(node?.title && { title: node.title }),
|
|
39
42
|
};
|
|
40
43
|
};
|
|
41
|
-
function paintWith(io) {
|
|
42
|
-
return (code, text) => io.color ? `\u001b[${code}m${text}\u001b[0m` : text;
|
|
43
|
-
}
|
|
44
44
|
function problemLines(io, problems) {
|
|
45
|
-
const paint =
|
|
45
|
+
const paint = painter(io.color);
|
|
46
46
|
return problems
|
|
47
47
|
.map((p) => {
|
|
48
48
|
const who = p.key
|
|
@@ -89,6 +89,15 @@ async function list(io, json) {
|
|
|
89
89
|
: `${row.id} ${row.name} (${row.nodes} ${row.nodes === 1 ? "node" : "nodes"})\n`);
|
|
90
90
|
return 0;
|
|
91
91
|
}
|
|
92
|
+
/** Checks one flow of the project, the same way for `check` and for the refusal before a run */
|
|
93
|
+
function checkOne(projectDir, flow, options) {
|
|
94
|
+
return checkFlowInProject({
|
|
95
|
+
projectDir,
|
|
96
|
+
flow,
|
|
97
|
+
unsupported: options.unsupported,
|
|
98
|
+
...(options.environment && { environment: options.environment }),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
92
101
|
async function check(refs, io, options) {
|
|
93
102
|
const projectDir = process.cwd();
|
|
94
103
|
const targets = refs.length ? refs : await everyFlow(projectDir);
|
|
@@ -104,12 +113,7 @@ async function check(refs, io, options) {
|
|
|
104
113
|
code = 2;
|
|
105
114
|
continue;
|
|
106
115
|
}
|
|
107
|
-
const result = await
|
|
108
|
-
projectDir,
|
|
109
|
-
flow,
|
|
110
|
-
unsupported: options.unsupported,
|
|
111
|
-
...(options.environment && { environment: options.environment }),
|
|
112
|
-
});
|
|
116
|
+
const result = await checkOne(projectDir, flow, options);
|
|
113
117
|
const problems = result.problems.map((p) => describe(result.flow, p));
|
|
114
118
|
all.push(...problems);
|
|
115
119
|
if (code === 0 && problems.some((p) => p.level === "error"))
|
|
@@ -141,19 +145,14 @@ async function run(refs, io, options) {
|
|
|
141
145
|
// Several flows: refuse them all before the first one runs
|
|
142
146
|
if (flows.length > 1) {
|
|
143
147
|
for (const flow of flows) {
|
|
144
|
-
const { problems } = await
|
|
145
|
-
projectDir,
|
|
146
|
-
flow,
|
|
147
|
-
unsupported: options.unsupported,
|
|
148
|
-
...(options.environment && { environment: options.environment }),
|
|
149
|
-
});
|
|
148
|
+
const { problems } = await checkOne(projectDir, flow, options);
|
|
150
149
|
const errors = problems.filter((p) => p.level === "error");
|
|
151
150
|
if (errors.length)
|
|
152
151
|
return refuse(errors, flow);
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
154
|
let code = 0;
|
|
156
|
-
for (const flow of flows) {
|
|
155
|
+
for (const [index, flow] of flows.entries()) {
|
|
157
156
|
if (io.signal?.aborted) {
|
|
158
157
|
code = 1;
|
|
159
158
|
break;
|
|
@@ -162,7 +161,7 @@ async function run(refs, io, options) {
|
|
|
162
161
|
const human = options.json
|
|
163
162
|
? undefined
|
|
164
163
|
: new FlowReporter({ flow, write: io.out, color: io.color, steps });
|
|
165
|
-
if (
|
|
164
|
+
if (index > 0 && !options.json)
|
|
166
165
|
io.out("\n");
|
|
167
166
|
let summary;
|
|
168
167
|
try {
|
|
@@ -200,7 +199,7 @@ export async function flowCommand(argv, io) {
|
|
|
200
199
|
const [sub, ...refs] = positionals;
|
|
201
200
|
const unsupported = values["allow-unsupported"] ? "skip" : "fail";
|
|
202
201
|
const json = values.json === true;
|
|
203
|
-
const overrides = parseRunOverrides(
|
|
202
|
+
const overrides = parseRunOverrides(values, io.env);
|
|
204
203
|
try {
|
|
205
204
|
if (sub === "list" && refs.length === 0)
|
|
206
205
|
return await list(io, json);
|
|
@@ -215,7 +214,7 @@ export async function flowCommand(argv, io) {
|
|
|
215
214
|
throw new UsageError("Give flows or --all, not both.");
|
|
216
215
|
if (!values.all && refs.length === 0)
|
|
217
216
|
throw new UsageError("Which flow? Give a flow or --all.");
|
|
218
|
-
const flags = parseRunnerFlags(
|
|
217
|
+
const flags = parseRunnerFlags(values);
|
|
219
218
|
const targets = values.all ? await everyFlow(process.cwd()) : refs;
|
|
220
219
|
return await run(targets, io, {
|
|
221
220
|
json,
|
|
@@ -225,6 +224,10 @@ export async function flowCommand(argv, io) {
|
|
|
225
224
|
...overrides,
|
|
226
225
|
...(flags.headless !== undefined && { headless: flags.headless }),
|
|
227
226
|
...(flags.port !== undefined && { port: flags.port }),
|
|
227
|
+
...(flags.workers !== undefined && { workers: flags.workers }),
|
|
228
|
+
...(io.env.SAMURAI_WORKERS && {
|
|
229
|
+
workersEnv: io.env.SAMURAI_WORKERS,
|
|
230
|
+
}),
|
|
228
231
|
},
|
|
229
232
|
});
|
|
230
233
|
}
|
package/dist/cli/init.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import { existsSync, mkdirSync,
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { frameworkVersion } from "./version.js";
|
|
3
4
|
const PACKAGE = "@itmetsam/samurai-framework";
|
|
4
|
-
/** The version of this package, so a new project asks for the release that scaffolded it */
|
|
5
|
-
function frameworkVersion() {
|
|
6
|
-
const manifest = new URL("../../package.json", import.meta.url);
|
|
7
|
-
return JSON.parse(readFileSync(manifest, "utf8"))
|
|
8
|
-
.version;
|
|
9
|
-
}
|
|
10
5
|
/** The files `samurai init` writes, by path relative to the project folder */
|
|
11
6
|
export function scaffold(name) {
|
|
12
7
|
return {
|
package/dist/cli/io.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** What the command line reads from and writes to; the process supplies it, tests fake it */
|
|
2
|
+
export interface Io {
|
|
3
|
+
out: (text: string) => void;
|
|
4
|
+
err: (text: string) => void;
|
|
5
|
+
/** Whether output goes to a terminal that shows colours */
|
|
6
|
+
color: boolean;
|
|
7
|
+
env: Partial<NodeJS.ProcessEnv>;
|
|
8
|
+
/** Aborts a recording (Ctrl+C) */
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
}
|
package/dist/cli/io.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli/main.d.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
err: (text: string) => void;
|
|
5
|
-
/** Whether output goes to a terminal that shows colours */
|
|
6
|
-
color: boolean;
|
|
7
|
-
env: Partial<NodeJS.ProcessEnv>;
|
|
8
|
-
/** Aborts a recording (Ctrl+C) */
|
|
9
|
-
signal?: AbortSignal;
|
|
10
|
-
}
|
|
1
|
+
import type { Io } from "./io.js";
|
|
2
|
+
import { USAGE } from "./usage.js";
|
|
3
|
+
export { USAGE };
|
|
11
4
|
/** The command line as `samurai` runs it. Returns the exit code */
|
|
12
5
|
export declare function main(argv: string[], io: Io): Promise<number>;
|