@applitools/eyes-storybook 3.54.0 → 3.55.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/CHANGELOG.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.55.1](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.55.0...js/eyes-storybook@3.55.1) (2025-04-13)
4
+
5
+
6
+ ### Performance Improvements
7
+
8
+ * cachify http agent ([#2466](https://github.com/Applitools-Dev/sdk/issues/2466)) ([bc2f4a1](https://github.com/Applitools-Dev/sdk/commit/bc2f4a1fae3c379f061c9199edf4c5257769fb44))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * @applitools/req bumped to 1.7.10
14
+ #### Bug Fixes
15
+
16
+ * req dummy ([23ddce8](https://github.com/Applitools-Dev/sdk/commit/23ddce8e3accd4b58838ec9cd722836c10310548))
17
+
18
+
19
+ #### Performance Improvements
20
+
21
+ * cachify http agent ([#2466](https://github.com/Applitools-Dev/sdk/issues/2466)) ([bc2f4a1](https://github.com/Applitools-Dev/sdk/commit/bc2f4a1fae3c379f061c9199edf4c5257769fb44))
22
+ * @applitools/core-base bumped to 1.24.0
23
+ #### Features
24
+
25
+ * add EYES_NETWORK_RETRY_LIMIT and EYES_NETWORK_RETRY_TIMEOUT environment variables ([#2911](https://github.com/Applitools-Dev/sdk/issues/2911)) ([7a1cca7](https://github.com/Applitools-Dev/sdk/commit/7a1cca73e7b6e5a377aea2d46171fdaab024c3c4))
26
+
27
+
28
+ #### Bug Fixes
29
+
30
+ * core base dummy ([d445665](https://github.com/Applitools-Dev/sdk/commit/d445665e1c32e62022646c4bbdb5190fef8f4bfe))
31
+
32
+
33
+ #### Performance Improvements
34
+
35
+ * cachify http agent ([#2466](https://github.com/Applitools-Dev/sdk/issues/2466)) ([bc2f4a1](https://github.com/Applitools-Dev/sdk/commit/bc2f4a1fae3c379f061c9199edf4c5257769fb44))
36
+
37
+
38
+
39
+ * @applitools/core bumped to 4.36.0
40
+ #### Features
41
+
42
+ * add EYES_NETWORK_RETRY_LIMIT and EYES_NETWORK_RETRY_TIMEOUT environment variables ([#2911](https://github.com/Applitools-Dev/sdk/issues/2911)) ([7a1cca7](https://github.com/Applitools-Dev/sdk/commit/7a1cca73e7b6e5a377aea2d46171fdaab024c3c4))
43
+
44
+
45
+ #### Bug Fixes
46
+
47
+ * basic auth protected resources | FLD-2761 | FMRI-120 ([#2444](https://github.com/Applitools-Dev/sdk/issues/2444)) ([b48cf49](https://github.com/Applitools-Dev/sdk/commit/b48cf49dec50bbf1ed2ba111608a48cf09962565))
48
+ * simplify sandbox creation and ensure cleanup after execution ([#2869](https://github.com/Applitools-Dev/sdk/issues/2869)) ([72c5e01](https://github.com/Applitools-Dev/sdk/commit/72c5e01307f6abd83fab365a7e235124caae0694))
49
+ * yarn4 pnp problem ([#2871](https://github.com/Applitools-Dev/sdk/issues/2871)) ([29b6935](https://github.com/Applitools-Dev/sdk/commit/29b69358b7ce734c495b3d2e159331c12b36a117))
50
+
51
+
52
+ #### Performance Improvements
53
+
54
+ * cachify http agent ([#2466](https://github.com/Applitools-Dev/sdk/issues/2466)) ([bc2f4a1](https://github.com/Applitools-Dev/sdk/commit/bc2f4a1fae3c379f061c9199edf4c5257769fb44))
55
+
56
+
57
+
58
+
59
+ ## [3.55.0](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.54.0...js/eyes-storybook@3.55.0) (2025-04-03)
60
+
61
+
62
+ ### Features
63
+
64
+ * browser headers override and requests caching ([#2885](https://github.com/Applitools-Dev/sdk/issues/2885)) ([7a83578](https://github.com/Applitools-Dev/sdk/commit/7a8357835dc41ab16ba3b392885b732045fe8022))
65
+
66
+
67
+ ### Dependencies
68
+
69
+ * @applitools/core bumped to 4.35.1
70
+ #### Bug Fixes
71
+
72
+ * dummy ([9b8ffef](https://github.com/Applitools-Dev/sdk/commit/9b8ffef6277015a9073caf50f5dc5741986fbf07))
73
+ * @applitools/eyes bumped to 1.33.2
74
+
75
+
3
76
  ## [3.54.0](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.53.14...js/eyes-storybook@3.54.0) (2025-03-30)
4
77
 
5
78
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-storybook",
3
- "version": "3.54.0",
3
+ "version": "3.55.1",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "applitools",
@@ -53,9 +53,9 @@
53
53
  "up:framework": "cd test/fixtures/storybook-versions/${APPLITOOLS_FRAMEWORK_VERSION} && npm ci"
54
54
  },
55
55
  "dependencies": {
56
- "@applitools/core": "4.34.0",
56
+ "@applitools/core": "4.36.0",
57
57
  "@applitools/driver": "1.21.0",
58
- "@applitools/eyes": "1.33.0",
58
+ "@applitools/eyes": "1.33.2",
59
59
  "@applitools/functional-commons": "1.6.0",
60
60
  "@applitools/logger": "2.1.2",
61
61
  "@applitools/monitoring-commons": "1.0.19",
@@ -21,4 +21,6 @@ module.exports = {
21
21
  navigationWaitUntil: undefined,
22
22
  networkBlockPatterns: undefined,
23
23
  browserRequestsTimeout: undefined,
24
+ browserHeadersOverride: undefined,
25
+ browserCacheRequests: undefined,
24
26
  };
@@ -69,6 +69,8 @@ async function eyesStorybook({
69
69
  await startInterception({
70
70
  timeout: config.browserRequestsTimeout,
71
71
  blockPatterns: config.networkBlockPatterns,
72
+ browserHeadersOverride: config.browserHeadersOverride,
73
+ cache: config.browserCacheRequests,
72
74
  });
73
75
 
74
76
  const environment = extractEnvironment();
package/src/initPage.js CHANGED
@@ -14,6 +14,8 @@ function makeInitPage({iframeUrl, config, browser, logger, getTransitiongIntoIE,
14
14
  await startInterception({
15
15
  timeout: config.browserRequestsTimeout,
16
16
  blockPatterns: config.networkBlockPatterns,
17
+ browserHeadersOverride: config.browserHeadersOverride,
18
+ cache: config.browserCacheRequests,
17
19
  });
18
20
 
19
21
  if (config.viewportSize) {
@@ -1,5 +1,8 @@
1
1
  /* eslint-disable no-restricted-globals */
2
2
  const {setTimeout} = require('timers/promises');
3
+ const utils = require('@applitools/utils');
4
+
5
+ const cachedFetch = utils.general.cachify(fetchRequest);
3
6
 
4
7
  function makeBrowserNetworkPolicy({page, logger, pageId = null}) {
5
8
  const scope = pageId ? `[page ${pageId}]` : '[master page]';
@@ -7,52 +10,64 @@ function makeBrowserNetworkPolicy({page, logger, pageId = null}) {
7
10
  extend(options) {
8
11
  return makeBrowserNetworkPolicy({page, logger, pageId, ...options});
9
12
  },
10
- async startInterception({timeout, blockPatterns}) {
11
- if (timeout || blockPatterns) {
13
+ async startInterception({timeout, blockPatterns, browserHeadersOverride, cache}) {
14
+ const fetch = cache ? cachedFetch : fetchRequest;
15
+ if (timeout || blockPatterns || browserHeadersOverride || cache) {
12
16
  const cdp = await page.target().createCDPSession();
13
17
 
14
18
  await cdp.send('Fetch.enable');
15
- await cdp.on('Fetch.requestPaused', async ({requestId, request}) => {
19
+ await cdp.on('Fetch.requestPaused', async ({requestId, request, ...others}) => {
16
20
  logger.log(`${scope} Request to ${request.url}`);
17
- if (blockPatterns && blockPatterns.some(pattern => request.url.includes(pattern))) {
18
- logger.log(`${scope} Blocking request to ${request.url}`);
19
- await cdp.send('Fetch.failRequest', {requestId, errorReason: 'Blocked'});
20
- return;
21
- }
22
- if (timeout) {
23
- await Promise.race([
24
- setTimeout(timeout, {action: 'abort'}),
25
- fetchRequest(request)
26
- .then(response => ({action: 'fulfill', response}))
27
- .catch(() => ({action: 'fail'})),
28
- ]).then(async ({action, response}) => {
29
- if (action === 'abort') {
30
- logger.log(`${scope} Timeout for request to ${request.url}`);
31
- await cdp.send('Fetch.failRequest', {requestId, errorReason: 'Aborted'});
32
- } else if (action === 'fulfill') {
33
- logger.log(`${scope} Fulfilled request to ${request.url}`);
34
- const bodyBytes = await response.arrayBuffer();
35
- const body = Buffer.from(bodyBytes).toString('base64');
36
- const cdpResponse = {
37
- requestId,
38
- responseCode: response.status,
39
- responseHeaders: [...response.headers.entries()].map(([name, value]) => ({
40
- name,
41
- value,
42
- })),
43
- body,
44
- };
45
- await cdp.send('Fetch.fulfillRequest', cdpResponse);
46
- } else {
47
- logger.log(`${scope} Failed request to ${request.url}`);
48
- await cdp.send('Fetch.failRequest', {requestId, errorReason: 'Failed'});
21
+ try {
22
+ if (blockPatterns && blockPatterns.some(pattern => request.url.includes(pattern))) {
23
+ logger.log(`${scope} Blocking request to ${request.url}`);
24
+ logger.log(others);
25
+ try {
26
+ await cdp.send('Fetch.failRequest', {requestId, errorReason: 'BlockedByClient'});
27
+ } catch (err) {
28
+ logger.log(`${scope} Failed to block request to ${request.url}. Error: ${err}`);
49
29
  }
50
- });
51
- } else {
52
- logger.log(`${scope} Not intercepting request to ${request.url}`);
53
- await cdp.send('Fetch.continueRequest', {
54
- requestId,
55
- });
30
+ return;
31
+ }
32
+ if (browserHeadersOverride) {
33
+ logger.log(`${scope} Overriding headers for request to ${request.url}`);
34
+ request.headers = applyHeaderOverrides(request.headers, browserHeadersOverride);
35
+ }
36
+ if (timeout) {
37
+ return await Promise.race([
38
+ setTimeout(timeout, {action: 'abort'}),
39
+ fetch(request)
40
+ .then(response => ({action: 'fulfill', response}))
41
+ .catch(() => ({action: 'fail'})),
42
+ ]).then(async ({action, response}) => {
43
+ if (action === 'abort') {
44
+ logger.log(`${scope} Timeout for request to ${request.url}`);
45
+ await cdp.send('Fetch.failRequest', {requestId, errorReason: 'Aborted'});
46
+ } else if (action === 'fulfill') {
47
+ logger.log(`${scope} Fulfilled request to ${request.url}`);
48
+ await cdp.send('Fetch.fulfillRequest', {...response, requestId});
49
+ } else {
50
+ logger.log(`${scope} Failed request to ${request.url}`);
51
+ await cdp.send('Fetch.failRequest', {requestId, errorReason: 'Failed'});
52
+ }
53
+ return;
54
+ });
55
+ }
56
+ if (browserHeadersOverride || cache) {
57
+ logger.log(`${scope} Fetching request to ${request.url}`);
58
+ const response = await fetch(request);
59
+ logger.log(`${scope} Fulfilled request to ${request.url}`);
60
+ await cdp.send('Fetch.fulfillRequest', {...response, requestId});
61
+ return;
62
+ } else {
63
+ logger.log(`${scope} Not intercepting request to ${request.url}`);
64
+ await cdp.send('Fetch.continueRequest', {
65
+ requestId,
66
+ });
67
+ }
68
+ } catch (err) {
69
+ // I beliebe it doens't necessarily indicate an error - if we get here, the request was cancled (e.g. by navigating away). Logging it for now.
70
+ logger.log(`${scope} Failed to intercept request to ${request.url}. Error: ${err}`);
56
71
  }
57
72
  });
58
73
  }
@@ -60,14 +75,37 @@ function makeBrowserNetworkPolicy({page, logger, pageId = null}) {
60
75
  };
61
76
  }
62
77
 
63
- function fetchRequest(request) {
64
- return fetch(request.url, {
78
+ async function fetchRequest(request) {
79
+ const response = await fetch(request.url, {
65
80
  method: request.method,
66
81
  headers: request.headers,
67
82
  body: request.postData,
68
83
  });
84
+ return {
85
+ responseCode: response.status,
86
+ responseHeaders: [...response.headers.entries()].map(([name, value]) => ({
87
+ name,
88
+ value,
89
+ })),
90
+ body: Buffer.from(await response.arrayBuffer()).toString('base64'),
91
+ };
92
+ }
93
+
94
+ function applyHeaderOverrides(headers, overrides) {
95
+ const result = {...headers};
96
+ for (const [name, value] of Object.entries(overrides)) {
97
+ if (typeof value === 'function') {
98
+ result[name] = value(result[name], headers);
99
+ } else if (value === null || value === undefined) {
100
+ result[name] = null;
101
+ } else {
102
+ result[name] = value;
103
+ }
104
+ }
105
+ return result;
69
106
  }
70
107
 
71
108
  module.exports = {
72
109
  makeNetworkUtils: makeBrowserNetworkPolicy,
110
+ clearNetworkCache: cachedFetch.clearCache, // for testing purposes
73
111
  };
@@ -69,6 +69,13 @@ module.exports = {
69
69
  array: true,
70
70
  },
71
71
 
72
+ browserCacheRequests: {
73
+ alias: ['browser-cache-requests'],
74
+ description: 'Intercept and cache requests coming from the browser',
75
+ requiresArg: false,
76
+ boolean: true,
77
+ },
78
+
72
79
  navigationWaitUntil: {
73
80
  alias: ['navigation-wait-until'],
74
81
  description: 'When to consider navigation to be finished',