flexysnap 0.2.4-alpha.1 → 0.2.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/README.md +15 -8
- package/package.json +2 -2
- package/src/wireframeComparison.js +7 -13
- package/src/wireframeUtils.js +135 -94
package/README.md
CHANGED
|
@@ -44,6 +44,7 @@ const elementGroups = [
|
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
- `strictPosition: false` — compare element size only, not exact position.
|
|
47
|
+
- `strictSize: false` — for position-tolerant groups, compare size by ratio rather than absolute pixel difference.
|
|
47
48
|
- `maskDigits: true` — replace digit runs with a placeholder before comparing text.
|
|
48
49
|
- `textIgnoreClasses` — skip text found inside elements carrying these class names, at any ancestor level.
|
|
49
50
|
|
|
@@ -95,6 +96,7 @@ test('product page wireframe', async ({ page }) => {
|
|
|
95
96
|
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
96
97
|
"scrollPosition": { "x": 0, "y": 0 },
|
|
97
98
|
"screenshotScrollPosition": { "x": 0, "y": 0 },
|
|
99
|
+
"deviceScaleFactor": 1,
|
|
98
100
|
"elementGroups": [
|
|
99
101
|
{
|
|
100
102
|
"selector": ".product-title",
|
|
@@ -127,11 +129,14 @@ Anything passed as `options.metadata` is merged into the top level of this objec
|
|
|
127
129
|
### Test utilities
|
|
128
130
|
|
|
129
131
|
- `waitForCompleteLoad(page)` — wait for `domcontentloaded`, `load`, and a settle delay.
|
|
132
|
+
- `gotoWithRetry(page, url)` — navigate to a URL, retrying once on failure, then wait for the page to finish loading.
|
|
130
133
|
- `click(page, locator)` — resilient click that closes popups, re-hovers, scrolls into view, and retries.
|
|
131
134
|
- `highlightedClick(page, locator)` — scroll a locator into the viewport and force-click it.
|
|
132
135
|
- `hover(page, locator)` — hover a locator and remember it for re-hovering.
|
|
133
136
|
- `rehover(page)` — re-hover the last hovered locator.
|
|
134
137
|
- `fill(page, field, value)` — click and fill an input by name or locator.
|
|
138
|
+
- `selectOption(page, field, value)` — click and select an option by name or locator.
|
|
139
|
+
- `scrollToTopOfElement(page, target, offset?)` — scroll so a locator (or selector string) is positioned near the top of the viewport, minus an optional offset in pixels.
|
|
135
140
|
- `setClosePopups(fn)` — register a function used to dismiss popups before interactions.
|
|
136
141
|
- `setBaseUrl(url)` — set the base URL used for request cache-busting.
|
|
137
142
|
- `logTimestamp(eventName)` — log an event with elapsed time since test start.
|
|
@@ -142,20 +147,22 @@ Anything passed as `options.metadata` is merged into the top level of this objec
|
|
|
142
147
|
- `options.retryDelay` (default `1000`) — minimum milliseconds between stability samples.
|
|
143
148
|
- `options.maxRetryCount` (default `10`) — maximum number of extraction attempts.
|
|
144
149
|
- `options.metadata` (default `{}`) — extra fields merged into the written JSON.
|
|
150
|
+
- `options.closePopups` (default no-op) — function called before each element group extraction to dismiss popups.
|
|
145
151
|
- `getRGBHistogramFromBuffer(buffer)` — compute a 48-bin RGB histogram (16 bins per channel, values normalized to percentages) from an image buffer.
|
|
146
152
|
|
|
147
153
|
### Wireframe comparison
|
|
148
154
|
|
|
149
|
-
- `compareWireframes(baselineWireframe, currentWireframe)` — diff two wireframes and
|
|
150
|
-
- `compareElements(baselineElement, currentElement, strictPosition?, maskDigits?)`
|
|
151
|
-
- `compareTexts(baselineTexts, currentTexts, strictPosition?, maskDigits?)`
|
|
152
|
-
- `compareBoundingBoxes(baselineRect, currentRect, tolerance?, strictPosition?)`
|
|
153
|
-
- `createPairings(currentElements, baselineElements)` — nearest bounding-box matching between two element sets, returning `{ matchedPairs, unmatchedCurrent, unmatchedBaseline }`.
|
|
154
|
-
- `histogramDiff(a, b)` — sum of absolute differences between two histograms.
|
|
155
|
+
- `compareWireframes(baselineWireframe, currentWireframe)` — diff two wireframes and return the current wireframe annotated with `differences`. Element groups are matched by index and must appear in the same order and count in both wireframes. Within each group, elements are paired with the baseline using nearest bounding-box matching, then diffed for layout shifts, size mismatches, text mismatches, and image histogram differences. Elements missing from the current capture are appended to the current wireframe's element groups so they still appear in the output, marked as `missing_element` (or `missing_text`).
|
|
155
156
|
|
|
156
157
|
### Stability
|
|
157
158
|
|
|
158
|
-
- `areWireframesStable(previousWireframeData, currentWireframeData)` — determine whether two consecutive captures are stable enough to trust.
|
|
159
|
+
- `areWireframesStable(previousWireframeData, currentWireframeData)` — determine whether two consecutive captures are stable enough to trust, by checking for empty element groups, mismatched element counts, text content differences, and overall bounding-box size drift.
|
|
160
|
+
|
|
161
|
+
### Output paths
|
|
162
|
+
|
|
163
|
+
- `setWireframeOutputRoot(rootPath)` — set the root directory used to resolve relative output directories (defaults to `process.cwd()`).
|
|
164
|
+
- `getWireframeOutputRoot()` — get the currently configured output root.
|
|
165
|
+
- `resolveWireframeOutputDir(outputDir)` — resolve an output directory against the configured root; absolute paths are returned unchanged.
|
|
159
166
|
|
|
160
167
|
## How it works
|
|
161
168
|
|
|
@@ -243,4 +250,4 @@ Issues and pull requests are welcome. Please open an issue before submitting lar
|
|
|
243
250
|
|
|
244
251
|
## License
|
|
245
252
|
|
|
246
|
-
MIT
|
|
253
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flexysnap",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Flexible visual snapshot testing for Playwright, built for e-commerce.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playwright",
|
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"eslint": "^9.9.0"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|
|
@@ -166,16 +166,8 @@ function compareTexts(baselineTexts, currentTexts, strictPosition = true, strict
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
function compareElements(baselineElement, currentElement, strictPosition = true, strictSize = true, maskDigits = false) {
|
|
169
|
-
currentElement.differences = compareBoundingBoxes(
|
|
170
|
-
baselineElement.boundingRect,
|
|
171
|
-
currentElement.boundingRect,
|
|
172
|
-
strictPosition,
|
|
173
|
-
strictSize
|
|
174
|
-
);
|
|
175
|
-
|
|
176
169
|
if (baselineElement.histogram && currentElement.histogram) {
|
|
177
170
|
const dh = histogramDiff(baselineElement.histogram, currentElement.histogram);
|
|
178
|
-
//expect.soft(dh, 'Histogram difference').toBeLessThanOrEqual(10);
|
|
179
171
|
if (dh > 15) {
|
|
180
172
|
currentElement.differences.push({
|
|
181
173
|
type: 'histogram_difference',
|
|
@@ -185,6 +177,13 @@ function compareElements(baselineElement, currentElement, strictPosition = true,
|
|
|
185
177
|
|
|
186
178
|
if (baselineElement.texts.length > 0 || currentElement.texts.length > 0) {
|
|
187
179
|
compareTexts(baselineElement.texts, currentElement.texts, strictPosition, strictSize, maskDigits);
|
|
180
|
+
} else {
|
|
181
|
+
currentElement.differences = compareBoundingBoxes(
|
|
182
|
+
baselineElement.boundingRect,
|
|
183
|
+
currentElement.boundingRect,
|
|
184
|
+
strictPosition,
|
|
185
|
+
strictSize
|
|
186
|
+
);
|
|
188
187
|
}
|
|
189
188
|
}
|
|
190
189
|
|
|
@@ -204,11 +203,6 @@ function compareWireframes(baselineWireframe, currentWireframe) {
|
|
|
204
203
|
const strictPosition = currentElementGroup.strictPosition !== false;
|
|
205
204
|
const strictSize = currentElementGroup.strictSize !== false;
|
|
206
205
|
const maskDigits = currentElementGroup.maskDigits === true;
|
|
207
|
-
|
|
208
|
-
//TODO: REMOVE later
|
|
209
|
-
if (currentElementGroup.differences?.length === 0) {
|
|
210
|
-
currentElementGroup.differences = undefined
|
|
211
|
-
}
|
|
212
206
|
|
|
213
207
|
const { matchedPairs, unmatchedCurrent, unmatchedBaseline } = createPairings(
|
|
214
208
|
currentElementGroup.elements,
|
package/src/wireframeUtils.js
CHANGED
|
@@ -6,6 +6,7 @@ import { areWireframesStable } from './wireframeStability.js';
|
|
|
6
6
|
import { resolveWireframeOutputDir } from './wireframeOutput.js';
|
|
7
7
|
|
|
8
8
|
const FLEXYSNAP_ELEMENT_ID_ATTRIBUTE = 'data-flexysnap-id';
|
|
9
|
+
const ELEMENT_GROUP_EXTRACTION_TIMEOUT_MS = 5000;
|
|
9
10
|
|
|
10
11
|
async function getRGBHistogramFromBuffer(buffer) {
|
|
11
12
|
const image = await loadImage(buffer);
|
|
@@ -39,6 +40,15 @@ function delay(milliseconds) {
|
|
|
39
40
|
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
function withTimeout(promise, milliseconds, timeoutMessage) {
|
|
44
|
+
let timeoutHandle;
|
|
45
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
46
|
+
timeoutHandle = setTimeout(() => reject(new Error(timeoutMessage)), milliseconds);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timeoutHandle));
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
async function getDeviceScaleFactor(page) {
|
|
43
53
|
try {
|
|
44
54
|
const scaleFactor = await page.evaluate(() => window.devicePixelRatio);
|
|
@@ -92,66 +102,62 @@ function scaleWireframeData(wireframeData, scaleFactor) {
|
|
|
92
102
|
return wireframeData;
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
right: Math.round(rect.right)
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function getTextNodeBoundingBox(textNode) {
|
|
109
|
-
const range = document.createRange();
|
|
110
|
-
range.selectNodeContents(textNode);
|
|
111
|
-
const rect = range.getBoundingClientRect();
|
|
112
|
-
return {
|
|
113
|
-
top: Math.round(rect.top),
|
|
114
|
-
left: Math.round(rect.left),
|
|
115
|
-
bottom: Math.round(rect.bottom),
|
|
116
|
-
right: Math.round(rect.right)
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function isElementVisible(element) {
|
|
121
|
-
const style = window.getComputedStyle(element);
|
|
122
|
-
if (style.display === 'none' ||
|
|
123
|
-
style.visibility === 'hidden' ||
|
|
124
|
-
style.opacity === '0' ||
|
|
125
|
-
element.offsetWidth <= 0 ||
|
|
126
|
-
element.offsetHeight <= 0) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const rect = element.getBoundingClientRect()
|
|
131
|
-
|
|
132
|
-
return rect.right >= 0 &&
|
|
133
|
-
rect.left < window.innerWidth &&
|
|
134
|
-
rect.bottom >= 0 &&
|
|
135
|
-
rect.top < window.innerHeight;
|
|
136
|
-
}
|
|
105
|
+
function createEmptyElementGroupResult(elementGroup) {
|
|
106
|
+
return {
|
|
107
|
+
...elementGroup,
|
|
108
|
+
strictPosition: elementGroup.strictPosition !== false,
|
|
109
|
+
strictSize: elementGroup.strictSize !== false,
|
|
110
|
+
maskDigits: elementGroup.maskDigits !== false,
|
|
111
|
+
elements: []
|
|
112
|
+
};
|
|
113
|
+
}
|
|
137
114
|
|
|
115
|
+
async function extractElementGroupData(page, elementGroup, groupIndex, elementIdAttribute) {
|
|
116
|
+
const extractionStartTime = Date.now();
|
|
138
117
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
elementGroup
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
118
|
+
try {
|
|
119
|
+
const result = await withTimeout(
|
|
120
|
+
page.evaluate(({elementGroup, groupIndex, elementIdAttribute}) => {
|
|
121
|
+
|
|
122
|
+
function createBoundingRect(element) {
|
|
123
|
+
const rect = element.getBoundingClientRect();
|
|
124
|
+
return {
|
|
125
|
+
top: Math.round(rect.top),
|
|
126
|
+
left: Math.round(rect.left),
|
|
127
|
+
bottom: Math.round(rect.bottom),
|
|
128
|
+
right: Math.round(rect.right)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
145
131
|
|
|
146
|
-
|
|
147
|
-
|
|
132
|
+
function getTextNodeBoundingBox(textNode) {
|
|
133
|
+
const range = document.createRange();
|
|
134
|
+
range.selectNodeContents(textNode);
|
|
135
|
+
const rect = range.getBoundingClientRect();
|
|
136
|
+
return {
|
|
137
|
+
top: Math.round(rect.top),
|
|
138
|
+
left: Math.round(rect.left),
|
|
139
|
+
bottom: Math.round(rect.bottom),
|
|
140
|
+
right: Math.round(rect.right)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
function isElementVisible(element) {
|
|
145
|
+
const style = window.getComputedStyle(element);
|
|
146
|
+
if (style.display === 'none' ||
|
|
147
|
+
style.visibility === 'hidden' ||
|
|
148
|
+
style.opacity === '0' ||
|
|
149
|
+
element.offsetWidth <= 0 ||
|
|
150
|
+
element.offsetHeight <= 0) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
152
153
|
|
|
154
|
+
const rect = element.getBoundingClientRect()
|
|
153
155
|
|
|
154
|
-
|
|
156
|
+
return rect.right >= 0 &&
|
|
157
|
+
rect.left < window.innerWidth &&
|
|
158
|
+
rect.bottom >= 0 &&
|
|
159
|
+
rect.top < window.innerHeight;
|
|
160
|
+
}
|
|
155
161
|
|
|
156
162
|
function getElementsWithDirectText(root, textIgnoreClasses) {
|
|
157
163
|
const results = [];
|
|
@@ -168,7 +174,6 @@ async function extractWireframe(page, elementGroups) {
|
|
|
168
174
|
|
|
169
175
|
if (textIgnoreClasses) {
|
|
170
176
|
let ignored = false;
|
|
171
|
-
console.log(textIgnoreClasses);
|
|
172
177
|
let parent = walker.currentNode.parentElement;
|
|
173
178
|
while (parent != null && !ignored) {
|
|
174
179
|
for (const className of parent.classList) {
|
|
@@ -192,52 +197,88 @@ async function extractWireframe(page, elementGroups) {
|
|
|
192
197
|
return results;
|
|
193
198
|
}
|
|
194
199
|
|
|
195
|
-
|
|
200
|
+
elementGroup.strictPosition = elementGroup.strictPosition !== false;
|
|
201
|
+
elementGroup.strictSize = elementGroup.strictSize !== false;
|
|
202
|
+
elementGroup.maskDigits = elementGroup.maskDigits !== false;
|
|
203
|
+
elementGroup.elements = [];
|
|
196
204
|
|
|
197
|
-
|
|
205
|
+
let index = 0;
|
|
206
|
+
const matchedElements = document.querySelectorAll(elementGroup.selector);
|
|
198
207
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
for (const element of matchedElements) {
|
|
209
|
+
if (!isElementVisible(element))
|
|
210
|
+
continue;
|
|
202
211
|
|
|
203
|
-
|
|
204
|
-
if (text.length === 0)
|
|
205
|
-
continue;
|
|
212
|
+
const texts = [];
|
|
206
213
|
|
|
207
|
-
|
|
208
|
-
other !== descendant && other.contains(descendant)
|
|
209
|
-
);
|
|
214
|
+
if (elementGroup.type === 'text') {
|
|
210
215
|
|
|
211
|
-
|
|
212
|
-
continue;
|
|
216
|
+
const descendantArray = getElementsWithDirectText(element, elementGroup.textIgnoreClasses)
|
|
213
217
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
for (const descendant of descendantArray) {
|
|
219
|
+
if (!isElementVisible(descendant.parentElement))
|
|
220
|
+
continue;
|
|
221
|
+
|
|
222
|
+
const text = descendant.textContent.trim().replaceAll(/\s+/g, ' ')
|
|
223
|
+
if (text.length === 0)
|
|
224
|
+
continue;
|
|
225
|
+
|
|
226
|
+
const isNested = descendantArray.some(other =>
|
|
227
|
+
other !== descendant && other.contains(descendant)
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (isNested)
|
|
231
|
+
continue;
|
|
232
|
+
|
|
233
|
+
texts.push({
|
|
234
|
+
text: text,
|
|
235
|
+
boundingRect: getTextNodeBoundingBox(descendant)
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const elementData = {
|
|
241
|
+
index: index,
|
|
242
|
+
boundingRect: createBoundingRect(element),
|
|
243
|
+
texts: texts,
|
|
244
|
+
type: elementGroup.type
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (elementGroup.type === 'image') {
|
|
248
|
+
const elementId = `fsnap-g${groupIndex}-e${index}`;
|
|
249
|
+
element.setAttribute(elementIdAttribute, elementId);
|
|
250
|
+
elementData.elementId = elementId;
|
|
218
251
|
}
|
|
219
|
-
}
|
|
220
252
|
|
|
221
|
-
|
|
222
|
-
index
|
|
223
|
-
boundingRect: createBoundingRect(element),
|
|
224
|
-
texts: texts,
|
|
225
|
-
type: elementGroup.type
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
if (elementGroup.type === 'image') {
|
|
229
|
-
const elementId = `fsnap-g${groupIndex}-e${index}`;
|
|
230
|
-
element.setAttribute(elementIdAttribute, elementId);
|
|
231
|
-
elementData.elementId = elementId;
|
|
253
|
+
elementGroup.elements.push(elementData);
|
|
254
|
+
index += 1;
|
|
232
255
|
}
|
|
233
256
|
|
|
234
|
-
elementGroup
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
257
|
+
return elementGroup;
|
|
258
|
+
}, {elementGroup, groupIndex, elementIdAttribute}),
|
|
259
|
+
ELEMENT_GROUP_EXTRACTION_TIMEOUT_MS,
|
|
260
|
+
`Timed out extracting element group with selector "${elementGroup.selector}"`
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const extractionDuration = Date.now() - extractionStartTime;
|
|
264
|
+
logTimestamp(`Extracted element group "${elementGroup.selector}" in ${extractionDuration/1000} seconds.`);
|
|
265
|
+
|
|
266
|
+
return result;
|
|
267
|
+
} catch (error) {
|
|
268
|
+
const extractionDuration = Date.now() - extractionStartTime;
|
|
269
|
+
logTimestamp(`Failed to extract element group "${elementGroup.selector}" after ${extractionDuration/1000} seconds: ${error.message}`);
|
|
270
|
+
return createEmptyElementGroupResult(elementGroup);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
238
273
|
|
|
239
|
-
|
|
240
|
-
|
|
274
|
+
async function extractWireframe(page, elementGroups, closePopups) {
|
|
275
|
+
const wireframeData = [];
|
|
276
|
+
|
|
277
|
+
for (let groupIndex = 0; groupIndex < elementGroups.length; groupIndex++) {
|
|
278
|
+
closePopups();
|
|
279
|
+
const elementGroupData = await extractElementGroupData(page, elementGroups[groupIndex], groupIndex, FLEXYSNAP_ELEMENT_ID_ATTRIBUTE);
|
|
280
|
+
wireframeData.push(elementGroupData);
|
|
281
|
+
}
|
|
241
282
|
|
|
242
283
|
const scrollPosition = await page.evaluate(() => ({
|
|
243
284
|
x: window.scrollX,
|
|
@@ -294,14 +335,14 @@ function cloneElementGroups(elementGroups) {
|
|
|
294
335
|
return elementGroups.map(elementGroup => ({...elementGroup, elements: undefined}));
|
|
295
336
|
}
|
|
296
337
|
|
|
297
|
-
async function extractStableWireframe(page, elementGroups, retryDelay, maxRetryCount) {
|
|
338
|
+
async function extractStableWireframe(page, elementGroups, retryDelay, maxRetryCount, closePopups) {
|
|
298
339
|
let previousWireframeData = null;
|
|
299
340
|
let currentWireframeData = null;
|
|
300
341
|
let currentScrollPosition = null;
|
|
301
342
|
|
|
302
343
|
for (let attempt = 0; attempt < maxRetryCount; attempt++) {
|
|
303
344
|
const extractionStartTime = Date.now();
|
|
304
|
-
const extractionResult = await extractWireframe(page, cloneElementGroups(elementGroups));
|
|
345
|
+
const extractionResult = await extractWireframe(page, cloneElementGroups(elementGroups), closePopups);
|
|
305
346
|
currentWireframeData = extractionResult.wireframeData;
|
|
306
347
|
currentScrollPosition = extractionResult.scrollPosition;
|
|
307
348
|
const extractionDuration = Date.now() - extractionStartTime;
|
|
@@ -327,10 +368,10 @@ async function extractStableWireframe(page, elementGroups, retryDelay, maxRetryC
|
|
|
327
368
|
}
|
|
328
369
|
|
|
329
370
|
async function expectWireframe(page, elementGroups, outputDir, outputFile, outputName, options = {}) {
|
|
330
|
-
const { retryDelay = 1000, maxRetryCount = 10, metadata = {} } = options;
|
|
371
|
+
const { retryDelay = 1000, maxRetryCount = 10, metadata = {}, closePopups = function() {} } = options;
|
|
331
372
|
|
|
332
373
|
logTimestamp(`Starting wireframe capture for: ${outputFile}`);
|
|
333
|
-
const { wireframeData, scrollPosition } = await extractStableWireframe(page, elementGroups, retryDelay, maxRetryCount);
|
|
374
|
+
const { wireframeData, scrollPosition } = await extractStableWireframe(page, elementGroups, retryDelay, maxRetryCount, closePopups);
|
|
334
375
|
|
|
335
376
|
const screenshotScrollPosition = await page.evaluate(() => ({
|
|
336
377
|
x: window.scrollX,
|