@applitools/eyes-storybook 3.53.7 → 3.53.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.53.9](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.53.8...js/eyes-storybook@3.53.9) (2025-02-23)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * page pool hang ([#2803](https://github.com/Applitools-Dev/sdk/issues/2803)) ([249043a](https://github.com/Applitools-Dev/sdk/commit/249043a4a31b358cbc3a06728d0fc493156d3c83))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * @applitools/ufg-client bumped to 1.16.5
14
+ #### Bug Fixes
15
+
16
+ * fix offline - url was replaced before resource fetched for url resources ([#2802](https://github.com/Applitools-Dev/sdk/issues/2802)) ([a67f86a](https://github.com/Applitools-Dev/sdk/commit/a67f86aabd56c59fb6cfa58578b1e8b3c31d2197))
17
+ * @applitools/core bumped to 4.31.3
18
+ #### Bug Fixes
19
+
20
+ * fix offline - url was replaced before resource fetched for url resources ([#2802](https://github.com/Applitools-Dev/sdk/issues/2802)) ([a67f86a](https://github.com/Applitools-Dev/sdk/commit/a67f86aabd56c59fb6cfa58578b1e8b3c31d2197))
21
+
22
+
23
+
24
+ * @applitools/eyes bumped to 1.32.2
25
+
26
+
27
+ ## [3.53.8](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.53.7...js/eyes-storybook@3.53.8) (2025-02-11)
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * add logs to page sanity check ([#2783](https://github.com/Applitools-Dev/sdk/issues/2783)) ([056c5bc](https://github.com/Applitools-Dev/sdk/commit/056c5bc0b91babd82a406e1ef57ca7ded8dcffdd))
33
+
3
34
  ## [3.53.7](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.53.6...js/eyes-storybook@3.53.7) (2025-02-10)
4
35
 
5
36
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-storybook",
3
- "version": "3.53.7",
3
+ "version": "3.53.9",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "applitools",
@@ -25,13 +25,13 @@
25
25
  "build": "rollup -c rollup.config.js",
26
26
  "build:heavy": "node scripts/bitmap.js",
27
27
  "test": "yarn build && yarn test:mocha",
28
- "test:mocha": "run --top-level mocha --trace-warnings 'test/{unit,it,e2e}/*.test.js'",
29
- "test:unit": "run --top-level mocha --trace-warnings 'test/unit/*.test.js'",
30
- "test:it": "run --top-level mocha --trace-warnings 'test/it/*.test.js'",
28
+ "test:mocha": "run --top-level mocha 'test/{unit,it,e2e}/*.test.js'",
29
+ "test:unit": "run --top-level mocha 'test/unit/*.test.js'",
30
+ "test:it": "run --top-level mocha 'test/it/*.test.js'",
31
31
  "test:versions": "yarn build && yarn test:e2e:versions && yarn lint",
32
- "test:e2e": "MOCHA_GROUP=e2e run --top-level mocha --trace-warnings 'test/e2e/*.e2e.test.js'",
33
- "test:e2e:versions": "MOCHA_GROUP=e2e_versions run --top-level mocha --trace-warnings test/versions/*.e2e.versions.test.js",
34
- "test:sanity": "run --top-level mocha --trace-warnings 'test/sanity/*.test.js'",
32
+ "test:e2e": "MOCHA_GROUP=e2e run --top-level mocha 'test/e2e/*.e2e.test.js'",
33
+ "test:e2e:versions": "MOCHA_GROUP=e2e_versions run --top-level mocha test/versions/*.e2e.versions.test.js",
34
+ "test:sanity": "run --top-level mocha 'test/sanity/*.test.js'",
35
35
  "test:heavy": "node bin/eyes-storybook.js -f test/fixtures/heavyStorybook/applitools.config.js",
36
36
  "storybook": "start-storybook -c test/fixtures/appWithStorybook -p 9001 -s test/fixtures",
37
37
  "storybook:httpHeaders": "start-storybook -c test/fixtures/appWithCustomHttpHeaders -p 9007",
@@ -53,14 +53,14 @@
53
53
  "up:framework": "cd test/fixtures/storybook-versions/${APPLITOOLS_FRAMEWORK_VERSION} && npm ci"
54
54
  },
55
55
  "dependencies": {
56
- "@applitools/core": "4.31.2",
56
+ "@applitools/core": "4.31.3",
57
57
  "@applitools/driver": "1.20.4",
58
- "@applitools/eyes": "1.32.1",
58
+ "@applitools/eyes": "1.32.2",
59
59
  "@applitools/functional-commons": "1.6.0",
60
60
  "@applitools/logger": "2.1.0",
61
61
  "@applitools/monitoring-commons": "1.0.19",
62
62
  "@applitools/spec-driver-puppeteer": "1.4.24",
63
- "@applitools/ufg-client": "1.16.4",
63
+ "@applitools/ufg-client": "1.16.5",
64
64
  "@applitools/utils": "1.7.7",
65
65
  "boxen": "4.2.0",
66
66
  "chalk": "3.0.0",
@@ -45,6 +45,7 @@ async function eyesStorybook({
45
45
  let iframeUrl;
46
46
  try {
47
47
  iframeUrl = getIframeUrl(storybookUrl);
48
+ logger.log('iframeUrl:', iframeUrl);
48
49
  } catch (ex) {
49
50
  logger.log(ex);
50
51
  throw new Error(`Storybook URL is not valid: ${storybookUrl}`);
@@ -118,13 +119,6 @@ async function eyesStorybook({
118
119
  try {
119
120
  const stories = await getStoriesWithSpinner();
120
121
 
121
- await Promise.all(
122
- Array.from({length: CONCURRENT_TABS}, async () => {
123
- const {pageId} = await pagePool.createPage();
124
- pagePool.addToPool(pageId);
125
- }),
126
- );
127
-
128
122
  const filteredStories = filterStories({stories, config});
129
123
  const storiesIncludingVariations = addVariationStories({
130
124
  stories: filteredStories,
@@ -173,6 +167,8 @@ async function eyesStorybook({
173
167
 
174
168
  logger.log('finished creating functions');
175
169
 
170
+ await initializeTabs();
171
+
176
172
  const [error, results] = await presult(
177
173
  executeRenders({
178
174
  renderStories,
@@ -307,22 +303,54 @@ async function eyesStorybook({
307
303
  }
308
304
  }
309
305
 
310
- async function sanityCheckForPage(page) {
311
- return executeWithRetry(_sanityCheckForPage, {
312
- timeout: readStoriesTimeout,
313
- delayBetweenRetries: 1000,
314
- initialErrMessage: `Could not get client API in sanity check since readStoriesTimeout is too short (${readStoriesTimeout}ms)`,
315
- });
306
+ async function sanityCheckForPage({page, pageId}) {
307
+ try {
308
+ await executeWithRetry(_sanityCheckForPage, {
309
+ timeout: readStoriesTimeout,
310
+ delayBetweenRetries: 1000,
311
+ initialErrMessage: `Could not get client API in sanity check since readStoriesTimeout is too short (${readStoriesTimeout}ms)`,
312
+ });
313
+ } catch (err) {
314
+ logger.log(`[page ${pageId}] Sanity check failed. Getting page HTML for inspection`);
315
+ try {
316
+ const html = await page.content();
317
+ logger.log(`[page ${pageId}] Page HTML: ${html}`);
318
+ } catch (htmlErr) {
319
+ logger.log(`[page ${pageId}] Error getting page HTML:`, htmlErr);
320
+ }
321
+ throw err;
322
+ }
316
323
 
317
324
  async function _sanityCheckForPage() {
318
325
  try {
319
326
  await page.evaluate(getClientAPI);
320
327
  } catch (err) {
321
- logger.log('Error in getClientAPI during sanity check:', err, ', retrying...');
328
+ logger.log(`[page ${pageId}] Error in getClientAPI during sanity check. Retrying...`, err);
322
329
  throw err;
323
330
  }
324
331
  }
325
332
  }
333
+
334
+ async function initializeTabs() {
335
+ logger.log('initializing tabs');
336
+ try {
337
+ await Promise.all(
338
+ Array.from({length: CONCURRENT_TABS}, async () => {
339
+ const {page, pageId} = await pagePool.createPage();
340
+ await sanityCheckForPage({page, pageId});
341
+ pagePool.addToPool(pageId);
342
+ }),
343
+ );
344
+ } catch (initializeTabsError) {
345
+ const msg = refineErrorMessage({
346
+ prefix: 'Error initializing browser tabs with storybook:',
347
+ error: initializeTabsError,
348
+ });
349
+ logger.log(msg);
350
+ ora({text: msg, stream: outputStream}).fail();
351
+ throw new Error();
352
+ }
353
+ }
326
354
  }
327
355
 
328
356
  module.exports = eyesStorybook;
package/src/pagePool.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- function createPagePool({initPage, logger}) {
3
+ function createPagePool({initPage, logger, freePageTimeout = 300_000}) {
4
4
  let counter = 0;
5
5
  const fullPageObjs = [];
6
6
  logger.log(`[page pool] created`);
@@ -48,22 +48,38 @@ function createPagePool({initPage, logger}) {
48
48
  pagePool.addToPool(newPageId);
49
49
  }
50
50
 
51
- async function getFreePage() {
52
- logger.log(`[page pool] waiting for free page`);
51
+ async function getFreePage(tryCount = 0) {
52
+ logger.log(`[page pool] waiting for free page, tryCount=${tryCount}`);
53
53
  await currWaitOnFreePage;
54
+ const availablePages = fullPageObjs.filter(p => p.isInPool());
55
+ // wait up to 5 minutes
56
+ if (availablePages.length === 0) {
57
+ const INTERVAL = 500;
58
+ if (tryCount < freePageTimeout / INTERVAL) {
59
+ logger.log(`[page pool] no available pages, retrying to get free page...`);
60
+ await new Promise(r => setTimeout(r, INTERVAL));
61
+ return getFreePage(tryCount + 1);
62
+ } else {
63
+ throw new Error('Could not find free page, timed out after waiting 5 minutes');
64
+ }
65
+ }
66
+ logger.log(`[page pool] waiting on pages ${availablePages.map(({pageId}) => pageId)}`);
54
67
  currWaitOnFreePage = Promise.race(
55
- fullPageObjs
56
- .filter(p => p.isInPool())
57
- .map(async p => {
58
- await p.waitUntilFree();
59
- return p;
60
- }),
68
+ availablePages.map(async p => {
69
+ await p.waitUntilFree();
70
+ return p;
71
+ }),
61
72
  );
62
73
 
63
74
  const fullPageObj = await currWaitOnFreePage;
64
- fullPageObj.occupyPage();
65
- logger.log(`[page pool] free page found: ${fullPageObj.pageId}`);
66
- return toSmallPageObj(fullPageObj);
75
+ if (fullPageObj.isInPool()) {
76
+ fullPageObj.occupyPage();
77
+ logger.log(`[page pool] free page found: ${fullPageObj.pageId}`);
78
+ return toSmallPageObj(fullPageObj);
79
+ } else {
80
+ logger.log(`[page pool] free page found, but it is no longer in pool: ${fullPageObj.pageId}`);
81
+ return getFreePage(tryCount + 1);
82
+ }
67
83
  }
68
84
 
69
85
  async function createPage() {
@@ -91,7 +107,9 @@ function createPagePool({initPage, logger}) {
91
107
  }
92
108
 
93
109
  async function waitUntilFree() {
110
+ logger.log(`[page ${pageId}] waitUntilFree before`);
94
111
  await workPromise;
112
+ logger.log(`[page ${pageId}] waitUntilFree after`);
95
113
  }
96
114
 
97
115
  function occupyPage() {
@@ -101,10 +119,13 @@ function createPagePool({initPage, logger}) {
101
119
  }
102
120
 
103
121
  function removePage() {
122
+ logger.log(`[page ${pageId}] removePage`);
104
123
  fullPageObjs.splice(
105
124
  fullPageObjs.findIndex(p => p.pageId === pageId),
106
125
  1,
107
126
  );
127
+ isActive = false;
128
+ resolveWork && resolveWork();
108
129
  }
109
130
 
110
131
  function isInPool() {
@@ -112,6 +133,7 @@ function createPagePool({initPage, logger}) {
112
133
  }
113
134
 
114
135
  function addToPool() {
136
+ logger.log(`[page ${pageId}] addToPool`);
115
137
  isActive = true;
116
138
  createdAt = Date.now();
117
139
  }
@@ -152,7 +152,7 @@ function makeRenderStories({
152
152
  const {pageId, page} = pageObj;
153
153
  logger.log(`[prepareNewPage] new page is ready: ${pageId}`);
154
154
  try {
155
- await sanityCheckForPage(page);
155
+ await sanityCheckForPage({page, pageId});
156
156
  logger.log(`[prepareNewPage] setting new page for replacement: ${pageId}`);
157
157
  newPageIdToAdd = pageId;
158
158
  } catch (errorInSanity) {