@percy/core 1.29.3-beta.1 → 1.29.3
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 +4 -1
- package/dist/network.js +13 -1
- package/dist/snapshot.js +19 -1
- package/dist/utils.js +73 -0
- package/package.json +8 -8
package/dist/discovery.js
CHANGED
|
@@ -389,7 +389,10 @@ export function createDiscoveryQueue(percy) {
|
|
|
389
389
|
authorization: snapshot.discovery.authorization,
|
|
390
390
|
userAgent: snapshot.discovery.userAgent,
|
|
391
391
|
captureMockedServiceWorker: snapshot.discovery.captureMockedServiceWorker,
|
|
392
|
-
meta:
|
|
392
|
+
meta: {
|
|
393
|
+
...snapshot.meta,
|
|
394
|
+
snapshotURL: snapshot.url
|
|
395
|
+
},
|
|
393
396
|
// enable network inteception
|
|
394
397
|
intercept: {
|
|
395
398
|
enableJavaScript: snapshot.enableJavaScript,
|
package/dist/network.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { request as makeRequest } from '@percy/client/utils';
|
|
2
2
|
import logger from '@percy/logger';
|
|
3
3
|
import mime from 'mime-types';
|
|
4
|
-
import { DefaultMap, createResource, hostnameMatches, normalizeURL, waitFor } from './utils.js';
|
|
4
|
+
import { DefaultMap, createResource, hostnameMatches, normalizeURL, waitFor, decodeAndEncodeURLWithLogging } from './utils.js';
|
|
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'];
|
|
@@ -205,6 +205,7 @@ export class Network {
|
|
|
205
205
|
// Called when a request will be sent. If the request has already been intercepted, handle it;
|
|
206
206
|
// otherwise set it to be pending until it is paused.
|
|
207
207
|
_handleRequestWillBeSent = async event => {
|
|
208
|
+
var _this$meta;
|
|
208
209
|
let {
|
|
209
210
|
requestId,
|
|
210
211
|
request,
|
|
@@ -213,6 +214,17 @@ export class Network {
|
|
|
213
214
|
|
|
214
215
|
// do not handle data urls
|
|
215
216
|
if (request.url.startsWith('data:')) return;
|
|
217
|
+
|
|
218
|
+
// Browsers handle URL encoding leniently.
|
|
219
|
+
// This code checks for issues such as `%` and leading spaces and warns the user accordingly.
|
|
220
|
+
decodeAndEncodeURLWithLogging(request.url, this.log, {
|
|
221
|
+
meta: {
|
|
222
|
+
...this.meta,
|
|
223
|
+
url: request.url
|
|
224
|
+
},
|
|
225
|
+
shouldLogWarning: request.url !== ((_this$meta = this.meta) === null || _this$meta === void 0 ? void 0 : _this$meta.snapshotURL),
|
|
226
|
+
warningMessage: `An invalid URL was detected for url: ${request.url} - the snapshot may fail on Percy. Please verify that your asset URL is valid.`
|
|
227
|
+
});
|
|
216
228
|
if (this.intercept) {
|
|
217
229
|
this.#pending.set(requestId, event);
|
|
218
230
|
if (this.captureMockedServiceWorker) {
|
package/dist/snapshot.js
CHANGED
|
@@ -3,7 +3,7 @@ import PercyConfig from '@percy/config';
|
|
|
3
3
|
import micromatch from 'micromatch';
|
|
4
4
|
import { configSchema } from './config.js';
|
|
5
5
|
import Queue from './queue.js';
|
|
6
|
-
import { request, hostnameMatches, yieldTo, snapshotLogName } from './utils.js';
|
|
6
|
+
import { request, hostnameMatches, yieldTo, snapshotLogName, decodeAndEncodeURLWithLogging } from './utils.js';
|
|
7
7
|
import { JobData } from './wait-for-job.js';
|
|
8
8
|
|
|
9
9
|
// Throw a better error message for missing or invalid urls
|
|
@@ -17,6 +17,23 @@ function validURL(url, base) {
|
|
|
17
17
|
throw new Error(`Invalid snapshot URL: ${e.input}`);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
function validateAndFixSnapshotUrl(snapshot) {
|
|
21
|
+
let log = logger('core:snapshot');
|
|
22
|
+
// encoding snapshot url, if contians invalid URI characters/syntax
|
|
23
|
+
let modifiedURL = decodeAndEncodeURLWithLogging(snapshot.url, log, {
|
|
24
|
+
meta: {
|
|
25
|
+
snapshot: {
|
|
26
|
+
name: snapshot.name || snapshot.url
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
shouldLogWarning: true,
|
|
30
|
+
warningMessage: `Invalid URL detected for url: ${snapshot.url} - the snapshot may fail on Percy. Please confirm that your website URL is valid.`
|
|
31
|
+
});
|
|
32
|
+
if (modifiedURL !== snapshot.url) {
|
|
33
|
+
log.debug(`Snapshot URL modified to: ${modifiedURL}`);
|
|
34
|
+
snapshot.url = modifiedURL;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
20
37
|
|
|
21
38
|
// used to deserialize regular expression strings
|
|
22
39
|
const RE_REGEXP = /^\/(.+)\/(\w+)?$/;
|
|
@@ -86,6 +103,7 @@ function mapSnapshotOptions(snapshots, context) {
|
|
|
86
103
|
if (typeof snapshot === 'string') snapshot = {
|
|
87
104
|
url: snapshot
|
|
88
105
|
};
|
|
106
|
+
if (process.env.PERCY_MODIFY_SNAPSHOT_URL !== 'false') validateAndFixSnapshotUrl(snapshot);
|
|
89
107
|
|
|
90
108
|
// normalize the snapshot url and use it for the default name
|
|
91
109
|
let url = validURL(snapshot.url, context === null || context === void 0 ? void 0 : context.baseUrl);
|
package/dist/utils.js
CHANGED
|
@@ -379,6 +379,79 @@ export function redactSecrets(data) {
|
|
|
379
379
|
export function base64encode(content) {
|
|
380
380
|
return Buffer.from(content).toString('base64');
|
|
381
381
|
}
|
|
382
|
+
const RESERVED_CHARACTERS = {
|
|
383
|
+
'%3A': ':',
|
|
384
|
+
'%23': '#',
|
|
385
|
+
'%24': '$',
|
|
386
|
+
'%26': '&',
|
|
387
|
+
'%2B': '+',
|
|
388
|
+
'%2C': ',',
|
|
389
|
+
'%2F': '/',
|
|
390
|
+
'%3B': ';',
|
|
391
|
+
'%3D': '=',
|
|
392
|
+
'%3F': '?',
|
|
393
|
+
'%40': '@'
|
|
394
|
+
};
|
|
395
|
+
function _replaceReservedCharactersWithPlaceholder(url) {
|
|
396
|
+
let result = url;
|
|
397
|
+
let matchedPattern = {};
|
|
398
|
+
let placeHolderCount = 0;
|
|
399
|
+
for (let key of Object.keys(RESERVED_CHARACTERS)) {
|
|
400
|
+
let regex = new RegExp(key, 'g');
|
|
401
|
+
if (regex.test(result)) {
|
|
402
|
+
let placeholder = `__PERCY_PLACEHOLDER_${placeHolderCount}__`;
|
|
403
|
+
result = result.replace(regex, placeholder);
|
|
404
|
+
matchedPattern[placeholder] = key;
|
|
405
|
+
placeHolderCount++;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
url: result,
|
|
410
|
+
matchedPattern
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function _replacePlaceholdersWithReservedCharacters(matchedPattern, url) {
|
|
414
|
+
let result = url;
|
|
415
|
+
for (let [key, value] of Object.entries(matchedPattern)) {
|
|
416
|
+
let regex = new RegExp(key, 'g');
|
|
417
|
+
result = result.replace(regex, value);
|
|
418
|
+
}
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// This function replaces invalid character that are not the
|
|
423
|
+
// part of valid URI syntax with there correct encoded value.
|
|
424
|
+
// Also, if a character is a part of valid URI syntax, those characters
|
|
425
|
+
// are not encoded
|
|
426
|
+
// Eg: [abc] -> gets encoded to %5Babc%5D
|
|
427
|
+
// ab c -> ab%20c
|
|
428
|
+
export function decodeAndEncodeURLWithLogging(url, logger, options = {}) {
|
|
429
|
+
// In case the url is partially encoded, then directly using encodeURI()
|
|
430
|
+
// will encode those characters again. Therefore decodeURI once helps is decoding
|
|
431
|
+
// partially encoded URL and then after encoding it again, full URL get encoded
|
|
432
|
+
// correctly.
|
|
433
|
+
const {
|
|
434
|
+
meta,
|
|
435
|
+
shouldLogWarning,
|
|
436
|
+
warningMessage
|
|
437
|
+
} = options;
|
|
438
|
+
try {
|
|
439
|
+
let {
|
|
440
|
+
url: placeholderURL,
|
|
441
|
+
matchedPattern
|
|
442
|
+
} = _replaceReservedCharactersWithPlaceholder(url);
|
|
443
|
+
let decodedURL = decodeURI(placeholderURL);
|
|
444
|
+
let encodedURL = encodeURI(decodedURL);
|
|
445
|
+
encodedURL = _replacePlaceholdersWithReservedCharacters(matchedPattern, encodedURL);
|
|
446
|
+
return encodedURL;
|
|
447
|
+
} catch (error) {
|
|
448
|
+
logger.debug(error, meta);
|
|
449
|
+
if (error.name === 'URIError' && shouldLogWarning) {
|
|
450
|
+
logger.warn(warningMessage);
|
|
451
|
+
}
|
|
452
|
+
return url;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
382
455
|
export function snapshotLogName(name, meta) {
|
|
383
456
|
var _meta$snapshot;
|
|
384
457
|
if (meta !== null && meta !== void 0 && (_meta$snapshot = meta.snapshot) !== null && _meta$snapshot !== void 0 && _meta$snapshot.testCase) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/core",
|
|
3
|
-
"version": "1.29.3
|
|
3
|
+
"version": "1.29.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public",
|
|
12
|
-
"tag": "
|
|
12
|
+
"tag": "latest"
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=14"
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"test:types": "tsd"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@percy/client": "1.29.3
|
|
47
|
-
"@percy/config": "1.29.3
|
|
48
|
-
"@percy/dom": "1.29.3
|
|
49
|
-
"@percy/logger": "1.29.3
|
|
50
|
-
"@percy/webdriver-utils": "1.29.3
|
|
46
|
+
"@percy/client": "1.29.3",
|
|
47
|
+
"@percy/config": "1.29.3",
|
|
48
|
+
"@percy/dom": "1.29.3",
|
|
49
|
+
"@percy/logger": "1.29.3",
|
|
50
|
+
"@percy/webdriver-utils": "1.29.3",
|
|
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": "f374b2c04840cc2992a43bff837d9740bf30f7b8"
|
|
64
64
|
}
|