@percy/core 1.26.3-beta.1 → 1.26.3-beta.2
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/network.js +55 -8
- package/dist/snapshot.js +1 -1
- package/package.json +6 -6
package/dist/network.js
CHANGED
|
@@ -5,6 +5,7 @@ import { normalizeURL, hostnameMatches, createResource, waitFor } from './utils.
|
|
|
5
5
|
const MAX_RESOURCE_SIZE = 25 * 1024 ** 2; // 25MB
|
|
6
6
|
const ALLOWED_STATUSES = [200, 201, 301, 302, 304, 307, 308];
|
|
7
7
|
const ALLOWED_RESOURCES = ['Document', 'Stylesheet', 'Image', 'Media', 'Font', 'Other'];
|
|
8
|
+
const ABORTED_MESSAGE = 'Request was aborted by browser';
|
|
8
9
|
|
|
9
10
|
// The Interceptor class creates common handlers for dealing with intercepting asset requests
|
|
10
11
|
// for a given page using various devtools protocol events and commands.
|
|
@@ -15,6 +16,7 @@ export class Network {
|
|
|
15
16
|
#requests = new Map();
|
|
16
17
|
#intercepts = new Map();
|
|
17
18
|
#authentications = new Set();
|
|
19
|
+
#aborted = new Set();
|
|
18
20
|
constructor(page, options) {
|
|
19
21
|
this.page = page;
|
|
20
22
|
this.timeout = options.networkIdleTimeout ?? 100;
|
|
@@ -77,6 +79,23 @@ export class Network {
|
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
// Validates that requestId is still valid as sometimes request gets cancelled and we have already executed
|
|
83
|
+
// _forgetRequest for the same, but we still attempt to make a call for it and it fails
|
|
84
|
+
// with Protocol error (Fetch.failRequest): Invalid InterceptionId.
|
|
85
|
+
async send(session, method, params) {
|
|
86
|
+
/* istanbul ignore else: currently all send have requestId */
|
|
87
|
+
if (params.requestId) {
|
|
88
|
+
/* istanbul ignore if: race condition, very hard to mock this */
|
|
89
|
+
if (this.isAborted(params.requestId)) {
|
|
90
|
+
throw new Error(ABORTED_MESSAGE);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return await session.send(method, params);
|
|
94
|
+
}
|
|
95
|
+
isAborted(requestId) {
|
|
96
|
+
return this.#aborted.has(requestId);
|
|
97
|
+
}
|
|
98
|
+
|
|
80
99
|
// Throw a better network timeout error
|
|
81
100
|
_throwTimeoutError(msg, filter = () => true) {
|
|
82
101
|
if (this.log.shouldLog('debug')) {
|
|
@@ -116,7 +135,7 @@ export class Network {
|
|
|
116
135
|
response = 'ProvideCredentials';
|
|
117
136
|
this.#authentications.add(requestId);
|
|
118
137
|
}
|
|
119
|
-
await
|
|
138
|
+
await this.send(session, 'Fetch.continueWithAuth', {
|
|
120
139
|
requestId: event.requestId,
|
|
121
140
|
authChallengeResponse: {
|
|
122
141
|
response,
|
|
@@ -222,7 +241,7 @@ export class Network {
|
|
|
222
241
|
if (!request) return;
|
|
223
242
|
request.response = response;
|
|
224
243
|
request.response.buffer = async () => {
|
|
225
|
-
let result = await
|
|
244
|
+
let result = await this.send(session, 'Network.getResponseBody', {
|
|
226
245
|
requestId
|
|
227
246
|
});
|
|
228
247
|
return Buffer.from(result.body, result.base64Encoded ? 'base64' : 'utf-8');
|
|
@@ -253,8 +272,18 @@ export class Network {
|
|
|
253
272
|
/* istanbul ignore if: race condition paranioa */
|
|
254
273
|
if (!request) return;
|
|
255
274
|
|
|
256
|
-
//
|
|
257
|
-
|
|
275
|
+
// If request was aborted, keep track of it as we need to cancel any in process callbacks for
|
|
276
|
+
// such a request to avoid Invalid InterceptionId errors
|
|
277
|
+
// Note: 404s also show up under ERR_ABORTED and not ERR_FAILED
|
|
278
|
+
if (event.errorText === 'net::ERR_ABORTED') {
|
|
279
|
+
let message = `Request aborted for ${request.url}: ${event.errorText}`;
|
|
280
|
+
this.log.debug(message, {
|
|
281
|
+
...this.meta,
|
|
282
|
+
url: request.url
|
|
283
|
+
});
|
|
284
|
+
this.#aborted.add(request.requestId);
|
|
285
|
+
} else if (event.errorText !== 'net::ERR_FAILED') {
|
|
286
|
+
// do not log generic messages since the real error was likely logged elsewhere
|
|
258
287
|
let message = `Request failed for ${request.url}: ${event.errorText}`;
|
|
259
288
|
this.log.debug(message, {
|
|
260
289
|
...this.meta,
|
|
@@ -289,18 +318,19 @@ async function sendResponseResource(network, request, session) {
|
|
|
289
318
|
...network.meta,
|
|
290
319
|
url
|
|
291
320
|
};
|
|
321
|
+
let send = (method, params) => network.send(session, method, params);
|
|
292
322
|
try {
|
|
293
323
|
let resource = network.intercept.getResource(url);
|
|
294
324
|
network.log.debug(`Handling request: ${url}`, meta);
|
|
295
325
|
if (!(resource !== null && resource !== void 0 && resource.root) && hostnameMatches(disallowedHostnames, url)) {
|
|
296
326
|
log.debug('- Skipping disallowed hostname', meta);
|
|
297
|
-
await
|
|
327
|
+
await send('Fetch.failRequest', {
|
|
298
328
|
requestId: request.interceptId,
|
|
299
329
|
errorReason: 'Aborted'
|
|
300
330
|
});
|
|
301
331
|
} else if (resource && (resource.root || resource.provided || !disableCache)) {
|
|
302
332
|
log.debug(resource.root ? '- Serving root resource' : '- Resource cache hit', meta);
|
|
303
|
-
await
|
|
333
|
+
await send('Fetch.fulfillRequest', {
|
|
304
334
|
requestId: request.interceptId,
|
|
305
335
|
responseCode: resource.status || 200,
|
|
306
336
|
body: Buffer.from(resource.content).toString('base64'),
|
|
@@ -310,18 +340,35 @@ async function sendResponseResource(network, request, session) {
|
|
|
310
340
|
}))
|
|
311
341
|
});
|
|
312
342
|
} else {
|
|
313
|
-
await
|
|
343
|
+
await send('Fetch.continueRequest', {
|
|
314
344
|
requestId: request.interceptId
|
|
315
345
|
});
|
|
316
346
|
}
|
|
317
347
|
} catch (error) {
|
|
318
348
|
/* istanbul ignore next: too hard to test (create race condition) */
|
|
319
349
|
if (session.closing && error.message.includes('close')) return;
|
|
350
|
+
|
|
351
|
+
// if failure is due to an already aborted request, ignore it
|
|
352
|
+
// due to race condition we might get aborted event later and see a `Invalid InterceptionId`
|
|
353
|
+
// error before, in which case we should wait for a tick and check again
|
|
354
|
+
// Note: its not a necessity that we would get aborted callback in a tick, its just that if we
|
|
355
|
+
// already have it then we can safely ignore this error
|
|
356
|
+
// Its very hard to test it as this function should be called and request should get cancelled before
|
|
357
|
+
if (error.message === ABORTED_MESSAGE || error.message.includes('Invalid InterceptionId')) {
|
|
358
|
+
// defer this to the end of queue to make sure that any incoming aborted messages were
|
|
359
|
+
// handled and network.#aborted is updated
|
|
360
|
+
await new Promise((res, _) => process.nextTick(res));
|
|
361
|
+
/* istanbul ignore else: too hard to create race where abortion event is delayed */
|
|
362
|
+
if (network.isAborted(request.requestId)) {
|
|
363
|
+
log.debug(`Ignoring further steps for ${url} as request was aborted by the browser.`);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
320
367
|
log.debug(`Encountered an error handling request: ${url}`, meta);
|
|
321
368
|
log.debug(error);
|
|
322
369
|
|
|
323
370
|
/* istanbul ignore next: catch race condition */
|
|
324
|
-
await
|
|
371
|
+
await send('Fetch.failRequest', {
|
|
325
372
|
requestId: request.interceptId,
|
|
326
373
|
errorReason: 'Failed'
|
|
327
374
|
}).catch(e => log.debug(e, meta));
|
package/dist/snapshot.js
CHANGED
|
@@ -78,7 +78,7 @@ function mapSnapshotOptions(snapshots, context) {
|
|
|
78
78
|
// assign additional options to included snaphots
|
|
79
79
|
snapshotMatches(snap, include, exclude) ? Object.assign(snap, opts) : snap), snap => getSnapshotOptions(snap, context));
|
|
80
80
|
|
|
81
|
-
// reduce snapshots with
|
|
81
|
+
// reduce snapshots with options
|
|
82
82
|
return snapshots.reduce((acc, snapshot) => {
|
|
83
83
|
var _snapshot;
|
|
84
84
|
// transform snapshot URL shorthand into an object
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/core",
|
|
3
|
-
"version": "1.26.3-beta.
|
|
3
|
+
"version": "1.26.3-beta.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"test:types": "tsd"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@percy/client": "1.26.3-beta.
|
|
47
|
-
"@percy/config": "1.26.3-beta.
|
|
48
|
-
"@percy/dom": "1.26.3-beta.
|
|
49
|
-
"@percy/logger": "1.26.3-beta.
|
|
46
|
+
"@percy/client": "1.26.3-beta.2",
|
|
47
|
+
"@percy/config": "1.26.3-beta.2",
|
|
48
|
+
"@percy/dom": "1.26.3-beta.2",
|
|
49
|
+
"@percy/logger": "1.26.3-beta.2",
|
|
50
50
|
"content-disposition": "^0.5.4",
|
|
51
51
|
"cross-spawn": "^7.0.3",
|
|
52
52
|
"extract-zip": "^2.0.1",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"rimraf": "^3.0.2",
|
|
58
58
|
"ws": "^8.0.0"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "5e402f5ff469cc521506fef6a347e04a1a2e1434"
|
|
61
61
|
}
|