@percy/core 1.29.0-beta.0 → 1.29.0-beta.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/dist/discovery.js +48 -22
- package/dist/network.js +16 -2
- package/dist/page.js +22 -3
- package/dist/timing.js +1 -1
- package/package.json +7 -7
package/dist/discovery.js
CHANGED
|
@@ -64,10 +64,11 @@ function debugSnapshotOptions(snapshot) {
|
|
|
64
64
|
function waitForDiscoveryNetworkIdle(page, options) {
|
|
65
65
|
let {
|
|
66
66
|
allowedHostnames,
|
|
67
|
-
networkIdleTimeout
|
|
67
|
+
networkIdleTimeout,
|
|
68
|
+
captureResponsiveAssetsEnabled
|
|
68
69
|
} = options;
|
|
69
70
|
let filter = r => hostnameMatches(allowedHostnames, r.url);
|
|
70
|
-
return page.network.idle(filter, networkIdleTimeout);
|
|
71
|
+
return page.network.idle(filter, networkIdleTimeout, captureResponsiveAssetsEnabled);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
// Creates an initial resource map for a snapshot containing serialized DOM
|
|
@@ -174,18 +175,55 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
174
175
|
mobile,
|
|
175
176
|
captureForDevices
|
|
176
177
|
} = options;
|
|
178
|
+
let cookies;
|
|
179
|
+
if (process.env.PERCY_DO_NOT_USE_CAPTURED_COOKIES !== 'true') {
|
|
180
|
+
var _snapshot$domSnapshot;
|
|
181
|
+
cookies = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot$domSnapshot = snapshot.domSnapshot) === null || _snapshot$domSnapshot === void 0 ? void 0 : _snapshot$domSnapshot.cookies;
|
|
182
|
+
}
|
|
183
|
+
if (typeof cookies === 'string' && cookies !== '') {
|
|
184
|
+
cookies = cookies.split('; ').map(c => c.split('='));
|
|
185
|
+
cookies = cookies.map(([key, value]) => {
|
|
186
|
+
return {
|
|
187
|
+
name: key,
|
|
188
|
+
value: value
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// iterate over device to trigger reqeusts and capture other dpr width
|
|
194
|
+
async function* captureResponsiveAssets() {
|
|
195
|
+
for (const device of captureForDevices) {
|
|
196
|
+
discovery = {
|
|
197
|
+
...discovery,
|
|
198
|
+
captureResponsiveAssetsEnabled: true
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// We are not adding these widths and pixels ratios in loop below because we want to explicitly reload the page after resize which we dont do below
|
|
202
|
+
yield* captureSnapshotResources(page, {
|
|
203
|
+
...snapshot,
|
|
204
|
+
discovery,
|
|
205
|
+
widths: [device.width]
|
|
206
|
+
}, {
|
|
207
|
+
deviceScaleFactor: device.deviceScaleFactor,
|
|
208
|
+
mobile: true
|
|
209
|
+
});
|
|
210
|
+
yield waitForDiscoveryNetworkIdle(page, discovery);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
177
213
|
|
|
178
214
|
// used to take snapshots and remove any discovered root resource
|
|
179
|
-
|
|
215
|
+
async function* takeSnapshot(options, width) {
|
|
180
216
|
if (captureWidths) options = {
|
|
181
217
|
...options,
|
|
182
218
|
width
|
|
183
219
|
};
|
|
184
220
|
let captured = await page.snapshot(options);
|
|
221
|
+
yield* captureResponsiveAssets();
|
|
185
222
|
captured.resources.delete(normalizeURL(captured.url));
|
|
186
223
|
capture(processSnapshotResources(captured));
|
|
187
224
|
return captured;
|
|
188
|
-
}
|
|
225
|
+
}
|
|
226
|
+
;
|
|
189
227
|
|
|
190
228
|
// used to resize the using capture options
|
|
191
229
|
let resizePage = width => page.resize({
|
|
@@ -197,7 +235,9 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
197
235
|
|
|
198
236
|
// navigate to the url
|
|
199
237
|
yield resizePage(snapshot.widths[0]);
|
|
200
|
-
yield page.goto(snapshot.url
|
|
238
|
+
yield page.goto(snapshot.url, {
|
|
239
|
+
cookies
|
|
240
|
+
});
|
|
201
241
|
if (snapshot.execute) {
|
|
202
242
|
// when any execute options are provided, inject snapshot options
|
|
203
243
|
/* istanbul ignore next: cannot detect coverage of injected code */
|
|
@@ -226,25 +266,10 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
226
266
|
} = snap;
|
|
227
267
|
let [width] = widths;
|
|
228
268
|
|
|
229
|
-
// iterate over device to trigger reqeusts and capture other dpr width
|
|
230
|
-
if (captureForDevices) {
|
|
231
|
-
for (const device of captureForDevices) {
|
|
232
|
-
yield waitForDiscoveryNetworkIdle(page, discovery);
|
|
233
|
-
// We are not adding these widths and pixels ratios in loop below because we want to explicitly reload the page after resize which we dont do below
|
|
234
|
-
yield* captureSnapshotResources(page, {
|
|
235
|
-
...snapshot,
|
|
236
|
-
widths: [device.width]
|
|
237
|
-
}, {
|
|
238
|
-
deviceScaleFactor: device.deviceScaleFactor,
|
|
239
|
-
mobile: true
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
269
|
// iterate over widths to trigger reqeusts and capture other widths
|
|
245
270
|
if (isBaseSnapshot || captureWidths) {
|
|
246
271
|
for (let i = 0; i < widths.length - 1; i++) {
|
|
247
|
-
if (captureWidths) yield takeSnapshot(snap, width);
|
|
272
|
+
if (captureWidths) yield* takeSnapshot(snap, width);
|
|
248
273
|
yield page.evaluate(execute === null || execute === void 0 ? void 0 : execute.beforeResize);
|
|
249
274
|
yield waitForDiscoveryNetworkIdle(page, discovery);
|
|
250
275
|
yield resizePage(width = widths[i + 1]);
|
|
@@ -253,7 +278,7 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
253
278
|
}
|
|
254
279
|
if (capture && !snapshot.domSnapshot) {
|
|
255
280
|
// capture this snapshot and update the base snapshot after capture
|
|
256
|
-
let captured = yield takeSnapshot(snap, width);
|
|
281
|
+
let captured = yield* takeSnapshot(snap, width);
|
|
257
282
|
if (isBaseSnapshot) baseSnapshot = captured;
|
|
258
283
|
|
|
259
284
|
// resize back to the initial width when capturing additional snapshot widths
|
|
@@ -272,6 +297,7 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
272
297
|
// wait for final network idle when not capturing DOM
|
|
273
298
|
if (capture && snapshot.domSnapshot) {
|
|
274
299
|
yield waitForDiscoveryNetworkIdle(page, discovery);
|
|
300
|
+
yield* captureResponsiveAssets();
|
|
275
301
|
capture(processSnapshotResources(snapshot));
|
|
276
302
|
}
|
|
277
303
|
}
|
package/dist/network.js
CHANGED
|
@@ -71,7 +71,7 @@ export class Network {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Resolves after the timeout when there are no more in-flight requests.
|
|
74
|
-
async idle(filter = () => true, timeout = this.timeout) {
|
|
74
|
+
async idle(filter = () => true, timeout = this.timeout, captureResponsiveAssetsEnabled = false) {
|
|
75
75
|
let requests = [];
|
|
76
76
|
this.log.debug(`Wait for ${timeout}ms idle`, this.meta);
|
|
77
77
|
await waitFor(() => {
|
|
@@ -91,11 +91,25 @@ export class Network {
|
|
|
91
91
|
idle: timeout
|
|
92
92
|
}).catch(error => {
|
|
93
93
|
if (error.message.startsWith('Timeout')) {
|
|
94
|
-
|
|
94
|
+
let message = 'Timed out waiting for network requests to idle.';
|
|
95
|
+
if (captureResponsiveAssetsEnabled) message += '\nWhile capturing responsive assets try setting PERCY_DO_NOT_CAPTURE_RESPONSIVE_ASSETS to true.';
|
|
96
|
+
this._throwTimeoutError(message, filter);
|
|
95
97
|
} else {
|
|
96
98
|
throw error;
|
|
97
99
|
}
|
|
98
100
|
});
|
|
101
|
+
|
|
102
|
+
// After waiting for network to idle check if there are still some request
|
|
103
|
+
const activeRequests = this.getActiveRequests(filter);
|
|
104
|
+
/* istanbul ignore if: race condition, very hard to mock this */
|
|
105
|
+
if (activeRequests.length > 0) {
|
|
106
|
+
this.log.debug(`There are ${activeRequests.length} active requests pending during asset discovery. Try increasing the networkIdleTimeout to resolve this issue. \n ${activeRequests}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
getActiveRequests(filter) {
|
|
110
|
+
let requests = Array.from(this.#requests.values()).filter(filter);
|
|
111
|
+
requests = requests.filter(req => !this.#finishedUrls.has(req.url));
|
|
112
|
+
return requests;
|
|
99
113
|
}
|
|
100
114
|
|
|
101
115
|
// Validates that requestId is still valid as sometimes request gets cancelled and we have already executed
|
package/dist/page.js
CHANGED
|
@@ -41,19 +41,38 @@ export class Page {
|
|
|
41
41
|
width
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
+
mergeCookies(userPassedCookie, autoCapturedCookie) {
|
|
45
|
+
if (!autoCapturedCookie) return userPassedCookie;
|
|
46
|
+
if (userPassedCookie.length === 0) return autoCapturedCookie;
|
|
47
|
+
|
|
48
|
+
// User passed cookie will be prioritized over auto captured cookie
|
|
49
|
+
const mergedCookies = [...userPassedCookie, ...autoCapturedCookie];
|
|
50
|
+
const uniqueCookies = [];
|
|
51
|
+
const names = new Set();
|
|
52
|
+
for (const cookie of mergedCookies) {
|
|
53
|
+
if (!names.has(cookie.name)) {
|
|
54
|
+
uniqueCookies.push(cookie);
|
|
55
|
+
names.add(cookie.name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return uniqueCookies;
|
|
59
|
+
}
|
|
44
60
|
|
|
45
61
|
// Go to a URL and wait for navigation to occur
|
|
46
62
|
async goto(url, {
|
|
47
|
-
waitUntil = 'load'
|
|
63
|
+
waitUntil = 'load',
|
|
64
|
+
cookies
|
|
48
65
|
} = {}) {
|
|
49
66
|
this.log.debug(`Navigate to: ${url}`, this.meta);
|
|
50
67
|
let navigate = async () => {
|
|
68
|
+
const userPassedCookie = this.session.browser.cookies;
|
|
51
69
|
// set cookies before navigation so we can default the domain to this hostname
|
|
52
|
-
if (
|
|
70
|
+
if (userPassedCookie.length || cookies) {
|
|
53
71
|
let defaultDomain = hostname(url);
|
|
72
|
+
cookies = this.mergeCookies(userPassedCookie, cookies);
|
|
54
73
|
await this.session.send('Network.setCookies', {
|
|
55
74
|
// spread is used to make a shallow copy of the cookie
|
|
56
|
-
cookies:
|
|
75
|
+
cookies: cookies.map(({
|
|
57
76
|
...cookie
|
|
58
77
|
}) => {
|
|
59
78
|
if (!cookie.url) cookie.domain || (cookie.domain = defaultDomain);
|
package/dist/timing.js
CHANGED
|
@@ -15,7 +15,7 @@ export default class TimeIt {
|
|
|
15
15
|
return await callback();
|
|
16
16
|
} finally {
|
|
17
17
|
const duration = Date.now() - startTime;
|
|
18
|
-
this.log.
|
|
18
|
+
this.log.debug(`${name} - ${identifier} - ${duration / 1000}s`);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/core",
|
|
3
|
-
"version": "1.29.0-beta.
|
|
3
|
+
"version": "1.29.0-beta.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"test:types": "tsd"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@percy/client": "1.29.0-beta.
|
|
47
|
-
"@percy/config": "1.29.0-beta.
|
|
48
|
-
"@percy/dom": "1.29.0-beta.
|
|
49
|
-
"@percy/logger": "1.29.0-beta.
|
|
50
|
-
"@percy/webdriver-utils": "1.29.0-beta.
|
|
46
|
+
"@percy/client": "1.29.0-beta.1",
|
|
47
|
+
"@percy/config": "1.29.0-beta.1",
|
|
48
|
+
"@percy/dom": "1.29.0-beta.1",
|
|
49
|
+
"@percy/logger": "1.29.0-beta.1",
|
|
50
|
+
"@percy/webdriver-utils": "1.29.0-beta.1",
|
|
51
51
|
"content-disposition": "^0.5.4",
|
|
52
52
|
"cross-spawn": "^7.0.3",
|
|
53
53
|
"extract-zip": "^2.0.1",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"ws": "^8.17.1",
|
|
61
61
|
"yaml": "^2.4.1"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "719cb9b3c5e50cfe23b2e27ebfa2410f30443cd8"
|
|
64
64
|
}
|