craftdriver 1.5.0 → 1.7.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/CHANGELOG.md +24 -0
- package/README.md +7 -3
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +4 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/server.js +4 -0
- package/dist/cli/mcp/server.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/browser.d.ts +73 -22
- package/dist/lib/browser.d.ts.map +1 -1
- package/dist/lib/browser.js +155 -41
- package/dist/lib/browser.js.map +1 -1
- package/dist/lib/browserContext.d.ts +1 -1
- package/dist/lib/browserContext.d.ts.map +1 -1
- package/dist/lib/builder.d.ts +12 -1
- package/dist/lib/builder.d.ts.map +1 -1
- package/dist/lib/builder.js +26 -0
- package/dist/lib/builder.js.map +1 -1
- package/dist/lib/capabilities.d.ts +8 -0
- package/dist/lib/capabilities.d.ts.map +1 -1
- package/dist/lib/capabilities.js +26 -10
- package/dist/lib/capabilities.js.map +1 -1
- package/dist/lib/driver.d.ts +17 -1
- package/dist/lib/driver.d.ts.map +1 -1
- package/dist/lib/driver.js +27 -2
- package/dist/lib/driver.js.map +1 -1
- package/dist/lib/elementHandle.d.ts.map +1 -1
- package/dist/lib/elementHandle.js +34 -0
- package/dist/lib/elementHandle.js.map +1 -1
- package/dist/lib/errors.d.ts +7 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +7 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +31 -10
- package/dist/lib/http.js.map +1 -1
- package/dist/lib/launchTarget.d.ts +21 -2
- package/dist/lib/launchTarget.d.ts.map +1 -1
- package/dist/lib/launchTarget.js +105 -17
- package/dist/lib/launchTarget.js.map +1 -1
- package/dist/lib/remote.d.ts +55 -0
- package/dist/lib/remote.d.ts.map +1 -0
- package/dist/lib/remote.js +127 -0
- package/dist/lib/remote.js.map +1 -0
- package/dist/lib/timing.d.ts +8 -0
- package/dist/lib/timing.d.ts.map +1 -1
- package/dist/lib/timing.js +8 -0
- package/dist/lib/timing.js.map +1 -1
- package/dist/lib/tracing.d.ts +1 -1
- package/dist/lib/tracing.d.ts.map +1 -1
- package/dist/lib/tracing.js.map +1 -1
- package/dist/lib/types.d.ts +22 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/vibiumTrace.d.ts +1 -1
- package/dist/lib/vibiumTrace.d.ts.map +1 -1
- package/dist/lib/visual/antialias.d.ts +41 -0
- package/dist/lib/visual/antialias.d.ts.map +1 -0
- package/dist/lib/visual/antialias.js +126 -0
- package/dist/lib/visual/antialias.js.map +1 -0
- package/dist/lib/visual/codec.d.ts +24 -0
- package/dist/lib/visual/codec.d.ts.map +1 -0
- package/dist/lib/visual/codec.js +11 -0
- package/dist/lib/visual/codec.js.map +1 -0
- package/dist/lib/visual/compare.d.ts +38 -0
- package/dist/lib/visual/compare.d.ts.map +1 -0
- package/dist/lib/visual/compare.js +209 -0
- package/dist/lib/visual/compare.js.map +1 -0
- package/dist/lib/visual/diff.d.ts +18 -0
- package/dist/lib/visual/diff.d.ts.map +1 -0
- package/dist/lib/visual/diff.js +23 -0
- package/dist/lib/visual/diff.js.map +1 -0
- package/dist/lib/visual/expectScreenshot.d.ts +65 -0
- package/dist/lib/visual/expectScreenshot.d.ts.map +1 -0
- package/dist/lib/visual/expectScreenshot.js +287 -0
- package/dist/lib/visual/expectScreenshot.js.map +1 -0
- package/dist/lib/visual/index.d.ts +10 -0
- package/dist/lib/visual/index.d.ts.map +1 -0
- package/dist/lib/visual/index.js +9 -0
- package/dist/lib/visual/index.js.map +1 -0
- package/dist/lib/visual/pixelMath.d.ts +32 -0
- package/dist/lib/visual/pixelMath.d.ts.map +1 -0
- package/dist/lib/visual/pixelMath.js +70 -0
- package/dist/lib/visual/pixelMath.js.map +1 -0
- package/dist/lib/visual/pngHeader.d.ts +27 -0
- package/dist/lib/visual/pngHeader.d.ts.map +1 -0
- package/dist/lib/visual/pngHeader.js +63 -0
- package/dist/lib/visual/pngHeader.js.map +1 -0
- package/dist/lib/visual/pngjsCodec.d.ts +22 -0
- package/dist/lib/visual/pngjsCodec.d.ts.map +1 -0
- package/dist/lib/visual/pngjsCodec.js +70 -0
- package/dist/lib/visual/pngjsCodec.js.map +1 -0
- package/dist/lib/visual/types.d.ts +89 -0
- package/dist/lib/visual/types.d.ts.map +1 -0
- package/dist/lib/visual/types.js +20 -0
- package/dist/lib/visual/types.js.map +1 -0
- package/dist/lib/visual/visualError.d.ts +32 -0
- package/dist/lib/visual/visualError.d.ts.map +1 -0
- package/dist/lib/visual/visualError.js +59 -0
- package/dist/lib/visual/visualError.js.map +1 -0
- package/dist/lib/wait.d.ts.map +1 -1
- package/dist/lib/wait.js +7 -1
- package/dist/lib/wait.js.map +1 -1
- package/docs/api-reference.md +18 -2
- package/docs/browser-api.md +5 -4
- package/docs/driver-configuration.md +6 -0
- package/docs/error-codes.md +1 -0
- package/docs/index.md +1 -0
- package/docs/keyboard-mouse.md +7 -5
- package/docs/recipes/run-on-browserstack.md +265 -0
- package/docs/recipes.md +15 -1
- package/docs/remote-webdriver.md +308 -0
- package/docs/screenshots.md +15 -6
- package/docs/standards.md +15 -10
- package/docs/visual-testing.md +254 -0
- package/docs/why-craftdriver.md +5 -2
- package/package.json +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pngHeader.js","sourceRoot":"","sources":["../../../src/lib/visual/pngHeader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated pngjs adapter — the single place that touches the CommonJS-shaped
|
|
3
|
+
* `pngjs` API. The rest of craftdriver is ESM and works only with the
|
|
4
|
+
* promise-based {@link PngCodec} and normalized {@link DecodedImage} defined in
|
|
5
|
+
* `./codec`; pngjs types never leak past this file.
|
|
6
|
+
*
|
|
7
|
+
* Decode and encode both use pngjs's asynchronous stream APIs (`parse` /
|
|
8
|
+
* `pack`) rather than the synchronous variants, so a large image cannot block
|
|
9
|
+
* the event loop inside a single call. CRC checking is left at pngjs's default
|
|
10
|
+
* (enabled) so corrupt chunks are rejected rather than silently decoded.
|
|
11
|
+
*
|
|
12
|
+
* Maintenance risk (recorded, not hidden): `pngjs@7.0.0` is pinned exactly. It
|
|
13
|
+
* had no reported npm/OSV advisory as of 2026-07-17, but that is a timestamped
|
|
14
|
+
* check, not proof of safety — its last release was 2023 and it publishes no
|
|
15
|
+
* security policy. It relies on Node's built-in `zlib`, so keeping Node patched
|
|
16
|
+
* is part of the posture. CI runs `npm audit --omit=dev`; this seam is kept
|
|
17
|
+
* narrow (see `./codec`) so the codec can be replaced without touching callers
|
|
18
|
+
* if the project goes unmaintained or an advisory lands.
|
|
19
|
+
*/
|
|
20
|
+
import type { PngCodec } from './codec.js';
|
|
21
|
+
export declare const pngjsCodec: PngCodec;
|
|
22
|
+
//# sourceMappingURL=pngjsCodec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pngjsCodec.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/pngjsCodec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAgB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwDzD,eAAO,MAAM,UAAU,EAAE,QAA6B,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated pngjs adapter — the single place that touches the CommonJS-shaped
|
|
3
|
+
* `pngjs` API. The rest of craftdriver is ESM and works only with the
|
|
4
|
+
* promise-based {@link PngCodec} and normalized {@link DecodedImage} defined in
|
|
5
|
+
* `./codec`; pngjs types never leak past this file.
|
|
6
|
+
*
|
|
7
|
+
* Decode and encode both use pngjs's asynchronous stream APIs (`parse` /
|
|
8
|
+
* `pack`) rather than the synchronous variants, so a large image cannot block
|
|
9
|
+
* the event loop inside a single call. CRC checking is left at pngjs's default
|
|
10
|
+
* (enabled) so corrupt chunks are rejected rather than silently decoded.
|
|
11
|
+
*
|
|
12
|
+
* Maintenance risk (recorded, not hidden): `pngjs@7.0.0` is pinned exactly. It
|
|
13
|
+
* had no reported npm/OSV advisory as of 2026-07-17, but that is a timestamped
|
|
14
|
+
* check, not proof of safety — its last release was 2023 and it publishes no
|
|
15
|
+
* security policy. It relies on Node's built-in `zlib`, so keeping Node patched
|
|
16
|
+
* is part of the posture. CI runs `npm audit --omit=dev`; this seam is kept
|
|
17
|
+
* narrow (see `./codec`) so the codec can be replaced without touching callers
|
|
18
|
+
* if the project goes unmaintained or an advisory lands.
|
|
19
|
+
*/
|
|
20
|
+
import { PNG } from 'pngjs';
|
|
21
|
+
import { CraftdriverError, ErrorCode } from '../errors.js';
|
|
22
|
+
function wrapDecodeError(cause) {
|
|
23
|
+
return new CraftdriverError(ErrorCode.INVALID_ARGUMENT, 'Failed to decode PNG image.', {
|
|
24
|
+
cause,
|
|
25
|
+
hint: 'The buffer is not a valid PNG, or its chunks failed CRC validation.',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Decode a compressed PNG buffer to a fresh, tightly-packed 8-bit RGBA view.
|
|
30
|
+
*
|
|
31
|
+
* pngjs always normalizes palette/grayscale/16-bit/interlaced inputs to 8-bit
|
|
32
|
+
* RGBA in `png.data`, but that buffer may be a view into a larger pool. We copy
|
|
33
|
+
* into a right-sized `Uint8Array` so downstream code can rely on
|
|
34
|
+
* `data.length === width * height * 4` and on a predictable backing buffer.
|
|
35
|
+
*/
|
|
36
|
+
function decode(buffer) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const png = new PNG();
|
|
39
|
+
const input = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
|
40
|
+
png.parse(input, (err, decoded) => {
|
|
41
|
+
if (err || !decoded) {
|
|
42
|
+
reject(wrapDecodeError(err ?? new Error('pngjs produced no image')));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const { width, height } = decoded;
|
|
46
|
+
const expected = width * height * 4;
|
|
47
|
+
const data = new Uint8Array(expected);
|
|
48
|
+
data.set(decoded.data.subarray(0, expected));
|
|
49
|
+
resolve({ width, height, data });
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** Encode normalized 8-bit RGBA back to a compressed PNG buffer. */
|
|
54
|
+
function encode(image) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const png = new PNG({ width: image.width, height: image.height });
|
|
57
|
+
// pngjs owns a Buffer at png.data of the right length; fill it in place.
|
|
58
|
+
png.data = Buffer.from(image.data.buffer, image.data.byteOffset, image.data.byteLength);
|
|
59
|
+
const chunks = [];
|
|
60
|
+
png
|
|
61
|
+
.pack()
|
|
62
|
+
.on('data', (chunk) => chunks.push(chunk))
|
|
63
|
+
.on('end', () => resolve(Buffer.concat(chunks)))
|
|
64
|
+
.on('error', (err) => reject(new CraftdriverError(ErrorCode.DRIVER_ERROR, 'Failed to encode diff PNG image.', {
|
|
65
|
+
cause: err,
|
|
66
|
+
})));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export const pngjsCodec = { decode, encode };
|
|
70
|
+
//# sourceMappingURL=pngjsCodec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pngjsCodec.js","sourceRoot":"","sources":["../../../src/lib/visual/pngjsCodec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG3D,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,gBAAgB,EAAE,6BAA6B,EAAE;QACrF,KAAK;QACL,IAAI,EAAE,qEAAqE;KAC5E,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,MAAM,CAAC,MAAkB;IAChC,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrE,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YAChC,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,CAAC,eAAe,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC;gBACrE,OAAO;YACT,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;YAClC,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7C,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oEAAoE;AACpE,SAAS,MAAM,CAAC,KAAmB;IACjC,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAClE,yEAAyE;QACzE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxF,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG;aACA,IAAI,EAAE;aACN,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aACjD,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;aAC/C,EAAE,CAAC,OAAO,EAAE,CAAC,GAAY,EAAE,EAAE,CAC5B,MAAM,CACJ,IAAI,gBAAgB,CAAC,SAAS,CAAC,YAAY,EAAE,kCAAkC,EAAE;YAC/E,KAAK,EAAE,GAAG;SACX,CAAC,CACH,CACF,CAAC;IACN,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAa,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public and internal types for visual screenshot assertions.
|
|
3
|
+
*
|
|
4
|
+
* The `(actual, expected)` argument order is used consistently across every
|
|
5
|
+
* public and internal helper (`compareScreenshots`, `compareDecoded`,
|
|
6
|
+
* `createDiff`). Both buffers share a type, so reversing the order would be a
|
|
7
|
+
* silent bug — never deviate from it.
|
|
8
|
+
*/
|
|
9
|
+
import type { By } from '../by.js';
|
|
10
|
+
/**
|
|
11
|
+
* Default upper bound on decoded image size, in pixels, enforced before RGBA
|
|
12
|
+
* allocation. RGBA is ≥4 bytes/pixel, so expected + actual + final raw diff is
|
|
13
|
+
* ~240 MB of raw arrays at this limit before compressed buffers and pngjs
|
|
14
|
+
* working memory — and parallel assertions multiply that. Raise it explicitly
|
|
15
|
+
* for unusually long full-page screenshots; lower it when many workers run
|
|
16
|
+
* concurrently. A 100M default would permit ≥1.2 GB and is not a real guard.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEFAULT_MAX_IMAGE_PIXELS = 20000000;
|
|
19
|
+
/** Default upper bound on a compressed PNG input buffer, in bytes (50 MiB). */
|
|
20
|
+
export declare const DEFAULT_MAX_INPUT_BYTES: number;
|
|
21
|
+
/**
|
|
22
|
+
* Mutually exclusive capture scope forwarded to `browser.screenshot()`.
|
|
23
|
+
* `fullPage` and `selector` cannot be combined (enforced by the union here and
|
|
24
|
+
* re-checked at runtime for JavaScript callers).
|
|
25
|
+
*/
|
|
26
|
+
export type VisualScreenshotOptions = {
|
|
27
|
+
fullPage: true;
|
|
28
|
+
selector?: never;
|
|
29
|
+
} | {
|
|
30
|
+
selector: string | By;
|
|
31
|
+
fullPage?: false;
|
|
32
|
+
} | {
|
|
33
|
+
fullPage?: false;
|
|
34
|
+
selector?: never;
|
|
35
|
+
};
|
|
36
|
+
/** Policies applied to a single buffer-to-buffer comparison. */
|
|
37
|
+
export interface ScreenshotCompareOptions {
|
|
38
|
+
/** Inclusive maximum difference for each visible RGB channel. Integer 0..255. Default: 0. */
|
|
39
|
+
pixelTolerance?: number;
|
|
40
|
+
/** Maximum counted different pixels. Non-negative integer. */
|
|
41
|
+
maxDiffPixels?: number;
|
|
42
|
+
/** Maximum counted different pixels as a percentage of all pixels. 0..100. */
|
|
43
|
+
maxDiffPercentage?: number;
|
|
44
|
+
/** Exclude pixels classified as anti-aliasing from diff totals. Default: false. */
|
|
45
|
+
ignoreAntialiasing?: boolean;
|
|
46
|
+
/** Reject images above this decoded size before allocation. Default: 20 million pixels. */
|
|
47
|
+
maxImagePixels?: number;
|
|
48
|
+
/** Reject compressed PNG input above this size. Default: 50 MiB. */
|
|
49
|
+
maxInputBytes?: number;
|
|
50
|
+
}
|
|
51
|
+
/** Options for the retrying `browser.expectScreenshot()` assertion. */
|
|
52
|
+
export interface ExpectScreenshotOptions extends ScreenshotCompareOptions {
|
|
53
|
+
/** Overall retry time in ms. Defaults to the browser's default timeout (5000 ms). */
|
|
54
|
+
timeout?: number;
|
|
55
|
+
/** Delay between failed attempts in ms. Integer >= 10. Default: 50. */
|
|
56
|
+
interval?: number;
|
|
57
|
+
/** Mutually exclusive capture scope passed to `browser.screenshot()`. */
|
|
58
|
+
screenshot?: VisualScreenshotOptions;
|
|
59
|
+
}
|
|
60
|
+
/** Result of one buffer-to-buffer comparison. */
|
|
61
|
+
export interface VisualComparisonResult {
|
|
62
|
+
matches: boolean;
|
|
63
|
+
diffPixels: number;
|
|
64
|
+
/** Raw, unrounded value in 0..100. */
|
|
65
|
+
diffPercentage: number;
|
|
66
|
+
ignoredAntialiasPixels: number;
|
|
67
|
+
expectedWidth: number;
|
|
68
|
+
expectedHeight: number;
|
|
69
|
+
actualWidth: number;
|
|
70
|
+
actualHeight: number;
|
|
71
|
+
dimensionMismatch: boolean;
|
|
72
|
+
}
|
|
73
|
+
/** Result of a successful `browser.expectScreenshot()` assertion. */
|
|
74
|
+
export interface ScreenshotMatchResult extends VisualComparisonResult {
|
|
75
|
+
attempts: number;
|
|
76
|
+
elapsedMs: number;
|
|
77
|
+
/**
|
|
78
|
+
* How the on-disk baseline was resolved:
|
|
79
|
+
* - `'matched'` — an existing baseline was compared and passed.
|
|
80
|
+
* - `'created'` — no baseline existed; the captured screenshot was written as
|
|
81
|
+
* the new baseline (always on; the diff fields are zero).
|
|
82
|
+
* - `'updated'` — an existing baseline differed and was overwritten with the
|
|
83
|
+
* captured screenshot (only under `CRAFTDRIVER_UPDATE_VISUAL_BASELINES=true`;
|
|
84
|
+
* the diff fields describe state relative to the new baseline, i.e. zero —
|
|
85
|
+
* the magnitude of the accepted change is reported to stderr).
|
|
86
|
+
*/
|
|
87
|
+
baseline: 'matched' | 'created' | 'updated';
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,WAAa,CAAC;AAEnD,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,QAAmB,CAAC;AAExD;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GACpC;IAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GAC3C;IAAE,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAE3C,gEAAgE;AAChE,MAAM,WAAW,wBAAwB;IACvC,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,2FAA2F;IAC3F,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uEAAuE;AACvE,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,yEAAyE;IACzE,UAAU,CAAC,EAAE,uBAAuB,CAAC;CACtC;AAED,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,qBAAsB,SAAQ,sBAAsB;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;;;;;OASG;IACH,QAAQ,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;CAC7C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public and internal types for visual screenshot assertions.
|
|
3
|
+
*
|
|
4
|
+
* The `(actual, expected)` argument order is used consistently across every
|
|
5
|
+
* public and internal helper (`compareScreenshots`, `compareDecoded`,
|
|
6
|
+
* `createDiff`). Both buffers share a type, so reversing the order would be a
|
|
7
|
+
* silent bug — never deviate from it.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Default upper bound on decoded image size, in pixels, enforced before RGBA
|
|
11
|
+
* allocation. RGBA is ≥4 bytes/pixel, so expected + actual + final raw diff is
|
|
12
|
+
* ~240 MB of raw arrays at this limit before compressed buffers and pngjs
|
|
13
|
+
* working memory — and parallel assertions multiply that. Raise it explicitly
|
|
14
|
+
* for unusually long full-page screenshots; lower it when many workers run
|
|
15
|
+
* concurrently. A 100M default would permit ≥1.2 GB and is not a real guard.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_MAX_IMAGE_PIXELS = 20_000_000;
|
|
18
|
+
/** Default upper bound on a compressed PNG input buffer, in bytes (50 MiB). */
|
|
19
|
+
export const DEFAULT_MAX_INPUT_BYTES = 50 * 1024 * 1024;
|
|
20
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/visual/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,UAAU,CAAC;AAEnD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed failure for a visual assertion.
|
|
3
|
+
*
|
|
4
|
+
* JavaScript cannot both throw and return a normal value, so the final actual
|
|
5
|
+
* screenshot and generated diff PNG travel on the error as `Buffer`
|
|
6
|
+
* properties, while a JSON-serializable summary lives in `detail` for agents.
|
|
7
|
+
*/
|
|
8
|
+
import { CraftdriverError } from '../errors.js';
|
|
9
|
+
import type { VisualComparisonResult } from './types.js';
|
|
10
|
+
export interface VisualMismatchInfo {
|
|
11
|
+
expectedPath: string;
|
|
12
|
+
timeout: number;
|
|
13
|
+
attempts: number;
|
|
14
|
+
elapsedMs: number;
|
|
15
|
+
comparison: VisualComparisonResult;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Thrown by `browser.expectScreenshot()` when no screenshot matched the
|
|
19
|
+
* baseline before the timeout. Carries the final actual and diff PNG buffers
|
|
20
|
+
* plus the comparison summary; `code` is `VISUAL_MISMATCH`.
|
|
21
|
+
*/
|
|
22
|
+
export declare class VisualMismatchError extends CraftdriverError {
|
|
23
|
+
/** Final browser screenshot (compressed PNG). */
|
|
24
|
+
readonly actual: Buffer;
|
|
25
|
+
/** Final generated diff (compressed PNG). */
|
|
26
|
+
readonly diff: Buffer;
|
|
27
|
+
readonly comparison: VisualComparisonResult;
|
|
28
|
+
readonly attempts: number;
|
|
29
|
+
readonly elapsedMs: number;
|
|
30
|
+
constructor(actual: Buffer, diff: Buffer, info: VisualMismatchInfo);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=visualError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualError.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/visualError.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAa,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,sBAAsB,CAAC;CACpC;AAgBD;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,gBAAgB;IACvD,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB;CAyBnE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed failure for a visual assertion.
|
|
3
|
+
*
|
|
4
|
+
* JavaScript cannot both throw and return a normal value, so the final actual
|
|
5
|
+
* screenshot and generated diff PNG travel on the error as `Buffer`
|
|
6
|
+
* properties, while a JSON-serializable summary lives in `detail` for agents.
|
|
7
|
+
*/
|
|
8
|
+
import { CraftdriverError, ErrorCode } from '../errors.js';
|
|
9
|
+
function buildMessage(info) {
|
|
10
|
+
const { comparison, timeout, attempts } = info;
|
|
11
|
+
if (comparison.dimensionMismatch) {
|
|
12
|
+
return (`Screenshot did not match after ${timeout} ms: dimensions differ ` +
|
|
13
|
+
`(expected ${comparison.expectedWidth}x${comparison.expectedHeight}, ` +
|
|
14
|
+
`actual ${comparison.actualWidth}x${comparison.actualHeight}) across ${attempts} attempts`);
|
|
15
|
+
}
|
|
16
|
+
const pixels = comparison.diffPixels.toLocaleString('en-US');
|
|
17
|
+
const pct = comparison.diffPercentage.toFixed(4);
|
|
18
|
+
return `Screenshot did not match after ${timeout} ms: ${pixels} pixels differed (${pct}%) across ${attempts} attempts`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Thrown by `browser.expectScreenshot()` when no screenshot matched the
|
|
22
|
+
* baseline before the timeout. Carries the final actual and diff PNG buffers
|
|
23
|
+
* plus the comparison summary; `code` is `VISUAL_MISMATCH`.
|
|
24
|
+
*/
|
|
25
|
+
export class VisualMismatchError extends CraftdriverError {
|
|
26
|
+
/** Final browser screenshot (compressed PNG). */
|
|
27
|
+
actual;
|
|
28
|
+
/** Final generated diff (compressed PNG). */
|
|
29
|
+
diff;
|
|
30
|
+
comparison;
|
|
31
|
+
attempts;
|
|
32
|
+
elapsedMs;
|
|
33
|
+
constructor(actual, diff, info) {
|
|
34
|
+
super(ErrorCode.VISUAL_MISMATCH, buildMessage(info), {
|
|
35
|
+
detail: {
|
|
36
|
+
expectedPath: info.expectedPath,
|
|
37
|
+
timeout: info.timeout,
|
|
38
|
+
attempts: info.attempts,
|
|
39
|
+
elapsedMs: info.elapsedMs,
|
|
40
|
+
diffPixels: info.comparison.diffPixels,
|
|
41
|
+
diffPercentage: info.comparison.diffPercentage,
|
|
42
|
+
ignoredAntialiasPixels: info.comparison.ignoredAntialiasPixels,
|
|
43
|
+
expectedWidth: info.comparison.expectedWidth,
|
|
44
|
+
expectedHeight: info.comparison.expectedHeight,
|
|
45
|
+
actualWidth: info.comparison.actualWidth,
|
|
46
|
+
actualHeight: info.comparison.actualHeight,
|
|
47
|
+
dimensionMismatch: info.comparison.dimensionMismatch,
|
|
48
|
+
},
|
|
49
|
+
hint: 'Inspect error.actual and error.diff (PNG buffers) to see the regression. If the change is intentional, re-run with CRAFTDRIVER_UPDATE_VISUAL_BASELINES=true to overwrite the baseline.',
|
|
50
|
+
});
|
|
51
|
+
this.name = 'VisualMismatchError';
|
|
52
|
+
this.actual = actual;
|
|
53
|
+
this.diff = diff;
|
|
54
|
+
this.comparison = info.comparison;
|
|
55
|
+
this.attempts = info.attempts;
|
|
56
|
+
this.elapsedMs = info.elapsedMs;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=visualError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualError.js","sourceRoot":"","sources":["../../../src/lib/visual/visualError.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAW3D,SAAS,YAAY,CAAC,IAAwB;IAC5C,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC/C,IAAI,UAAU,CAAC,iBAAiB,EAAE,CAAC;QACjC,OAAO,CACL,kCAAkC,OAAO,yBAAyB;YAClE,aAAa,UAAU,CAAC,aAAa,IAAI,UAAU,CAAC,cAAc,IAAI;YACtE,UAAU,UAAU,CAAC,WAAW,IAAI,UAAU,CAAC,YAAY,YAAY,QAAQ,WAAW,CAC3F,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,kCAAkC,OAAO,QAAQ,MAAM,qBAAqB,GAAG,aAAa,QAAQ,WAAW,CAAC;AACzH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,mBAAoB,SAAQ,gBAAgB;IACvD,iDAAiD;IACxC,MAAM,CAAS;IACxB,6CAA6C;IACpC,IAAI,CAAS;IACb,UAAU,CAAyB;IACnC,QAAQ,CAAS;IACjB,SAAS,CAAS;IAE3B,YAAY,MAAc,EAAE,IAAY,EAAE,IAAwB;QAChE,KAAK,CAAC,SAAS,CAAC,eAAe,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE;YACnD,MAAM,EAAE;gBACN,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU;gBACtC,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,cAAc;gBAC9C,sBAAsB,EAAE,IAAI,CAAC,UAAU,CAAC,sBAAsB;gBAC9D,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,aAAa;gBAC5C,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,cAAc;gBAC9C,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW;gBACxC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,YAAY;gBAC1C,iBAAiB,EAAE,IAAI,CAAC,UAAU,CAAC,iBAAiB;aACrD;YACD,IAAI,EAAE,wLAAwL;SAC/L,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAClC,CAAC;CACF"}
|
package/dist/lib/wait.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../src/lib/wait.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C,MAAM,MAAM,SAAS,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD,qBAAa,aAAa;IAMtB,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAS;gBAGlB,MAAM,EAAE,MAAM,EACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,WAAW,EACvC,UAAU,CAAC,EAAE,MAAM;IAYf,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../src/lib/wait.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C,MAAM,MAAM,SAAS,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD,qBAAa,aAAa;IAMtB,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAS;gBAGlB,MAAM,EAAE,MAAM,EACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,WAAW,EACvC,UAAU,CAAC,EAAE,MAAM;IAYf,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAmCtE;AAOD,eAAO,MAAM,KAAK;8BACU,EAAE,MAAY,QAAQ,MAAM;6BAI7B,EAAE,MAAY,QAAQ,MAAM;gCASzB,EAAE,MAAY,QAAQ,MAAM;+BAS7B,EAAE,GAAG,UAAU,MAAY,QAAQ,MAAM;kCAUtC,EAAE,GAAG,UAAU,MAAY,QAAQ,MAAM;CAaxE,CAAC"}
|
package/dist/lib/wait.js
CHANGED
|
@@ -27,7 +27,11 @@ export class WebDriverWait {
|
|
|
27
27
|
async until(condition, message) {
|
|
28
28
|
const deadline = Date.now() + this.timeoutMs;
|
|
29
29
|
let lastErr;
|
|
30
|
-
|
|
30
|
+
// Check-first: the condition is always evaluated at least once, even with a
|
|
31
|
+
// zero (or already-elapsed) timeout. A `while (Date.now() < deadline)` loop
|
|
32
|
+
// would run zero iterations at timeout 0 and report an already-satisfiable
|
|
33
|
+
// condition as a spurious timeout.
|
|
34
|
+
for (;;) {
|
|
31
35
|
try {
|
|
32
36
|
const result = await condition(this.driver);
|
|
33
37
|
// Resolve on truthy or non-null/undefined result
|
|
@@ -38,6 +42,8 @@ export class WebDriverWait {
|
|
|
38
42
|
catch (e) {
|
|
39
43
|
lastErr = e;
|
|
40
44
|
}
|
|
45
|
+
if (Date.now() >= deadline)
|
|
46
|
+
break;
|
|
41
47
|
await new Promise((r) => setTimeout(r, this.intervalMs));
|
|
42
48
|
}
|
|
43
49
|
const errMsg = message ?? this.timeoutMsg ?? `Wait timed out after ${this.timeoutMs}ms`;
|
package/dist/lib/wait.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.js","sourceRoot":"","sources":["../../src/lib/wait.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAUnF,SAAS,oBAAoB,CAAC,GAAY;IACxC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IACpE,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC;IAClD,OAAO,cAAc,KAAK,iBAAiB,IAAI,cAAc,KAAK,yBAAyB,CAAC;AAC9F,CAAC;AAED,MAAM,OAAO,aAAa;IAMd;IALF,SAAS,CAAS;IAClB,UAAU,CAAS;IACnB,UAAU,CAAU;IAE5B,YACU,MAAc,EACtB,gBAAuC,EACvC,UAAmB;QAFX,WAAM,GAAN,MAAM,CAAQ;QAItB,IAAI,OAAO,gBAAgB,KAAK,QAAQ,EAAE,CAAC;YACzC,IAAI,CAAC,SAAS,GAAG,gBAAgB,EAAE,OAAO,IAAI,0BAA0B,CAAC;YACzE,IAAI,CAAC,UAAU,GAAG,gBAAgB,EAAE,QAAQ,IAAI,wBAAwB,CAAC;YACzE,IAAI,CAAC,UAAU,GAAG,gBAAgB,EAAE,UAAU,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,GAAG,gBAAgB,IAAI,0BAA0B,CAAC;YAChE,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,wBAAwB,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAI,SAAuB,EAAE,OAAgB;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7C,IAAI,OAAgB,CAAC;QACrB,
|
|
1
|
+
{"version":3,"file":"wait.js","sourceRoot":"","sources":["../../src/lib/wait.ts"],"names":[],"mappings":"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"}
|
package/docs/api-reference.md
CHANGED
|
@@ -14,7 +14,7 @@ Launch browsers, move between pages and frames, handle dialogs, and wait for nav
|
|
|
14
14
|
| Symbol | Kind | Summary | Docs |
|
|
15
15
|
|---|---|---|---|
|
|
16
16
|
| `Browser` | class | — | [browser-api](browser-api.md) |
|
|
17
|
-
| `LaunchOptions` | type | Mutually-exclusive browser and
|
|
17
|
+
| `LaunchOptions` | type | Mutually-exclusive browser, Electron, and remote-WebDriver launch configurations. | [browser-api](browser-api.md) |
|
|
18
18
|
| `LoadState` | type | When to consider a navigation complete. - `'load'` — page `load` event has fired (default) - `'domcontentloaded'` — `DOMContentLoaded` has fired (faster, no waiting for images/fonts) - `'networkidle'` — `load` + no in-flight requests for 500 ms - `'none'` — do not wait; return as soon as the navigation is initiated | [browser-api](browser-api.md) |
|
|
19
19
|
| `Page` | class | — | [browser-api](browser-api.md) |
|
|
20
20
|
| `Frame` | class | — | [browser-api](browser-api.md) |
|
|
@@ -124,6 +124,20 @@ Launch packaged Electron applications, drive their renderer, and opt in to main-
|
|
|
124
124
|
| `ElectronMainLogHandler` | type | — | [electron](electron.md) |
|
|
125
125
|
| `ElectronMainLogLevel` | type | Normalized level for a main-process log entry. | [electron](electron.md) |
|
|
126
126
|
|
|
127
|
+
## Visual Testing
|
|
128
|
+
|
|
129
|
+
Assert screenshots against baselines with pixel/percentage tolerances and optional anti-alias handling.
|
|
130
|
+
|
|
131
|
+
| Symbol | Kind | Summary | Docs |
|
|
132
|
+
|---|---|---|---|
|
|
133
|
+
| `compareScreenshots` | function | Compare two compressed PNG buffers without disk access, browser capture, retries, or throwing on a normal mismatch. Applies the same byte/pixel input limits as the retrying assertion. | [visual-testing](visual-testing.md) |
|
|
134
|
+
| `VisualMismatchError` | class | Thrown by `browser.expectScreenshot()` when no screenshot matched the baseline before the timeout. Carries the final actual and diff PNG buffers plus the comparison summary; `code` is `VISUAL_MISMATCH`. | [visual-testing](visual-testing.md) |
|
|
135
|
+
| `ScreenshotCompareOptions` | type | Policies applied to a single buffer-to-buffer comparison. | [visual-testing](visual-testing.md) |
|
|
136
|
+
| `ExpectScreenshotOptions` | type | Options for the retrying `browser.expectScreenshot()` assertion. | [visual-testing](visual-testing.md) |
|
|
137
|
+
| `VisualScreenshotOptions` | type | Mutually exclusive capture scope forwarded to `browser.screenshot()`. `fullPage` and `selector` cannot be combined (enforced by the union here and re-checked at runtime for JavaScript callers). | [visual-testing](visual-testing.md) |
|
|
138
|
+
| `VisualComparisonResult` | type | Result of one buffer-to-buffer comparison. | [visual-testing](visual-testing.md) |
|
|
139
|
+
| `ScreenshotMatchResult` | type | Result of a successful `browser.expectScreenshot()` assertion. | [visual-testing](visual-testing.md) |
|
|
140
|
+
|
|
127
141
|
## Accessibility
|
|
128
142
|
|
|
129
143
|
Run axe-core accessibility checks and inspect violation details.
|
|
@@ -167,5 +181,7 @@ Exports that are public but not yet assigned to a feature group.
|
|
|
167
181
|
| `ElectronMockCall` | type | One recorded invocation of a mocked Electron main-process method. | — |
|
|
168
182
|
| `ElectronRemoteOptions` | type | Extra context ElectronRemote needs beyond the inspector endpoint. | [electron](electron.md) |
|
|
169
183
|
| `PageMatcher` | type | Selects a top-level page by `url` and/or `title` for {@link Browser.waitForPage}. A string matches as a substring; a `RegExp` is tested. When both fields are given, both must match. | [browser-api](browser-api.md) |
|
|
184
|
+
| `RemoteAuth` | type | — | — |
|
|
185
|
+
| `RemoteWebDriverOptions` | type | Options for connecting to any W3C-compatible remote WebDriver endpoint — a self-hosted Selenium Grid, BrowserStack, or another cloud provider. Provider-specific detail (BrowserStack's `bstack:options`, etc.) is forwarded through `capabilities` without schema conversion. | — |
|
|
170
186
|
|
|
171
|
-
Total exports: **
|
|
187
|
+
Total exports: **93**.
|
package/docs/browser-api.md
CHANGED
|
@@ -27,7 +27,7 @@ const browser = await Browser.launch({
|
|
|
27
27
|
|
|
28
28
|
| Option | Type | Default | Description |
|
|
29
29
|
|--------|------|---------|-------------|
|
|
30
|
-
| `browserName` | `'chrome' \| 'chromium' \| 'firefox'` | `'chrome'` |
|
|
30
|
+
| `browserName` | `'chrome' \| 'chromium' \| 'firefox' \| 'safari'`; any non-empty `string` remotely | `'chrome'` | Local browser to launch or provider-facing remote browser name |
|
|
31
31
|
| `enableBiDi` | `boolean` | browsers: `true`; Electron: `false` | Use WebDriver BiDi. Electron requires an explicit opt-in because negotiation resets its initial renderer to `about:blank`. |
|
|
32
32
|
| `storageState` | `string` | — | Path to a session-state JSON file to load on startup |
|
|
33
33
|
| `mobileEmulation` | `MobileEmulation \| DeviceName` | — | Mobile device emulation settings (Chrome/Chromium only) |
|
|
@@ -35,10 +35,11 @@ const browser = await Browser.launch({
|
|
|
35
35
|
| `browserPath` | `string` | — | Custom browser binary to launch (Chrome/Chromium/Firefox) — see [Driver Configuration → Browser Binary Configuration](./driver-configuration.md#browser-binary-configuration) |
|
|
36
36
|
| `electron` | `ElectronLaunchOptions` | — | Launch a packaged Electron application renderer instead of a browser. Mutually exclusive with browser-only options; see [Testing Electron Apps](./electron.md). |
|
|
37
37
|
| `electronService` | `ElectronService` | automatic | Customize the Electron-specific chromedriver service. Valid only with `electron`. |
|
|
38
|
+
| `remote` | `RemoteWebDriverOptions` | — | Connect to a remote W3C WebDriver endpoint instead of launching locally. It supports `browserName`, `enableBiDi`, and `storageState`, but not local service, binary, argument, emulation, or download-directory options. **Not supported by the CLI or MCP server.** See [Remote WebDriver](./remote-webdriver.md). |
|
|
38
39
|
|
|
39
|
-
The TypeScript surface is a discriminated union
|
|
40
|
-
|
|
41
|
-
JSON-driven callers.
|
|
40
|
+
The TypeScript surface is a discriminated union for local browser, Electron,
|
|
41
|
+
and remote targets. Target-specific conflicts are also validated at runtime
|
|
42
|
+
for JavaScript and JSON-driven callers.
|
|
42
43
|
|
|
43
44
|
## Navigation
|
|
44
45
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Driver Configuration
|
|
2
2
|
|
|
3
|
+
> This page is **local-only** — it covers resolving a local
|
|
4
|
+
> chromedriver/geckodriver/safaridriver binary. Connecting to a remote
|
|
5
|
+
> Selenium Grid or cloud provider instead of a local driver process is a
|
|
6
|
+
> different, simpler configuration surface — see
|
|
7
|
+
> [Remote WebDriver](./remote-webdriver.md).
|
|
8
|
+
|
|
3
9
|
Craftdriver resolves the WebDriver binary through a chain — first match wins:
|
|
4
10
|
|
|
5
11
|
| Step | Source |
|
package/docs/error-codes.md
CHANGED
|
@@ -54,6 +54,7 @@ try {
|
|
|
54
54
|
| `ELECTRON_MAIN_UNAVAILABLE` | `browser.electron.executeMain(...)` couldn't reach the app's main process. | Launch with `electron: { mainProcess: true }`; ensure the app build keeps the `EnableNodeCliInspectArguments` fuse enabled (default). `hint` names the fix. |
|
|
55
55
|
| `ELECTRON_MAIN_THREW` | The `executeMain(...)` callback threw inside the Electron main process. | The main-process exception text is in the message; treat like a failed assertion about main-process state. |
|
|
56
56
|
| `ELECTRON_DEEPLINK_FAILED` | `browser.electron.triggerDeeplink(url)` could not open the custom-protocol URL. | An unsupported platform, a missing `appBinaryPath` on Windows, or the OS `open`/`gio`/`rundll32` launcher failed (`error.detail.command`, `error.cause`). An invalid or `http(s)`/`file` URL throws `INVALID_ARGUMENT` instead. |
|
|
57
|
+
| `VISUAL_MISMATCH` | `browser.expectScreenshot()` never matched the baseline within its timeout. | Thrown as `VisualMismatchError` (a `CraftdriverError` subclass). Read `error.actual` and `error.diff` (PNG `Buffer`s) to see the regression; `error.detail` carries JSON-safe path/dimensions/`diffPixels`/`diffPercentage`/`attempts`. If the change is intentional, re-run with `CRAFTDRIVER_UPDATE_VISUAL_BASELINES=true` to overwrite the baseline. See [visual-testing.md](./visual-testing.md). |
|
|
57
58
|
|
|
58
59
|
## Stability
|
|
59
60
|
|
package/docs/index.md
CHANGED
|
@@ -60,6 +60,7 @@ await browser.quit();
|
|
|
60
60
|
| Write browser automation | [Getting Started](./getting-started.md) |
|
|
61
61
|
| Solve a common testing workflow | [Recipes](./recipes.md) |
|
|
62
62
|
| Give an AI coding agent a browser | [AI Agent Guide](./agents.md) |
|
|
63
|
+
| Run on a Grid or cloud provider | [Remote WebDriver](./remote-webdriver.md) |
|
|
63
64
|
|
|
64
65
|
## Good Stuff To Read Next
|
|
65
66
|
|
package/docs/keyboard-mouse.md
CHANGED
|
@@ -255,10 +255,11 @@ This is often more convenient than using the global keyboard API.
|
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
|
258
|
-
## Touch gestures
|
|
258
|
+
## Touch gestures
|
|
259
259
|
|
|
260
|
-
When running with `mobileEmulation`,
|
|
261
|
-
|
|
260
|
+
When running Chrome/Chromium with `mobileEmulation`, or a remote real-device
|
|
261
|
+
session whose provider supports W3C touch-pointer actions, two convenience
|
|
262
|
+
gestures are exposed under `browser.gesture`:
|
|
262
263
|
|
|
263
264
|
```typescript
|
|
264
265
|
// Swipe from one point to another (px coordinates).
|
|
@@ -277,5 +278,6 @@ await browser.gesture.pinch({
|
|
|
277
278
|
});
|
|
278
279
|
```
|
|
279
280
|
|
|
280
|
-
These
|
|
281
|
-
|
|
281
|
+
These use W3C Pointer Actions and do not require BiDi. Remote support depends
|
|
282
|
+
on the selected device, browser, and provider. Local desktop Safari rejects
|
|
283
|
+
touch gestures because it has no documented touch-pointer automation surface.
|