@testivai/witness-playwright 1.5.1 → 1.5.2
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/dist/capture/element-map.d.ts +2 -2
- package/dist/capture/element-map.js +41 -12
- package/dist/snapshot.js +2 -1
- package/package.json +1 -1
|
@@ -27,11 +27,11 @@ export interface CollectedElement {
|
|
|
27
27
|
* - `styleHash` digests a fixed, documented list of computed properties
|
|
28
28
|
* (FNV-1a 32-bit, hex) — deterministic for identical rendering.
|
|
29
29
|
*/
|
|
30
|
-
export declare function collectElementMap(doc: Document, win: Window & typeof globalThis, maxElements: number): CollectedElement[];
|
|
30
|
+
export declare function collectElementMap(doc: Document, win: Window & typeof globalThis, maxElements: number, ignoreSelectors?: string[]): CollectedElement[];
|
|
31
31
|
/** Default element cap — bounds capture time and elements.json size. */
|
|
32
32
|
export declare const DEFAULT_MAX_ELEMENTS = 3000;
|
|
33
33
|
/**
|
|
34
34
|
* The page-side expression evaluated by the adapter. Serializes the
|
|
35
35
|
* collector so page code and unit-tested code are the same function.
|
|
36
36
|
*/
|
|
37
|
-
export declare function buildElementMapExpression(maxElements?: number): string;
|
|
37
|
+
export declare function buildElementMapExpression(maxElements?: number, ignoreSelectors?: string[]): string;
|
|
@@ -24,7 +24,7 @@ exports.buildElementMapExpression = buildElementMapExpression;
|
|
|
24
24
|
* - `styleHash` digests a fixed, documented list of computed properties
|
|
25
25
|
* (FNV-1a 32-bit, hex) — deterministic for identical rendering.
|
|
26
26
|
*/
|
|
27
|
-
function collectElementMap(doc, win, maxElements) {
|
|
27
|
+
function collectElementMap(doc, win, maxElements, ignoreSelectors = []) {
|
|
28
28
|
var STYLE_PROPS = [
|
|
29
29
|
'color', 'background-color', 'background-image',
|
|
30
30
|
'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color',
|
|
@@ -84,26 +84,55 @@ function collectElementMap(doc, win, maxElements) {
|
|
|
84
84
|
var stack = [body];
|
|
85
85
|
while (stack.length > 0 && out.length < maxElements) {
|
|
86
86
|
var el = stack.pop();
|
|
87
|
+
// The consistency rule: elements covered by ignoreSelectors are
|
|
88
|
+
// excluded from pixels and the DOM snapshot — they must be excluded
|
|
89
|
+
// from the element map too (subtree included), or their dynamic
|
|
90
|
+
// styles would trip the style fingerprint they were meant to escape.
|
|
91
|
+
var ignored = false;
|
|
92
|
+
if (ignoreSelectors.length > 0 && typeof el.matches === 'function') {
|
|
93
|
+
for (var g = 0; g < ignoreSelectors.length; g++) {
|
|
94
|
+
try {
|
|
95
|
+
if (el.matches(ignoreSelectors[g])) {
|
|
96
|
+
ignored = true;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
// invalid selector — never breaks the walk
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (ignored)
|
|
106
|
+
continue; // skip element AND subtree
|
|
87
107
|
var rect = el.getBoundingClientRect();
|
|
88
108
|
if (rect.width >= 4 && rect.height >= 4) {
|
|
89
109
|
var styleParts = [];
|
|
110
|
+
var hidden = false;
|
|
90
111
|
try {
|
|
91
112
|
var cs = win.getComputedStyle(el);
|
|
92
113
|
for (var p = 0; p < STYLE_PROPS.length; p++) {
|
|
93
|
-
|
|
114
|
+
var value = cs.getPropertyValue(STYLE_PROPS[p]);
|
|
115
|
+
if (STYLE_PROPS[p] === 'visibility' && value === 'hidden')
|
|
116
|
+
hidden = true;
|
|
117
|
+
styleParts.push(STYLE_PROPS[p] + ':' + value);
|
|
94
118
|
}
|
|
95
119
|
}
|
|
96
120
|
catch (e) {
|
|
97
121
|
// styleHash stays a digest of the empty string — still deterministic
|
|
98
122
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
123
|
+
// visibility:hidden elements paint no pixels, so their style changes
|
|
124
|
+
// can never explain a pixel diff — keep them out of the map. Their
|
|
125
|
+
// CHILDREN may override visibility, so the subtree still walks.
|
|
126
|
+
if (!hidden) {
|
|
127
|
+
out.push({
|
|
128
|
+
path: pathOf(el, body),
|
|
129
|
+
x: Math.round((rect.x + scrollX) * dpr),
|
|
130
|
+
y: Math.round((rect.y + scrollY) * dpr),
|
|
131
|
+
width: Math.round(rect.width * dpr),
|
|
132
|
+
height: Math.round(rect.height * dpr),
|
|
133
|
+
styleHash: fnv1a(styleParts.join(';')),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
107
136
|
}
|
|
108
137
|
// Push children in reverse so the walk stays document-ordered
|
|
109
138
|
for (var c = el.children.length - 1; c >= 0; c--) {
|
|
@@ -118,6 +147,6 @@ exports.DEFAULT_MAX_ELEMENTS = 3000;
|
|
|
118
147
|
* The page-side expression evaluated by the adapter. Serializes the
|
|
119
148
|
* collector so page code and unit-tested code are the same function.
|
|
120
149
|
*/
|
|
121
|
-
function buildElementMapExpression(maxElements = exports.DEFAULT_MAX_ELEMENTS) {
|
|
122
|
-
return `(${collectElementMap.toString()})(document, window, ${maxElements})`;
|
|
150
|
+
function buildElementMapExpression(maxElements = exports.DEFAULT_MAX_ELEMENTS, ignoreSelectors = []) {
|
|
151
|
+
return `(${collectElementMap.toString()})(document, window, ${maxElements}, ${JSON.stringify(ignoreSelectors)})`;
|
|
123
152
|
}
|
package/dist/snapshot.js
CHANGED
|
@@ -469,7 +469,8 @@ async function snapshot(page, testInfo, name, config) {
|
|
|
469
469
|
// shift classification, and the style fingerprint on the compare
|
|
470
470
|
// side. Best-effort — the screenshot path never depends on it.
|
|
471
471
|
try {
|
|
472
|
-
const
|
|
472
|
+
const mapIgnores = (0, ignore_selectors_1.collectIgnoreSelectors)(process.cwd(), projectConfig, effectiveConfig);
|
|
473
|
+
const elementMap = await page.evaluate((0, element_map_1.buildElementMapExpression)(undefined, mapIgnores));
|
|
473
474
|
if (Array.isArray(elementMap) && elementMap.length > 0) {
|
|
474
475
|
await fs.writeJson(path.join(localSnapshotDir, 'elements.json'), elementMap);
|
|
475
476
|
}
|