@percy/core 1.29.0 → 1.29.1-beta.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/dist/config.js CHANGED
@@ -7,6 +7,10 @@ export const configSchema = {
7
7
  deferUploads: {
8
8
  type: 'boolean'
9
9
  },
10
+ useSystemProxy: {
11
+ type: 'boolean',
12
+ default: false
13
+ },
10
14
  token: {
11
15
  type: 'string'
12
16
  },
@@ -584,6 +588,9 @@ export const snapshotSchema = {
584
588
  type: 'string'
585
589
  }
586
590
  },
591
+ cookies: {
592
+ type: 'string'
593
+ },
587
594
  resources: {
588
595
  type: 'array',
589
596
  items: {
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, decodeAndEncodeURLWithLogging, hostnameMatches, normalizeURL, waitFor } 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'];
@@ -213,6 +213,17 @@ export class Network {
213
213
 
214
214
  // do not handle data urls
215
215
  if (request.url.startsWith('data:')) return;
216
+
217
+ // Browsers handle URL encoding leniently, but invalid characters can break tools like Jackproxy.
218
+ // This code checks for issues such as `%` and leading spaces and warns the user accordingly.
219
+ decodeAndEncodeURLWithLogging(request.url, this.log, {
220
+ meta: {
221
+ ...this.meta,
222
+ url: request.url
223
+ },
224
+ shouldLogWarning: true,
225
+ warningMessage: `An invalid URL was detected for url: ${request.url} - the snapshot may fail on Percy. Please verify that your asset URL is valid.`
226
+ });
216
227
  if (this.intercept) {
217
228
  this.#pending.set(requestId, event);
218
229
  if (this.captureMockedServiceWorker) {
package/dist/percy.js CHANGED
@@ -17,7 +17,7 @@ import logger from '@percy/logger';
17
17
  import { getProxy } from '@percy/client/utils';
18
18
  import Browser from './browser.js';
19
19
  import Pako from 'pako';
20
- import { base64encode, generatePromise, yieldAll, yieldTo, redactSecrets } from './utils.js';
20
+ import { base64encode, generatePromise, yieldAll, yieldTo, redactSecrets, detectSystemProxyAndLog } from './utils.js';
21
21
  import { createPercyServer, createStaticServer } from './api.js';
22
22
  import { gatherSnapshots, createSnapshotsQueue, validateSnapshotOptions } from './snapshot.js';
23
23
  import { discoverSnapshotResources, createDiscoveryQueue } from './discovery.js';
@@ -179,6 +179,9 @@ export class Percy {
179
179
  if (process.env.PERCY_CLIENT_ERROR_LOGS !== 'false') {
180
180
  this.log.warn('Notice: Percy collects CI logs for service improvement, stored for 30 days. Opt-out anytime with export PERCY_CLIENT_ERROR_LOGS=false');
181
181
  }
182
+ // Not awaiting proxy check as this can be asyncronous when not enabled
183
+ const detectProxy = detectSystemProxyAndLog(this.config.percy.useSystemProxy);
184
+ if (this.config.percy.useSystemProxy) await detectProxy;
182
185
  // start the snapshots queue immediately when not delayed or deferred
183
186
  if (!this.delayUploads && !this.deferUploads) yield _classPrivateFieldGet2(this, _snapshots).start();
184
187
  // do not start the discovery queue when not needed
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,9 +103,9 @@ function mapSnapshotOptions(snapshots, context) {
86
103
  if (typeof snapshot === 'string') snapshot = {
87
104
  url: snapshot
88
105
  };
89
-
90
- // normalize the snapshot url and use it for the default name
106
+ validateAndFixSnapshotUrl(snapshot);
91
107
  let url = validURL(snapshot.url, context === null || context === void 0 ? void 0 : context.baseUrl);
108
+ // normalize the snapshot url and use it for the default name
92
109
  (_snapshot = snapshot).name || (_snapshot.name = `${url.pathname}${url.search}${url.hash}`);
93
110
  snapshot.url = url.href;
94
111
 
package/dist/utils.js CHANGED
@@ -5,6 +5,8 @@ import YAML from 'yaml';
5
5
  import path from 'path';
6
6
  import url from 'url';
7
7
  import { readFileSync } from 'fs';
8
+ import logger from '@percy/logger';
9
+ import DetectProxy from '@percy/client/detect-proxy';
8
10
  export { request, getPackageJSON, hostnameMatches } from '@percy/client/utils';
9
11
  export { Server, createServer } from './server.js';
10
12
 
@@ -377,6 +379,35 @@ export function redactSecrets(data) {
377
379
  export function base64encode(content) {
378
380
  return Buffer.from(content).toString('base64');
379
381
  }
382
+
383
+ // This function replaces invalid character that are not the
384
+ // part of valid URI syntax with there correct encoded value.
385
+ // Also, if a character is a part of valid URI syntax, those characters
386
+ // are not encoded
387
+ // Eg: [abc] -> gets encoded to %5Babc%5D
388
+ // ab c -> ab%20c
389
+ export function decodeAndEncodeURLWithLogging(url, logger, options = {}) {
390
+ // In case the url is partially encoded, then directly using encodeURI()
391
+ // will encode those characters again. Therefore decodeURI once helps is decoding
392
+ // partially encoded URL and then after encoding it again, full URL get encoded
393
+ // correctly.
394
+ const {
395
+ meta,
396
+ shouldLogWarning,
397
+ warningMessage
398
+ } = options;
399
+ try {
400
+ let decodedURL = decodeURI(url); // This can throw error, so handle it will trycatch
401
+ let encodedURL = encodeURI(decodedURL);
402
+ return encodedURL;
403
+ } catch (error) {
404
+ logger.debug(error, meta);
405
+ if (error.name === 'URIError' && shouldLogWarning) {
406
+ logger.warn(warningMessage);
407
+ }
408
+ return url;
409
+ }
410
+ }
380
411
  export function snapshotLogName(name, meta) {
381
412
  var _meta$snapshot;
382
413
  if (meta !== null && meta !== void 0 && (_meta$snapshot = meta.snapshot) !== null && _meta$snapshot !== void 0 && _meta$snapshot.testCase) {
@@ -384,6 +415,34 @@ export function snapshotLogName(name, meta) {
384
415
  }
385
416
  return name;
386
417
  }
418
+ export async function detectSystemProxyAndLog(applyProxy) {
419
+ // if proxy is already set no need to check again
420
+ if (process.env.HTTPS_PROXY || process.env.HTTP_PROXY) return;
421
+ let proxyPresent = false;
422
+ const log = logger('core:utils');
423
+ // Checking proxy shouldn't cause failure
424
+ try {
425
+ const detectProxy = new DetectProxy();
426
+ const proxies = await detectProxy.getSystemProxy();
427
+ proxyPresent = proxies.length !== 0;
428
+ if (proxyPresent) {
429
+ if (applyProxy) {
430
+ proxies.forEach(proxy => {
431
+ if (proxy.type === 'HTTPS') {
432
+ process.env.HTTPS_PROXY = 'https://' + proxy.host + ':' + proxy.port;
433
+ } else if (proxy.type === 'HTTP') {
434
+ process.env.HTTP_PROXY = 'http://' + proxy.host + ':' + proxy.port;
435
+ }
436
+ });
437
+ } else {
438
+ log.warn('We have detected a system level proxy in your system. use HTTP_PROXY or HTTPS_PROXY env vars or To auto apply proxy set useSystemProxy: true under percy in config file');
439
+ }
440
+ }
441
+ } catch (e) {
442
+ log.debug(`Failed to detect system proxy ${e}`);
443
+ }
444
+ return proxyPresent;
445
+ }
387
446
 
388
447
  // DefaultMap, which returns a default value for an uninitialized key
389
448
  // Similar to defaultDict in python
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/core",
3
- "version": "1.29.0",
3
+ "version": "1.29.1-beta.0",
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": "latest"
12
+ "tag": "beta"
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.0",
47
- "@percy/config": "1.29.0",
48
- "@percy/dom": "1.29.0",
49
- "@percy/logger": "1.29.0",
50
- "@percy/webdriver-utils": "1.29.0",
46
+ "@percy/client": "1.29.1-beta.0",
47
+ "@percy/config": "1.29.1-beta.0",
48
+ "@percy/dom": "1.29.1-beta.0",
49
+ "@percy/logger": "1.29.1-beta.0",
50
+ "@percy/webdriver-utils": "1.29.1-beta.0",
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": "5fed3bcc30798d4447b70ee57ea6331e8ec9b501"
63
+ "gitHead": "d325b7bbe56764dbde494477d1f4f3bfdc562d6e"
64
64
  }