@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.
@@ -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
- styleParts.push(STYLE_PROPS[p] + ':' + cs.getPropertyValue(STYLE_PROPS[p]));
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
- out.push({
100
- path: pathOf(el, body),
101
- x: Math.round((rect.x + scrollX) * dpr),
102
- y: Math.round((rect.y + scrollY) * dpr),
103
- width: Math.round(rect.width * dpr),
104
- height: Math.round(rect.height * dpr),
105
- styleHash: fnv1a(styleParts.join(';')),
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 elementMap = await page.evaluate((0, element_map_1.buildElementMapExpression)());
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testivai/witness-playwright",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "Playwright sensor for Testivai Visual Regression Test system",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",