@applitools/dom-snapshot 4.15.2 → 4.15.3

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
@@ -9,6 +9,13 @@
9
9
  - fix style programmatic generated fallback
10
10
  - performance boost
11
11
 
12
+ ## [4.15.3](https://github.com/Applitools-Dev/sdk/compare/js/dom-snapshot@4.15.2...js/dom-snapshot@4.15.3) (2025-12-07)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * capture JavaScript-modified CSS selectors in nested [@layer](https://github.com/layer) rules ([#3391](https://github.com/Applitools-Dev/sdk/issues/3391)) ([b3bceb5](https://github.com/Applitools-Dev/sdk/commit/b3bceb5bfe894f3548173d23942e09d0e04b7e04))
18
+
12
19
  ## [4.15.2](https://github.com/Applitools-Dev/sdk/compare/js/dom-snapshot@4.15.1...js/dom-snapshot@4.15.2) (2025-12-01)
13
20
 
14
21
 
package/README.md CHANGED
@@ -101,6 +101,50 @@ This approach:
101
101
  - Build system remains consistent across all outputs
102
102
  - Consumer packages unaffected during migration
103
103
 
104
+ ### CSS Merging Design Principles
105
+
106
+ The DOM snapshot captures CSS from two sources to ensure **cross-browser re-renderability**:
107
+
108
+ 1. **textContent** - Raw CSS as written in `<style>` tags (source code)
109
+ 2. **CSSOM** - Browser's runtime CSS Object Model (computed state)
110
+
111
+ #### Why Merge Both Sources?
112
+
113
+ Different browsers have varying CSS support levels. By merging both sources, we ensure:
114
+ - ✅ **Browser-specific syntax is preserved** (e.g., `-webkit-appearance`, vendor prefixes)
115
+ - ✅ **Unsupported CSS features are captured** (e.g., CSS nesting in older browsers)
116
+ - ✅ **Runtime modifications are included** (e.g., JavaScript-modified styles)
117
+ - ✅ **Snapshots render correctly across browsers** with different CSS capabilities
118
+
119
+ #### Design Trade-off: Re-renderability vs Runtime State
120
+
121
+ When CSS exists in textContent but not in CSSOM, we **cannot distinguish** between:
122
+
123
+ 1. **Browser limitation** - CSSOM doesn't support the syntax (e.g., vendor prefixes, new CSS features)
124
+ - ✅ **Should preserve** for cross-browser re-renderability
125
+
126
+ 2. **JavaScript removal** - JavaScript explicitly deleted the CSS at runtime
127
+ - ❌ **Ideally wouldn't preserve** since it was intentionally removed
128
+
129
+ **Our Choice: Prioritize Re-renderability**
130
+
131
+ We choose to **preserve textContent when CSSOM is missing**, accepting the trade-off that we might include CSS that JavaScript intentionally removed. This decision:
132
+
133
+ - ✅ Maximizes cross-browser compatibility
134
+ - ✅ Ensures vendor-specific CSS works where supported
135
+ - ✅ Captures emerging CSS features not yet in CSSOM
136
+ - ❌ May include runtime-deleted CSS (unavoidable without JS tracking)
137
+
138
+ This is consistent with how we handle vendor prefixes and other browser-specific CSS throughout the package.
139
+
140
+ #### Implementation Details
141
+
142
+ See `src/browser/cssom/mergeRules.ts` for the merging algorithm, which:
143
+ - Recursively merges CSS rules from textContent and CSSOM
144
+ - Preserves nested rules (CSS nesting with `&`) from either source
145
+ - Handles style property conflicts by preferring CSSOM values
146
+ - Maintains both vendor-prefixed and normalized property versions
147
+
104
148
  ## Installing
105
149
 
