@applitools/eyes-storybook 3.53.14 → 3.55.0
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 +24 -0
- package/package.json +3 -3
- package/src/defaultConfig.js +3 -0
- package/src/eyesStorybook.js +14 -12
- package/src/initPage.js +10 -12
- package/src/utils/pageNetworkUtils.js +111 -0
- package/src/yargsOptions.js +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [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)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* browser headers override and requests caching ([#2885](https://github.com/Applitools-Dev/sdk/issues/2885)) ([7a83578](https://github.com/Applitools-Dev/sdk/commit/7a8357835dc41ab16ba3b392885b732045fe8022))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* @applitools/core bumped to 4.35.1
|
|
14
|
+
#### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* dummy ([9b8ffef](https://github.com/Applitools-Dev/sdk/commit/9b8ffef6277015a9073caf50f5dc5741986fbf07))
|
|
17
|
+
* @applitools/eyes bumped to 1.33.2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## [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)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* implement browser-side timeout for eyes storybook ([#2877](https://github.com/Applitools-Dev/sdk/issues/2877)) ([591d950](https://github.com/Applitools-Dev/sdk/commit/591d950154368cc64f93835586da1eef296e2d33))
|
|
26
|
+
|
|
3
27
|
## [3.53.14](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.53.13...js/eyes-storybook@3.53.14) (2025-03-30)
|
|
4
28
|
|
|
5
29
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/eyes-storybook",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.55.0",
|
|
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.
|
|
56
|
+
"@applitools/core": "4.35.1",
|
|
57
57
|
"@applitools/driver": "1.21.0",
|
|
58
|
-
"@applitools/eyes": "1.33.
|
|
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",
|
package/src/defaultConfig.js
CHANGED
package/src/eyesStorybook.js
CHANGED
|
@@ -23,6 +23,7 @@ const executeRenders = require('./executeRenders');
|
|
|
23
23
|
const {extractEnvironment} = require('./extractEnvironment');
|
|
24
24
|
const {makeCore} = require('@applitools/core');
|
|
25
25
|
const makeGetStoriesWithConfig = require('./getStoriesWithConfig');
|
|
26
|
+
const {makeNetworkUtils} = require('./utils/pageNetworkUtils');
|
|
26
27
|
|
|
27
28
|
async function eyesStorybook({
|
|
28
29
|
config,
|
|
@@ -55,22 +56,23 @@ async function eyesStorybook({
|
|
|
55
56
|
const browser = await puppeteer.launch(config.puppeteerOptions);
|
|
56
57
|
logger.log('browser launched');
|
|
57
58
|
const page = await browser.newPage();
|
|
59
|
+
|
|
60
|
+
const {startInterception} = makeNetworkUtils({
|
|
61
|
+
page,
|
|
62
|
+
logger,
|
|
63
|
+
});
|
|
58
64
|
// we send http headers here and in init page
|
|
59
65
|
if (config.puppeteerExtraHTTPHeaders) {
|
|
60
66
|
await page.setExtraHTTPHeaders(config.puppeteerExtraHTTPHeaders);
|
|
61
67
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
request.continue();
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
68
|
+
|
|
69
|
+
await startInterception({
|
|
70
|
+
timeout: config.browserRequestsTimeout,
|
|
71
|
+
blockPatterns: config.networkBlockPatterns,
|
|
72
|
+
browserHeadersOverride: config.browserHeadersOverride,
|
|
73
|
+
cache: config.browserCacheRequests,
|
|
74
|
+
});
|
|
75
|
+
|
|
74
76
|
const environment = extractEnvironment();
|
|
75
77
|
const core = await makeCore({spec, agentId, environment, logger});
|
|
76
78
|
const manager = await core.makeManager({
|
package/src/initPage.js
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
const {presult} = require('@applitools/functional-commons');
|
|
2
2
|
const browserLog = require('./browserLog');
|
|
3
3
|
const fakeIE = require('./fakeIE');
|
|
4
|
+
const {makeNetworkUtils} = require('./utils/pageNetworkUtils');
|
|
4
5
|
|
|
5
6
|
function makeInitPage({iframeUrl, config, browser, logger, getTransitiongIntoIE, getRenderIE}) {
|
|
7
|
+
const networkUtils = makeNetworkUtils({logger});
|
|
6
8
|
return async function initPage({pageId, pagePool}) {
|
|
7
9
|
logger.log('initializing puppeteer page number ', pageId);
|
|
8
10
|
const browserContext = await browser.createBrowserContext();
|
|
9
11
|
const page = await browserContext.newPage();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
request.continue();
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
12
|
+
const {startInterception} = networkUtils.extend({page, pageId});
|
|
13
|
+
|
|
14
|
+
await startInterception({
|
|
15
|
+
timeout: config.browserRequestsTimeout,
|
|
16
|
+
blockPatterns: config.networkBlockPatterns,
|
|
17
|
+
browserHeadersOverride: config.browserHeadersOverride,
|
|
18
|
+
cache: config.browserCacheRequests,
|
|
19
|
+
});
|
|
22
20
|
|
|
23
21
|
if (config.viewportSize) {
|
|
24
22
|
await page.setViewport(config.viewportSize);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-globals */
|
|
2
|
+
const {setTimeout} = require('timers/promises');
|
|
3
|
+
const utils = require('@applitools/utils');
|
|
4
|
+
|
|
5
|
+
const cachedFetch = utils.general.cachify(fetchRequest);
|
|
6
|
+
|
|
7
|
+
function makeBrowserNetworkPolicy({page, logger, pageId = null}) {
|
|
8
|
+
const scope = pageId ? `[page ${pageId}]` : '[master page]';
|
|
9
|
+
return {
|
|
10
|
+
extend(options) {
|
|
11
|
+
return makeBrowserNetworkPolicy({page, logger, pageId, ...options});
|
|
12
|
+
},
|
|
13
|
+
async startInterception({timeout, blockPatterns, browserHeadersOverride, cache}) {
|
|
14
|
+
const fetch = cache ? cachedFetch : fetchRequest;
|
|
15
|
+
if (timeout || blockPatterns || browserHeadersOverride || cache) {
|
|
16
|
+
const cdp = await page.target().createCDPSession();
|
|
17
|
+
|
|
18
|
+
await cdp.send('Fetch.enable');
|
|
19
|
+
await cdp.on('Fetch.requestPaused', async ({requestId, request, ...others}) => {
|
|
20
|
+
logger.log(`${scope} Request to ${request.url}`);
|
|
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}`);
|
|
29
|
+
}
|
|
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}`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function fetchRequest(request) {
|
|
79
|
+
const response = await fetch(request.url, {
|
|
80
|
+
method: request.method,
|
|
81
|
+
headers: request.headers,
|
|
82
|
+
body: request.postData,
|
|
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;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = {
|
|
109
|
+
makeNetworkUtils: makeBrowserNetworkPolicy,
|
|
110
|
+
clearNetworkCache: cachedFetch.clearCache, // for testing purposes
|
|
111
|
+
};
|
package/src/yargsOptions.js
CHANGED
|
@@ -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',
|