flexysnap 0.1.4-alpha.1 → 0.1.5-alpha.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flexysnap",
3
- "version": "0.1.4-alpha.1",
3
+ "version": "0.1.5-alpha.1",
4
4
  "description": "Flexible visual snapshot testing for Playwright, built for e-commerce.",
5
5
  "keywords": [
6
6
  "playwright",
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export {
2
2
  waitForCompleteLoad,
3
+ gotoWithRetry,
3
4
  highlightedClick,
4
5
  click,
5
6
  hover,
@@ -23,7 +24,7 @@ export {
23
24
 
24
25
  export { areWireframesStable } from './wireframeStability.js';
25
26
 
26
- export { expectWireframe, getRGBHistogramFromBuffer } from './wireframeUtils.js';
27
+ export { expectWireframe, getRGBHistogramFromBuffer, getDeviceScaleFactor } from './wireframeUtils.js';
27
28
 
28
29
  export {
29
30
  setWireframeOutputRoot,
package/src/testUtils.js CHANGED
@@ -2,6 +2,18 @@ import { test } from '@playwright/test';
2
2
 
3
3
  let closePopups = async function(page) {}
4
4
 
5
+ async function gotoWithRetry(page, url) {
6
+ try {
7
+ logTimestamp('Loading ' + url);
8
+ await page.goto(url, { timeout: 30_000, waitUntil: "domcontentloaded" });
9
+ } catch (firstError) {
10
+ logTimestamp('Retry loading ' + url);
11
+ await page.goto(url, { timeout: 30_000, waitUntil: "domcontentloaded" });
12
+ }
13
+ await waitForCompleteLoad(page)
14
+ }
15
+
16
+
5
17
  function setClosePopups(f) {
6
18
  closePopups = f;
7
19
  }
@@ -188,6 +200,7 @@ async function selectOption(page, field, value) {
188
200
 
189
201
  export {
190
202
  waitForCompleteLoad,
203
+ gotoWithRetry,
191
204
  highlightedClick,
192
205
  click,
193
206
  hover,
@@ -39,6 +39,58 @@ function delay(milliseconds) {
39
39
  return new Promise(resolve => setTimeout(resolve, milliseconds));
40
40
  }
41
41
 
42
+ async function getDeviceScaleFactor(page) {
43
+ const rawScaleFactor = await page.evaluate(() => window.devicePixelRatio);
44
+
45
+ if (typeof rawScaleFactor !== 'number' || !Number.isFinite(rawScaleFactor) || rawScaleFactor <= 0) {
46
+ return 1;
47
+ }
48
+
49
+ return rawScaleFactor;
50
+ }
51
+
52
+ function scaleBoundingRect(boundingRect, scaleFactor) {
53
+ if (!boundingRect) {
54
+ return boundingRect;
55
+ }
56
+
57
+ return {
58
+ top: Math.round(boundingRect.top * scaleFactor),
59
+ left: Math.round(boundingRect.left * scaleFactor),
60
+ bottom: Math.round(boundingRect.bottom * scaleFactor),
61
+ right: Math.round(boundingRect.right * scaleFactor)
62
+ };
63
+ }
64
+
65
+ function scalePoint(point, scaleFactor) {
66
+ if (!point) {
67
+ return point;
68
+ }
69
+
70
+ return {
71
+ x: Math.round(point.x * scaleFactor),
72
+ y: Math.round(point.y * scaleFactor)
73
+ };
74
+ }
75
+
76
+ function scaleWireframeData(wireframeData, scaleFactor) {
77
+ if (scaleFactor === 1) {
78
+ return wireframeData;
79
+ }
80
+
81
+ for (const elementGroup of wireframeData) {
82
+ for (const element of elementGroup.elements || []) {
83
+ element.boundingRect = scaleBoundingRect(element.boundingRect, scaleFactor);
84
+
85
+ for (const textEntry of element.texts || []) {
86
+ textEntry.boundingRect = scaleBoundingRect(textEntry.boundingRect, scaleFactor);
87
+ }
88
+ }
89
+ }
90
+
91
+ return wireframeData;
92
+ }
93
+
42
94
  async function extractWireframe(page, elementGroups) {
43
95
  const wireframeData = await page.evaluate(async ({elementGroups, elementIdAttribute}) => {
44
96
 
@@ -272,7 +324,7 @@ async function extractStableWireframe(page, elementGroups, retryDelay, maxRetryC
272
324
  }
273
325
 
274
326
  async function expectWireframe(page, elementGroups, outputDir, outputFile, outputName, options = {}) {
275
- const { retryDelay = 1000, maxRetryCount = 10, metadata = {} } = options;
327
+ const { retryDelay = 1000, maxRetryCount = 10, metadata = {}, deviceScaleFactor } = options;
276
328
 
277
329
  logTimestamp(`Starting wireframe capture for: ${outputFile}`);
278
330
  const { wireframeData, scrollPosition } = await extractStableWireframe(page, elementGroups, retryDelay, maxRetryCount);
@@ -282,12 +334,23 @@ async function expectWireframe(page, elementGroups, outputDir, outputFile, outpu
282
334
  y: window.scrollY
283
335
  }));
284
336
 
337
+ const resolvedDeviceScaleFactor = deviceScaleFactor !== undefined
338
+ ? deviceScaleFactor
339
+ : await getDeviceScaleFactor(page);
340
+
341
+ logTimestamp(`Applying device scale factor: ${resolvedDeviceScaleFactor}`);
342
+
343
+ const scaledWireframeData = scaleWireframeData(wireframeData, resolvedDeviceScaleFactor);
344
+ const scaledScrollPosition = scalePoint(scrollPosition, resolvedDeviceScaleFactor);
345
+ const scaledScreenshotScrollPosition = scalePoint(screenshotScrollPosition, resolvedDeviceScaleFactor);
346
+
285
347
  const wireframeOutput = {
286
348
  name: outputName,
287
349
  timestamp: new Date().toISOString(),
288
- scrollPosition,
289
- screenshotScrollPosition,
290
- elementGroups: wireframeData,
350
+ scrollPosition: scaledScrollPosition,
351
+ screenshotScrollPosition: scaledScreenshotScrollPosition,
352
+ elementGroups: scaledWireframeData,
353
+ deviceScaleFactor: resolvedDeviceScaleFactor,
291
354
  ...metadata
292
355
  };
293
356
 
@@ -306,4 +369,4 @@ async function expectWireframe(page, elementGroups, outputDir, outputFile, outpu
306
369
  return {wireframeOutput, screenshotPath, outputDir: resolvedDir};
307
370
  }
308
371
 
309
- export { expectWireframe, getRGBHistogramFromBuffer };
372
+ export { expectWireframe, getRGBHistogramFromBuffer, getDeviceScaleFactor };