@applitools/spec-driver-browser-extension 1.5.5 → 1.5.6

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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.5.6](https://github.com/Applitools-Dev/sdk/compare/js/spec-driver-browser-extension@1.5.5...js/spec-driver-browser-extension@1.5.6) (2026-07-21)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * @applitools/dom-shared bumped to 1.2.2
9
+ #### Bug Fixes
10
+
11
+ * CSP-safe sandbox opt-out for the MV3 extension content script | AD-14808 ([#3969](https://github.com/Applitools-Dev/sdk/issues/3969)) ([772aefa](https://github.com/Applitools-Dev/sdk/commit/772aefaa3e2bc1eb345fa8d3f6c91ad0913f82e7))
12
+ * @applitools/snippets bumped to 2.9.4
13
+ #### Bug Fixes
14
+
15
+ * bound lazyLoad scroll loop to prevent poll-timeout abort | FLD-4680 ([#3972](https://github.com/Applitools-Dev/sdk/issues/3972)) ([4deea6b](https://github.com/Applitools-Dev/sdk/commit/4deea6b1f6f8ec53bd989cd6bbd021cac2ee3c1e))
16
+
17
+
18
+
19
+ * @applitools/driver bumped to 1.26.6
20
+
21
+ * @applitools/spec-driver-playwright bumped to 1.9.6
22
+
23
+
3
24
  ## [1.5.5](https://github.com/Applitools-Dev/sdk/compare/js/spec-driver-browser-extension@1.5.4...js/spec-driver-browser-extension@1.5.5) (2026-06-28)
4
25
 
5
26
 
package/dist/index.js CHANGED
@@ -28,5 +28,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const spec = __importStar(require("./spec-driver"));
30
30
  __exportStar(require("./refer"), exports);
31
+ __exportStar(require("./page-dispatch"), exports);
31
32
  __exportStar(require("./spec-driver"), exports);
32
33
  exports.default = spec;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // Page-world handlers the content script installs on `window.applitools`: resolve a snippet/poll by its
3
+ // stable id and run it in the page that owns `refer`. See OVERVIEW.md for the dispatch rationale.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.makeRunPoll = exports.makeRunSnippet = void 0;
6
+ // Returns an envelope instead of throwing: MV3 nulls in-page throws, losing the error signal.
7
+ function makeRunSnippet({ snippetById, refer }) {
8
+ return function runSnippet(id, arg) {
9
+ const fn = snippetById.get(id);
10
+ if (!fn)
11
+ return { status: 'error', error: { name: 'SnippetNotFound', message: String(id) } };
12
+ try {
13
+ // Re-ref node returns too: the result is structured-cloned back, which skips Node.toJSON.
14
+ // Snippets are contractually SYNCHRONOUS: every @applitools/snippets export returns a value
15
+ // synchronously. `fn` is called and its return re-ref'd without awaiting, so a Promise-returning
16
+ // snippet would be ref'd as `{}` and drop its value. Any future async snippet must change this seam.
17
+ return { status: 'success', value: refer.ref(fn(refer.deref(arg))) };
18
+ }
19
+ catch (err) {
20
+ return { status: 'error', error: { name: err && err.name, message: err && err.message, stack: err && err.stack } };
21
+ }
22
+ };
23
+ }
24
+ exports.makeRunSnippet = makeRunSnippet;
25
+ // A poll returns its own JSON-string envelope, so pass it back verbatim; catch throws into that shape.
26
+ function makeRunPoll({ pollById, refer }) {
27
+ return function runPoll(id, arg) {
28
+ const fn = pollById.get(id);
29
+ if (!fn)
30
+ return JSON.stringify({ status: 'ERROR', error: 'poll fn not found: ' + id });
31
+ try {
32
+ return fn(refer.deref(arg));
33
+ }
34
+ catch (err) {
35
+ return JSON.stringify({ status: 'ERROR', error: err && err.message });
36
+ }
37
+ };
38
+ }
39
+ exports.makeRunPoll = makeRunPoll;
package/dist/refer.js CHANGED
@@ -26,7 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.makeRefer = void 0;
27
27
  const utils = __importStar(require("@applitools/utils"));
28
28
  const REF_ID = 'applitools-ref-id';
29
- function makeRefer({ check = (_arg) => true, validate = (_arg) => void 0 } = {}) {
29
+ function makeRefer({ check = (_arg) => true, validate = (_arg) => void 0, } = {}) {
30
30
  const store = new Map();
31
31
  const shorthands = new Map();
32
32
  return { isRef, get, ref, deref };
@@ -71,17 +71,66 @@ function extractContext(driver) {
71
71
  return { ...driver, frameId: 0 };
72
72
  }
73
73
  exports.extractContext = extractContext;
74
+ // Re-throw an executeScript-level injection failure, preserving the original stack.
75
+ function throwInjectionError(error) {
76
+ const err = new Error(error.message);
77
+ err.stack = error.stack;
78
+ throw err;
79
+ }
74
80
  async function executeScript(context, script, arg) {
81
+ // Dispatch a stamped snippet by id through the page registry: executeScript structured-clones args
82
+ // (so the content-script deref reviver never fires), and the page returns a {status, value|error}
83
+ // envelope because MV3 nulls in-page throws.
84
+ const snippetName = typeof script === 'function' ? script.snippetName : undefined;
85
+ if (snippetName) {
86
+ const [{ result, error }] = await webextension_polyfill_1.default.scripting.executeScript({
87
+ target: { tabId: context.tabId, frameIds: [context.frameId || 0] },
88
+ func: (id, arg) => window.applitools.runSnippet(id, arg),
89
+ args: [snippetName, arg !== null && arg !== void 0 ? arg : null],
90
+ });
91
+ if (error)
92
+ throwInjectionError(error);
93
+ if (result && result.status === 'error') {
94
+ // Rebuild the error so isStaleElementError can match on `.message`.
95
+ const err = new Error(result.error.message);
96
+ err.name = result.error.name;
97
+ err.stack = result.error.stack;
98
+ throw err;
99
+ }
100
+ if (!result) {
101
+ // A falsy result is MV3 nulling an in-page throw (e.g. the registry isn't installed yet), never a
102
+ // real return — those arrive in a truthy success envelope. Make it recoverable so withRefresh retries.
103
+ throw new Error('StaleElementReferenceError');
104
+ }
105
+ if (result.status === 'success')
106
+ return result.value;
107
+ throw new Error(`runSnippet returned a malformed envelope: ${JSON.stringify(result)}`);
108
+ }
109
+ // Same dispatch for dom-snapshot polls, but the poll already returns its own JSON-string envelope, so
110
+ // pass it back verbatim — no {status, value} wrapping.
111
+ const pollName = typeof script === 'function' ? script.pollName : undefined;
112
+ if (pollName) {
113
+ const [{ result, error }] = await webextension_polyfill_1.default.scripting.executeScript({
114
+ target: { tabId: context.tabId, frameIds: [context.frameId || 0] },
115
+ func: (id, arg) => window.applitools.runPoll(id, arg),
116
+ args: [pollName, arg !== null && arg !== void 0 ? arg : null],
117
+ });
118
+ if (error)
119
+ throwInjectionError(error);
120
+ if (!result) {
121
+ // A falsy result is MV3 nulling an in-page throw (e.g. the registry isn't installed yet), never a
122
+ // real return — runPoll always yields a truthy JSON-string envelope. Make it recoverable so withRefresh retries.
123
+ throw new Error('StaleElementReferenceError');
124
+ }
125
+ return result;
126
+ }
75
127
  const [{ result, error }] = await webextension_polyfill_1.default.scripting.executeScript({
76
128
  target: { tabId: context.tabId, frameIds: [context.frameId || 0] },
77
129
  func: script,
78
- args: [arg || null],
130
+ args: [arg !== null && arg !== void 0 ? arg : null],
79
131
  });
80
- if (error) {
81
- const err = new Error(error.message);
82
- err.stack = error.stack;
83
- throw err;
84
- }
132
+ if (error)
133
+ throwInjectionError(error);
85
134
  return result;
86
135
  }
87
136
  exports.executeScript = executeScript;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/spec-driver-browser-extension",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "keywords": [
5
5
  "playwright",
6
6
  "chrome devtools protocol",
@@ -40,14 +40,14 @@
40
40
  "playwright:setup": "yarn playwright install --with-deps chromium"
41
41
  },
42
42
  "dependencies": {
43
- "@applitools/driver": "1.26.5",
43
+ "@applitools/driver": "1.26.6",
44
44
  "@applitools/utils": "1.15.1",
45
45
  "webextension-polyfill": "0.10.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@applitools/api-extractor": "^1.2.22",
49
49
  "@applitools/logger": "^2.3.0",
50
- "@applitools/spec-driver-playwright": "^1.9.5",
50
+ "@applitools/spec-driver-playwright": "^1.9.6",
51
51
  "@applitools/test-utils": "^1.5.17",
52
52
  "@babel/core": "^7.26.0",
53
53
  "@babel/preset-env": "^7.22.5",
package/types/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as spec from './spec-driver';
2
2
  export * from './refer';
3
+ export * from './page-dispatch';
3
4
  export * from './spec-driver';
4
5
  export default spec;
@@ -0,0 +1,18 @@
1
+ type Refer = {
2
+ ref(value: any): any;
3
+ deref(ref: any): any;
4
+ };
5
+ type PageFn = (arg: any) => any;
6
+ export declare function makeRunSnippet({ snippetById, refer }: {
7
+ snippetById: Map<string, PageFn>;
8
+ refer: Refer;
9
+ }): (id: string, arg: any) => {
10
+ status: 'success' | 'error';
11
+ value?: any;
12
+ error?: any;
13
+ };
14
+ export declare function makeRunPoll({ pollById, refer }: {
15
+ pollById: Map<string, PageFn>;
16
+ refer: Refer;
17
+ }): (id: string, arg: any) => string;
18
+ export {};
package/types/refer.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export declare function makeRefer({ check, validate }?: {
2
- check?: ((_arg: any) => true) | undefined;
3
- validate?: ((_arg: any) => undefined) | undefined;
1
+ export declare function makeRefer({ check, validate, }?: {
2
+ check?: (value: any) => boolean;
3
+ validate?: (value: any) => void;
4
4
  }): {
5
5
  isRef: (ref: any) => boolean;
6
6
  get: (key: any) => any;