flexysnap 0.5.3 → 0.5.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/testUtils.js +55 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flexysnap",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Flexible visual snapshot testing for Playwright, built for e-commerce.",
5
5
  "keywords": [
6
6
  "playwright",
package/src/testUtils.js CHANGED
@@ -34,30 +34,65 @@ async function attemptNavigation(page, url, timeout) {
34
34
  }
35
35
  }
36
36
 
37
- async function prepareRetry(page, waitMs) {
38
- await page.goto('about:blank', { timeout: 5000 }).catch(() => {});
37
+ const CLOSE_STUCK_TARGET_TIMEOUT_MS = 5000;
38
+ const replacementContexts = [];
39
+
40
+ function closeWithinTimeout(closeable, timeoutMs) {
41
+ let timeoutHandle;
42
+ const timeoutPromise = new Promise(resolve => {
43
+ timeoutHandle = setTimeout(resolve, timeoutMs);
44
+ });
45
+ const closePromise = closeable.close().catch(() => {});
46
+ return Promise.race([closePromise, timeoutPromise]).finally(() => clearTimeout(timeoutHandle));
47
+ }
48
+
49
+ async function openReplacementPage(stuckPage, contextOptions) {
50
+ const stuckContext = stuckPage.context();
51
+ const browser = stuckContext.browser();
52
+
53
+ if (!browser) {
54
+ await closeWithinTimeout(stuckPage, CLOSE_STUCK_TARGET_TIMEOUT_MS);
55
+ return stuckContext.newPage();
56
+ }
57
+
58
+ const viewport = stuckPage.viewportSize();
59
+ await closeWithinTimeout(stuckContext, CLOSE_STUCK_TARGET_TIMEOUT_MS);
60
+
61
+ const replacementContext = await browser.newContext({ viewport, ...contextOptions });
62
+ replacementContexts.push(replacementContext);
63
+ await configureContext(replacementContext);
64
+
65
+ return replacementContext.newPage();
66
+ }
67
+
68
+ async function prepareRetry(stuckPage, waitMs, contextOptions) {
69
+ logTimestamp('Discarding stuck page and opening a new browser context');
70
+ const replacementPage = await openReplacementPage(stuckPage, contextOptions);
39
71
  logTimestamp(`Waiting ${waitMs}ms before retrying`);
40
- await page.waitForTimeout(waitMs);
72
+ await replacementPage.waitForTimeout(waitMs);
73
+ return replacementPage;
41
74
  }
42
75
 
43
76
  async function gotoWithRetry(page, url, options = {}) {
44
- const { baseTimeout = 20000, backoffMs = 3000 } = options;
77
+ const { baseTimeout = 20000, backoffMs = 3000, contextOptions = {} } = options;
45
78
  const maxAttempts = 3;
46
79
  let error = null;
80
+ let currentPage = page;
47
81
  for (let i = 1; i <= maxAttempts; ++i) {
48
82
  error = null;
49
83
  const timeout = baseTimeout * i;
50
84
  try {
51
- await attemptNavigation(page, url, timeout);
85
+ await attemptNavigation(currentPage, url, timeout);
52
86
  break
53
87
  } catch (e) {
54
88
  error = e
55
89
  if (i < maxAttempts)
56
- await prepareRetry(page, backoffMs * i);
90
+ currentPage = await prepareRetry(currentPage, backoffMs * i, contextOptions);
57
91
  }
58
92
  }
59
93
  if (error)
60
94
  throw error
95
+ return currentPage;
61
96
  }
62
97
 
63
98
 
@@ -82,9 +117,7 @@ function isTestedSiteUrl(url) {
82
117
  return baseUrl !== '' && url.href.includes(baseUrl);
83
118
  }
84
119
 
85
- test.beforeEach(async ({ context }) => {
86
- startTimer();
87
- logTimestamp('Test execution started');
120
+ async function configureContext(context) {
88
121
  context.on('requestfailed', request => {
89
122
  const errorText = request.failure()?.errorText;
90
123
  logTimestamp(`Request failed: ${request.method()} ${request.url()} - ${errorText}`);
@@ -112,6 +145,19 @@ test.beforeEach(async ({ context }) => {
112
145
  logTimestamp('Requesting ' + urlString);
113
146
  route.continue({ url: urlString });
114
147
  });
148
+ }
149
+
150
+ test.beforeEach(async ({ context }) => {
151
+ startTimer();
152
+ logTimestamp('Test execution started');
153
+ await configureContext(context);
154
+ });
155
+
156
+ test.afterEach(async () => {
157
+ const contextsToClose = replacementContexts.splice(0, replacementContexts.length);
158
+ for (const replacementContext of contextsToClose) {
159
+ await closeWithinTimeout(replacementContext, CLOSE_STUCK_TARGET_TIMEOUT_MS);
160
+ }
115
161
  });
116
162
 
117
163
  let testStartTime = null;