106
150
  ```sh
@@ -1,4 +1,4 @@
1
- /* @applitools/dom-snapshot@4.15.2 */
1
+ /* @applitools/dom-snapshot@4.15.3 */
2
2
  function __pollResult() {
3
3
  var pollResult=function(){"use strict";return function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=function(t){return function(){var t={};function e(t,e=0){const n=t.charCodeAt(e);return n>=55296&&n<56320?1024*(n-55296)+(t.charCodeAt(e+1)-56320)+65536:56320<=n&&n<=57343?-1:n}var n=function(t,n){const r=[];let o=0;for(let c=0;c<t.length;++c){const u=e(t,c);let a=0;u>0&&(a=u<128?1:u<2048?2:u<65536?3:u<2097152?4:u<67108864?5:6),o+a>n?(r.push(c),o=a):o+=a}return r};const r=function(t){return t&&t.__esModule?t:{default:t}}(n),o="WIP",c="SUCCESS",u="SUCCESS_CHUNKED",a="ERROR";var s=function(t,e,n={}){const s=function(t,{chunkByteLength:e=0}={}){if(t){if(t.value){if(e){if(!t.chunks)try{const n=JSON.stringify(t.value);t.chunks=(0,r.default)(n,e),t.chunks.length>0&&(t.from=0,t.value=n)}catch(t){return{status:a,error:t.message}}if(t.from>=0)return{status:u,value:t.value.substring(t.from,t.from=t.chunks.shift()),done:!t.from}}return{status:c,value:t.value}}return t.error?{status:a,error:t.error}:{status:o}}return{status:a,error:"unexpected poll request received - cannot find state of current operation"}}((t=t||{})[e],n);return(s.status===c||s.status===a||s.status===u&&s.done)&&delete t[e],s};const i=s;var l=function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(t,"__esModule",{value:!0}),t.isAccessibleFrame=t.isInlineFrame=t.absolutizeUrl=p=t.poll=t.pollify=t.chunkify=void 0;const f=l(n);t.chunkify=f.default;const d=l((function(t,e,n){return r=>function(...o){return e[n]||(e[n]={},Promise.resolve().then((()=>t(...o))).then((t=>e[n].value=t)).catch((t=>e[n].error=t.message+"\nStack:"+t.stack))),i(e,n,r)}}));t.pollify=d.default;const h=l(s);var p=t.poll=h.default;const m=l((function(t,e){if(function(t){try{return new URL(t),!0}catch(t){return!1}}(t))return t;let n=!0;try{n=t!==decodeURI(t)}catch(t){n=!0}try{const r=new URL(t,e).href;return n?r:decodeURI(r)}catch(e){return n?t:decodeURI(t)}}));t.absolutizeUrl=m.default;const v=l((function(t){return t.contentDocument&&t.contentDocument.location&&!/^https?:$/.test(t.contentDocument.location.protocol)}));t.isInlineFrame=v.default;const y=l((function(t){try{const e=t.contentDocument;return Boolean(e&&e.defaultView&&e.defaultView.frameElement)}catch(t){return!1}}));return t.isAccessibleFrame=y.default,function(t){try{return JSON.stringify(p(window.__EYES__APPLITOOLS__,"domSnapshotResult",t))}catch(t){return JSON.stringify({status:"ERROR",error:t.message})}}}()},r=!0;try{var o=window.__applitools_sandbox;o||((o=document.createElement("iframe")).setAttribute("data-applitools-sandbox",""),o.setAttribute("data-applitools-skip",""),document.head.appendChild(o),window.__applitools_sandbox=o);var c=window.crypto.getRandomValues(new Uint32Array(1))[0],u=o.contentDocument.createElement("script");u.textContent="window['ctor-".concat(c,"'] = ").concat(n.toString(),";"),o.contentDocument.head.appendChild(u);var a=o.contentWindow["ctor-".concat(c)];if("function"!=typeof a)throw new Error("Sandbox failed to extract function");return r=!1,a(document).apply(void 0,t)}catch(e){try{return n(document).apply(void 0,t)}catch(t){throw r?t:e}}}}();
4
4
  //# sourceMappingURL=pollResult.js.map
@@ -1,3 +1,3 @@
1
- /* @applitools/dom-snapshot@4.15.2 */
1
+ /* @applitools/dom-snapshot@4.15.3 */
2
2
  "use strict";module.exports=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=function(t){return function(){var t={};function e(t,e=0){const n=t.charCodeAt(e);return n>=55296&&n<56320?1024*(n-55296)+(t.charCodeAt(e+1)-56320)+65536:56320<=n&&n<=57343?-1:n}var n=function(t,n){const r=[];let o=0;for(let c=0;c<t.length;++c){const u=e(t,c);let a=0;u>0&&(a=u<128?1:u<2048?2:u<65536?3:u<2097152?4:u<67108864?5:6),o+a>n?(r.push(c),o=a):o+=a}return r};const r=function(t){return t&&t.__esModule?t:{default:t}}(n),o="WIP",c="SUCCESS",u="SUCCESS_CHUNKED",a="ERROR";var s=function(t,e,n={}){const s=function(t,{chunkByteLength:e=0}={}){if(t){if(t.value){if(e){if(!t.chunks)try{const n=JSON.stringify(t.value);t.chunks=(0,r.default)(n,e),t.chunks.length>0&&(t.from=0,t.value=n)}catch(t){return{status:a,error:t.message}}if(t.from>=0)return{status:u,value:t.value.substring(t.from,t.from=t.chunks.shift()),done:!t.from}}return{status:c,value:t.value}}return t.error?{status:a,error:t.error}:{status:o}}return{status:a,error:"unexpected poll request received - cannot find state of current operation"}}((t=t||{})[e],n);return(s.status===c||s.status===a||s.status===u&&s.done)&&delete t[e],s};const i=s;var l=function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(t,"__esModule",{value:!0}),t.isAccessibleFrame=t.isInlineFrame=t.absolutizeUrl=p=t.poll=t.pollify=t.chunkify=void 0;const f=l(n);t.chunkify=f.default;const d=l((function(t,e,n){return r=>function(...o){return e[n]||(e[n]={},Promise.resolve().then((()=>t(...o))).then((t=>e[n].value=t)).catch((t=>e[n].error=t.message+"\nStack:"+t.stack))),i(e,n,r)}}));t.pollify=d.default;const h=l(s);var p=t.poll=h.default;const m=l((function(t,e){if(function(t){try{return new URL(t),!0}catch(t){return!1}}(t))return t;let n=!0;try{n=t!==decodeURI(t)}catch(t){n=!0}try{const r=new URL(t,e).href;return n?r:decodeURI(r)}catch(e){return n?t:decodeURI(t)}}));t.absolutizeUrl=m.default;const v=l((function(t){return t.contentDocument&&t.contentDocument.location&&!/^https?:$/.test(t.contentDocument.location.protocol)}));t.isInlineFrame=v.default;const y=l((function(t){try{const e=t.contentDocument;return Boolean(e&&e.defaultView&&e.defaultView.frameElement)}catch(t){return!1}}));return t.isAccessibleFrame=y.default,function(t){try{return JSON.stringify(p(window.__EYES__APPLITOOLS__,"domSnapshotResult",t))}catch(t){return JSON.stringify({status:"ERROR",error:t.message})}}}()},r=!0;try{var o=window.__applitools_sandbox;o||((o=document.createElement("iframe")).setAttribute("data-applitools-sandbox",""),o.setAttribute("data-applitools-skip",""),document.head.appendChild(o),window.__applitools_sandbox=o);var c=window.crypto.getRandomValues(new Uint32Array(1))[0],u=o.contentDocument.createElement("script");u.textContent="window['ctor-".concat(c,"'] = ").concat(n.toString(),";"),o.contentDocument.head.appendChild(u);var a=o.contentWindow["ctor-".concat(c)];if("function"!=typeof a)throw new Error("Sandbox failed to extract function");return r=!1,a(document).apply(void 0,t)}catch(e){try{return n(document).apply(void 0,t)}catch(t){throw r?t:e}}};
3
3
  //# sourceMappingURL=pollResultCjs.js.map
@@ -1,3 +1,3 @@
1
- /* @applitools/dom-snapshot@4.15.2 */
1
+ /* @applitools/dom-snapshot@4.15.3 */
2
2
  function t(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=function(t){return function(){var t={};function e(t,e=0){const n=t.charCodeAt(e);return n>=55296&&n<56320?1024*(n-55296)+(t.charCodeAt(e+1)-56320)+65536:56320<=n&&n<=57343?-1:n}var n=function(t,n){const r=[];let o=0;for(let c=0;c<t.length;++c){const u=e(t,c);let a=0;u>0&&(a=u<128?1:u<2048?2:u<65536?3:u<2097152?4:u<67108864?5:6),o+a>n?(r.push(c),o=a):o+=a}return r};const r=function(t){return t&&t.__esModule?t:{default:t}}(n),o="WIP",c="SUCCESS",u="SUCCESS_CHUNKED",a="ERROR";var s=function(t,e,n={}){const s=function(t,{chunkByteLength:e=0}={}){if(t){if(t.value){if(e){if(!t.chunks)try{const n=JSON.stringify(t.value);t.chunks=(0,r.default)(n,e),t.chunks.length>0&&(t.from=0,t.value=n)}catch(t){return{status:a,error:t.message}}if(t.from>=0)return{status:u,value:t.value.substring(t.from,t.from=t.chunks.shift()),done:!t.from}}return{status:c,value:t.value}}return t.error?{status:a,error:t.error}:{status:o}}return{status:a,error:"unexpected poll request received - cannot find state of current operation"}}((t=t||{})[e],n);return(s.status===c||s.status===a||s.status===u&&s.done)&&delete t[e],s};const i=s;var l=function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(t,"__esModule",{value:!0}),t.isAccessibleFrame=t.isInlineFrame=t.absolutizeUrl=p=t.poll=t.pollify=t.chunkify=void 0;const f=l(n);t.chunkify=f.default;const d=l((function(t,e,n){return r=>function(...o){return e[n]||(e[n]={},Promise.resolve().then((()=>t(...o))).then((t=>e[n].value=t)).catch((t=>e[n].error=t.message+"\nStack:"+t.stack))),i(e,n,r)}}));t.pollify=d.default;const h=l(s);var p=t.poll=h.default;const m=l((function(t,e){if(function(t){try{return new URL(t),!0}catch(t){return!1}}(t))return t;let n=!0;try{n=t!==decodeURI(t)}catch(t){n=!0}try{const r=new URL(t,e).href;return n?r:decodeURI(r)}catch(e){return n?t:decodeURI(t)}}));t.absolutizeUrl=m.default;const v=l((function(t){return t.contentDocument&&t.contentDocument.location&&!/^https?:$/.test(t.contentDocument.location.protocol)}));t.isInlineFrame=v.default;const y=l((function(t){try{const e=t.contentDocument;return Boolean(e&&e.defaultView&&e.defaultView.frameElement)}catch(t){return!1}}));return t.isAccessibleFrame=y.default,function(t){try{return JSON.stringify(p(window.__EYES__APPLITOOLS__,"domSnapshotResult",t))}catch(t){return JSON.stringify({status:"ERROR",error:t.message})}}}()},r=!0;try{var o=window.__applitools_sandbox;o||((o=document.createElement("iframe")).setAttribute("data-applitools-sandbox",""),o.setAttribute("data-applitools-skip",""),document.head.appendChild(o),window.__applitools_sandbox=o);var c=window.crypto.getRandomValues(new Uint32Array(1))[0],u=o.contentDocument.createElement("script");u.textContent="window['ctor-".concat(c,"'] = ").concat(n.toString(),";"),o.contentDocument.head.appendChild(u);var a=o.contentWindow["ctor-".concat(c)];if("function"!=typeof a)throw new Error("Sandbox failed to extract function");return r=!1,a(document).apply(void 0,t)}catch(e){try{return n(document).apply(void 0,t)}catch(t){throw r?t:e}}}export{t as default};
3
3
  //# sourceMappingURL=pollResultEs.js.map