@percy/core 1.29.1-alpha.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 +7 -0
- package/dist/discovery.js +48 -22
- package/dist/network.js +28 -3
- package/dist/page.js +22 -3
- package/dist/percy.js +50 -35
- package/dist/queue.js +113 -80
- package/dist/server.js +57 -39
- package/dist/snapshot.js +20 -3
- package/dist/timing.js +1 -1
- package/dist/utils.js +59 -0
- package/package.json +8 -8
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/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
|
@@ -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'];
|
|
@@ -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
|
|
@@ -199,6 +213,17 @@ export class Network {
|
|
|
199
213
|
|
|
200
214
|
// do not handle data urls
|
|
201
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
|
+
});
|
|
202
227
|
if (this.intercept) {
|
|
203
228
|
this.#pending.set(requestId, event);
|
|
204
229
|
if (this.captureMockedServiceWorker) {
|
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/percy.js
CHANGED
|
@@ -4,16 +4,20 @@ function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("C
|
|
|
4
4
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
5
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
6
6
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
function _classPrivateMethodGet(s, a, r) { return _assertClassBrand(a, s), r; }
|
|
8
|
+
function _classPrivateFieldGet2(e, t) { var r = _classPrivateFieldGet(t, e); return _classApplyDescriptorGet(e, r); }
|
|
9
|
+
function _classApplyDescriptorGet(e, t) { return t.get ? t.get.call(e) : t.value; }
|
|
10
|
+
function _classPrivateFieldSet(e, t, r) { var s = _classPrivateFieldGet(t, e); return _classApplyDescriptorSet(e, s, r), r; }
|
|
7
11
|
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
|
|
8
|
-
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
|
|
9
12
|
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
|
13
|
+
function _classApplyDescriptorSet(e, t, l) { if (t.set) t.set.call(e, l);else { if (!t.writable) throw new TypeError("attempted to set read only private field"); t.value = l; } }
|
|
10
14
|
import PercyClient from '@percy/client';
|
|
11
15
|
import PercyConfig from '@percy/config';
|
|
12
16
|
import logger from '@percy/logger';
|
|
13
17
|
import { getProxy } from '@percy/client/utils';
|
|
14
18
|
import Browser from './browser.js';
|
|
15
19
|
import Pako from 'pako';
|
|
16
|
-
import { base64encode, generatePromise, yieldAll, yieldTo, redactSecrets } from './utils.js';
|
|
20
|
+
import { base64encode, generatePromise, yieldAll, yieldTo, redactSecrets, detectSystemProxyAndLog } from './utils.js';
|
|
17
21
|
import { createPercyServer, createStaticServer } from './api.js';
|
|
18
22
|
import { gatherSnapshots, createSnapshotsQueue, validateSnapshotOptions } from './snapshot.js';
|
|
19
23
|
import { discoverSnapshotResources, createDiscoveryQueue } from './discovery.js';
|
|
@@ -24,7 +28,8 @@ import { WaitForJob } from './wait-for-job.js';
|
|
|
24
28
|
// concurrently and the build is not finalized until all snapshots have been handled.
|
|
25
29
|
var _discovery = /*#__PURE__*/new WeakMap();
|
|
26
30
|
var _snapshots = /*#__PURE__*/new WeakMap();
|
|
27
|
-
var
|
|
31
|
+
var _displaySuggestionLogs = /*#__PURE__*/new WeakSet();
|
|
32
|
+
var _proxyEnabled = /*#__PURE__*/new WeakSet();
|
|
28
33
|
export class Percy {
|
|
29
34
|
// Static shortcut to create and start an instance in one call
|
|
30
35
|
static async start(options) {
|
|
@@ -63,11 +68,18 @@ export class Percy {
|
|
|
63
68
|
..._options
|
|
64
69
|
} = {}) {
|
|
65
70
|
var _config$percy, _config$percy2;
|
|
66
|
-
_classPrivateMethodInitSpec(this,
|
|
71
|
+
_classPrivateMethodInitSpec(this, _proxyEnabled);
|
|
72
|
+
_classPrivateMethodInitSpec(this, _displaySuggestionLogs);
|
|
67
73
|
_defineProperty(this, "log", logger('core'));
|
|
68
74
|
_defineProperty(this, "readyState", null);
|
|
69
|
-
_classPrivateFieldInitSpec(this, _discovery,
|
|
70
|
-
|
|
75
|
+
_classPrivateFieldInitSpec(this, _discovery, {
|
|
76
|
+
writable: true,
|
|
77
|
+
value: null
|
|
78
|
+
});
|
|
79
|
+
_classPrivateFieldInitSpec(this, _snapshots, {
|
|
80
|
+
writable: true,
|
|
81
|
+
value: null
|
|
82
|
+
});
|
|
71
83
|
let config = PercyConfig.load({
|
|
72
84
|
overrides: _options,
|
|
73
85
|
path: configFile
|
|
@@ -95,8 +107,8 @@ export class Percy {
|
|
|
95
107
|
});
|
|
96
108
|
if (server) this.server = createPercyServer(this, port);
|
|
97
109
|
this.browser = new Browser(this);
|
|
98
|
-
_classPrivateFieldSet(
|
|
99
|
-
_classPrivateFieldSet(
|
|
110
|
+
_classPrivateFieldSet(this, _discovery, createDiscoveryQueue(this));
|
|
111
|
+
_classPrivateFieldSet(this, _snapshots, createSnapshotsQueue(this));
|
|
100
112
|
|
|
101
113
|
// generator methods are wrapped to autorun and return promises
|
|
102
114
|
for (let m of ['start', 'stop', 'flush', 'idle', 'snapshot', 'upload']) {
|
|
@@ -149,10 +161,10 @@ export class Percy {
|
|
|
149
161
|
let {
|
|
150
162
|
concurrency
|
|
151
163
|
} = this.config.discovery;
|
|
152
|
-
|
|
164
|
+
_classPrivateFieldGet2(this, _discovery).set({
|
|
153
165
|
concurrency
|
|
154
166
|
});
|
|
155
|
-
|
|
167
|
+
_classPrivateFieldGet2(this, _snapshots).set({
|
|
156
168
|
concurrency
|
|
157
169
|
});
|
|
158
170
|
return this.config;
|
|
@@ -167,10 +179,13 @@ export class Percy {
|
|
|
167
179
|
if (process.env.PERCY_CLIENT_ERROR_LOGS !== 'false') {
|
|
168
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');
|
|
169
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;
|
|
170
185
|
// start the snapshots queue immediately when not delayed or deferred
|
|
171
|
-
if (!this.delayUploads && !this.deferUploads) yield
|
|
186
|
+
if (!this.delayUploads && !this.deferUploads) yield _classPrivateFieldGet2(this, _snapshots).start();
|
|
172
187
|
// do not start the discovery queue when not needed
|
|
173
|
-
if (!this.skipDiscovery) yield
|
|
188
|
+
if (!this.skipDiscovery) yield _classPrivateFieldGet2(this, _discovery).start();
|
|
174
189
|
// start a local API server for SDK communication
|
|
175
190
|
if (this.server) yield this.server.listen();
|
|
176
191
|
if (this.projectType === 'web') {
|
|
@@ -188,8 +203,8 @@ export class Percy {
|
|
|
188
203
|
var _this$server2;
|
|
189
204
|
// on error, close any running server and end queues
|
|
190
205
|
await ((_this$server2 = this.server) === null || _this$server2 === void 0 ? void 0 : _this$server2.close());
|
|
191
|
-
await
|
|
192
|
-
await
|
|
206
|
+
await _classPrivateFieldGet2(this, _discovery).end();
|
|
207
|
+
await _classPrivateFieldGet2(this, _snapshots).end();
|
|
193
208
|
|
|
194
209
|
// mark this instance as closed unless aborting
|
|
195
210
|
this.readyState = error.name !== 'AbortError' ? 3 : null;
|
|
@@ -208,8 +223,8 @@ export class Percy {
|
|
|
208
223
|
|
|
209
224
|
// Resolves once snapshot and upload queues are idle
|
|
210
225
|
async *idle() {
|
|
211
|
-
yield*
|
|
212
|
-
yield*
|
|
226
|
+
yield* _classPrivateFieldGet2(this, _discovery).idle();
|
|
227
|
+
yield* _classPrivateFieldGet2(this, _snapshots).idle();
|
|
213
228
|
}
|
|
214
229
|
|
|
215
230
|
// Wait for currently queued snapshots then run and wait for resulting uploads
|
|
@@ -222,13 +237,13 @@ export class Percy {
|
|
|
222
237
|
yield new Promise(r => setImmediate(r));
|
|
223
238
|
|
|
224
239
|
// flush and log progress for discovery before snapshots
|
|
225
|
-
if (!this.skipDiscovery &&
|
|
226
|
-
if (options) yield* yieldAll(options.map(o =>
|
|
240
|
+
if (!this.skipDiscovery && _classPrivateFieldGet2(this, _discovery).size) {
|
|
241
|
+
if (options) yield* yieldAll(options.map(o => _classPrivateFieldGet2(this, _discovery).process(o)));else yield* _classPrivateFieldGet2(this, _discovery).flush(size => callback === null || callback === void 0 ? void 0 : callback('Processing', size));
|
|
227
242
|
}
|
|
228
243
|
|
|
229
244
|
// flush and log progress for snapshot uploads
|
|
230
|
-
if (!this.skipUploads &&
|
|
231
|
-
if (options) yield* yieldAll(options.map(o =>
|
|
245
|
+
if (!this.skipUploads && _classPrivateFieldGet2(this, _snapshots).size) {
|
|
246
|
+
if (options) yield* yieldAll(options.map(o => _classPrivateFieldGet2(this, _snapshots).process(o)));else yield* _classPrivateFieldGet2(this, _snapshots).flush(size => callback === null || callback === void 0 ? void 0 : callback('Uploading', size));
|
|
232
247
|
}
|
|
233
248
|
}
|
|
234
249
|
|
|
@@ -247,8 +262,8 @@ export class Percy {
|
|
|
247
262
|
|
|
248
263
|
// close queues asap
|
|
249
264
|
if (force) {
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
_classPrivateFieldGet2(this, _discovery).close(true);
|
|
266
|
+
_classPrivateFieldGet2(this, _snapshots).close(true);
|
|
252
267
|
}
|
|
253
268
|
|
|
254
269
|
// already stopping
|
|
@@ -273,14 +288,14 @@ export class Percy {
|
|
|
273
288
|
}
|
|
274
289
|
|
|
275
290
|
// if dry-running, log the total number of snapshots
|
|
276
|
-
if (this.dryRun &&
|
|
277
|
-
this.log.info(info('Found',
|
|
291
|
+
if (this.dryRun && _classPrivateFieldGet2(this, _snapshots).size) {
|
|
292
|
+
this.log.info(info('Found', _classPrivateFieldGet2(this, _snapshots).size));
|
|
278
293
|
}
|
|
279
294
|
|
|
280
295
|
// close server and end queues
|
|
281
296
|
await ((_this$server3 = this.server) === null || _this$server3 === void 0 ? void 0 : _this$server3.close());
|
|
282
|
-
await
|
|
283
|
-
await
|
|
297
|
+
await _classPrivateFieldGet2(this, _discovery).end();
|
|
298
|
+
await _classPrivateFieldGet2(this, _snapshots).end();
|
|
284
299
|
|
|
285
300
|
// mark instance as stopped
|
|
286
301
|
this.readyState = 3;
|
|
@@ -343,7 +358,7 @@ export class Percy {
|
|
|
343
358
|
}
|
|
344
359
|
|
|
345
360
|
// gather snapshots and discover snapshot resources
|
|
346
|
-
yield* discoverSnapshotResources(
|
|
361
|
+
yield* discoverSnapshotResources(_classPrivateFieldGet2(this, _discovery), {
|
|
347
362
|
skipDiscovery: this.skipDiscovery,
|
|
348
363
|
dryRun: this.dryRun,
|
|
349
364
|
snapshots: yield* gatherSnapshots(options, {
|
|
@@ -363,7 +378,7 @@ export class Percy {
|
|
|
363
378
|
});
|
|
364
379
|
}
|
|
365
380
|
// push each finished snapshot to the snapshots queue
|
|
366
|
-
|
|
381
|
+
_classPrivateFieldGet2(this, _snapshots).push(snapshot);
|
|
367
382
|
});
|
|
368
383
|
} finally {
|
|
369
384
|
var _server;
|
|
@@ -423,9 +438,9 @@ export class Percy {
|
|
|
423
438
|
// return an async generator to allow cancelation
|
|
424
439
|
return async function* () {
|
|
425
440
|
try {
|
|
426
|
-
return yield* yieldTo(
|
|
441
|
+
return yield* yieldTo(_classPrivateFieldGet2(this, _snapshots).push(options));
|
|
427
442
|
} catch (error) {
|
|
428
|
-
|
|
443
|
+
_classPrivateFieldGet2(this, _snapshots).cancel(options);
|
|
429
444
|
// Detecting and suggesting fix for errors;
|
|
430
445
|
await this.suggestionsForFix(error.message);
|
|
431
446
|
throw error;
|
|
@@ -475,7 +490,7 @@ export class Percy {
|
|
|
475
490
|
});
|
|
476
491
|
if (isPercyStarted && !containsSnapshotTaken) {
|
|
477
492
|
// This is the case for No snapshot command called
|
|
478
|
-
|
|
493
|
+
_classPrivateMethodGet(this, _displaySuggestionLogs, _displaySuggestionLogs2).call(this, [{
|
|
479
494
|
failure_reason: 'Snapshot command was not called',
|
|
480
495
|
reason_message: 'Snapshot Command was not called. please check your CI for errors',
|
|
481
496
|
suggestion: 'Try using percy snapshot command to take snapshots',
|
|
@@ -486,14 +501,14 @@ export class Percy {
|
|
|
486
501
|
async suggestionsForFix(errors, options = {}) {
|
|
487
502
|
try {
|
|
488
503
|
const suggestionResponse = await this.client.getErrorAnalysis(errors);
|
|
489
|
-
|
|
504
|
+
_classPrivateMethodGet(this, _displaySuggestionLogs, _displaySuggestionLogs2).call(this, suggestionResponse, options);
|
|
490
505
|
} catch (e) {
|
|
491
506
|
// Common error code for Proxy issues
|
|
492
507
|
const PROXY_CODES = ['ECONNREFUSED', 'ECONNRESET', 'EHOSTUNREACH'];
|
|
493
508
|
if (!!e.code && PROXY_CODES.includes(e.code)) {
|
|
494
509
|
// This can be due to proxy issue
|
|
495
510
|
this.log.error('percy.io might not be reachable, check network connection, proxy and ensure that percy.io is whitelisted.');
|
|
496
|
-
if (!
|
|
511
|
+
if (!_classPrivateMethodGet(this, _proxyEnabled, _proxyEnabled2).call(this)) {
|
|
497
512
|
this.log.error('If inside a proxied envirnment, please configure the following environment variables: HTTP_PROXY, [ and optionally HTTPS_PROXY if you need it ]. Refer to our documentation for more details');
|
|
498
513
|
}
|
|
499
514
|
}
|
|
@@ -532,7 +547,7 @@ export class Percy {
|
|
|
532
547
|
}
|
|
533
548
|
}
|
|
534
549
|
}
|
|
535
|
-
function
|
|
550
|
+
function _displaySuggestionLogs2(suggestions, options = {}) {
|
|
536
551
|
if (!(suggestions !== null && suggestions !== void 0 && suggestions.length)) return;
|
|
537
552
|
suggestions.forEach(item => {
|
|
538
553
|
const failure = item === null || item === void 0 ? void 0 : item.failure_reason;
|
|
@@ -555,7 +570,7 @@ function _displaySuggestionLogs(suggestions, options = {}) {
|
|
|
555
570
|
}
|
|
556
571
|
});
|
|
557
572
|
}
|
|
558
|
-
function
|
|
573
|
+
function _proxyEnabled2() {
|
|
559
574
|
return !!(getProxy({
|
|
560
575
|
protocol: 'https:'
|
|
561
576
|
}) || getProxy({}));
|
package/dist/queue.js
CHANGED
|
@@ -4,9 +4,13 @@ function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("C
|
|
|
4
4
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
5
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
6
6
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
-
function _classPrivateFieldSet(
|
|
8
|
-
function
|
|
7
|
+
function _classPrivateFieldSet(e, t, r) { var s = _classPrivateFieldGet2(t, e); return _classApplyDescriptorSet(e, s, r), r; }
|
|
8
|
+
function _classApplyDescriptorSet(e, t, l) { if (t.set) t.set.call(e, l);else { if (!t.writable) throw new TypeError("attempted to set read only private field"); t.value = l; } }
|
|
9
|
+
function _classPrivateMethodGet(s, a, r) { return _assertClassBrand(a, s), r; }
|
|
10
|
+
function _classPrivateFieldGet(e, t) { var r = _classPrivateFieldGet2(t, e); return _classApplyDescriptorGet(e, r); }
|
|
11
|
+
function _classPrivateFieldGet2(s, a) { return s.get(_assertClassBrand(s, a)); }
|
|
9
12
|
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
|
13
|
+
function _classApplyDescriptorGet(e, t) { return t.get ? t.get.call(e) : t.value; }
|
|
10
14
|
import { yieldFor, generatePromise, AbortController } from './utils.js';
|
|
11
15
|
import logger from '@percy/logger';
|
|
12
16
|
|
|
@@ -39,25 +43,42 @@ class QueueClosedError extends Error {
|
|
|
39
43
|
var _handlers = /*#__PURE__*/new WeakMap();
|
|
40
44
|
var _queued = /*#__PURE__*/new WeakMap();
|
|
41
45
|
var _pending = /*#__PURE__*/new WeakMap();
|
|
42
|
-
var
|
|
46
|
+
var _dequeue = /*#__PURE__*/new WeakSet();
|
|
47
|
+
var _find = /*#__PURE__*/new WeakSet();
|
|
43
48
|
var _start = /*#__PURE__*/new WeakMap();
|
|
44
49
|
var _end = /*#__PURE__*/new WeakMap();
|
|
50
|
+
var _process = /*#__PURE__*/new WeakSet();
|
|
51
|
+
var _until = /*#__PURE__*/new WeakSet();
|
|
45
52
|
export class Queue {
|
|
53
|
+
// item concurrency
|
|
54
|
+
|
|
46
55
|
constructor(name) {
|
|
47
|
-
|
|
48
|
-
_classPrivateMethodInitSpec(this,
|
|
49
|
-
|
|
56
|
+
_classPrivateMethodInitSpec(this, _until);
|
|
57
|
+
_classPrivateMethodInitSpec(this, _process);
|
|
58
|
+
_classPrivateMethodInitSpec(this, _find);
|
|
59
|
+
_classPrivateMethodInitSpec(this, _dequeue);
|
|
50
60
|
_defineProperty(this, "concurrency", 10);
|
|
51
61
|
_defineProperty(this, "log", logger('core:queue'));
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
_classPrivateFieldInitSpec(this,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
_classPrivateFieldInitSpec(this, _handlers, {
|
|
63
|
+
writable: true,
|
|
64
|
+
value: {}
|
|
65
|
+
});
|
|
66
|
+
_classPrivateFieldInitSpec(this, _queued, {
|
|
67
|
+
writable: true,
|
|
68
|
+
value: new Set()
|
|
69
|
+
});
|
|
70
|
+
_classPrivateFieldInitSpec(this, _pending, {
|
|
71
|
+
writable: true,
|
|
72
|
+
value: new Set()
|
|
73
|
+
});
|
|
74
|
+
_classPrivateFieldInitSpec(this, _start, {
|
|
75
|
+
writable: true,
|
|
76
|
+
value: null
|
|
77
|
+
});
|
|
78
|
+
_classPrivateFieldInitSpec(this, _end, {
|
|
79
|
+
writable: true,
|
|
80
|
+
value: null
|
|
81
|
+
});
|
|
61
82
|
_defineProperty(this, "readyState", 0);
|
|
62
83
|
this.name = name;
|
|
63
84
|
}
|
|
@@ -69,13 +90,19 @@ export class Queue {
|
|
|
69
90
|
if (concurrency) this.concurrency = concurrency;
|
|
70
91
|
return this;
|
|
71
92
|
}
|
|
93
|
+
|
|
94
|
+
// Configure queue handlers
|
|
95
|
+
|
|
72
96
|
handle(event, handler) {
|
|
73
|
-
_classPrivateFieldGet(
|
|
97
|
+
_classPrivateFieldGet(this, _handlers)[event] = handler;
|
|
74
98
|
return this;
|
|
75
99
|
}
|
|
100
|
+
|
|
101
|
+
// internal queues
|
|
102
|
+
|
|
76
103
|
// Queue size is total queued and pending items
|
|
77
104
|
get size() {
|
|
78
|
-
return _classPrivateFieldGet(
|
|
105
|
+
return _classPrivateFieldGet(this, _queued).size + _classPrivateFieldGet(this, _pending).size;
|
|
79
106
|
}
|
|
80
107
|
|
|
81
108
|
// Pushes an item into the queue, additional args are passed to any configured task handler.
|
|
@@ -86,8 +113,8 @@ export class Queue {
|
|
|
86
113
|
|
|
87
114
|
// attach any configured error handler
|
|
88
115
|
task.deferred = task.deferred.catch(e => {
|
|
89
|
-
if (!_classPrivateFieldGet(
|
|
90
|
-
return _classPrivateFieldGet(
|
|
116
|
+
if (!_classPrivateFieldGet(this, _handlers).error) throw e;
|
|
117
|
+
return _classPrivateFieldGet(this, _handlers).error(item, e);
|
|
91
118
|
});
|
|
92
119
|
|
|
93
120
|
// when closed, reject with a queue closed error
|
|
@@ -105,22 +132,25 @@ export class Queue {
|
|
|
105
132
|
if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
|
|
106
133
|
item._ctrl = task.ctrl;
|
|
107
134
|
}
|
|
108
|
-
task.item = item = _classPrivateFieldGet(
|
|
109
|
-
task.handler = () => _classPrivateFieldGet(
|
|
135
|
+
task.item = item = _classPrivateFieldGet(this, _handlers).push ? _classPrivateFieldGet(this, _handlers).push(item, exists) : item;
|
|
136
|
+
task.handler = () => _classPrivateFieldGet(this, _handlers).task ? _classPrivateFieldGet(this, _handlers).task(item, ...args) : item;
|
|
110
137
|
|
|
111
138
|
// queue this task & maybe dequeue the next task
|
|
112
|
-
_classPrivateFieldGet(
|
|
113
|
-
|
|
139
|
+
_classPrivateFieldGet(this, _queued).add(task);
|
|
140
|
+
_classPrivateMethodGet(this, _dequeue, _dequeue2).call(this);
|
|
114
141
|
|
|
115
142
|
// return the deferred task promise
|
|
116
143
|
return task.deferred;
|
|
117
144
|
}
|
|
145
|
+
|
|
146
|
+
// Maybe processes the next queued item task.
|
|
147
|
+
|
|
118
148
|
// Cancels and aborts a specific item task.
|
|
119
149
|
cancel(item) {
|
|
120
|
-
let task =
|
|
150
|
+
let task = _classPrivateMethodGet(this, _find, _find2).call(this, item);
|
|
121
151
|
task === null || task === void 0 ? void 0 : task.ctrl.abort();
|
|
122
|
-
let queued = _classPrivateFieldGet(
|
|
123
|
-
let pending = _classPrivateFieldGet(
|
|
152
|
+
let queued = _classPrivateFieldGet(this, _queued).delete(task);
|
|
153
|
+
let pending = _classPrivateFieldGet(this, _pending).delete(task);
|
|
124
154
|
|
|
125
155
|
// reject queued tasks that are not pending
|
|
126
156
|
if (task && queued && !pending) {
|
|
@@ -133,36 +163,39 @@ export class Queue {
|
|
|
133
163
|
|
|
134
164
|
// Returns an item task matching the provided subject.
|
|
135
165
|
|
|
166
|
+
// keep track of start and end tasks
|
|
167
|
+
|
|
136
168
|
// Initialize a starting task or return an existing one.
|
|
137
169
|
start() {
|
|
138
|
-
var
|
|
139
|
-
_classPrivateFieldGet(
|
|
170
|
+
var _classPrivateFieldGet3;
|
|
171
|
+
_classPrivateFieldGet(this, _start) ?? _classPrivateFieldSet(this, _start, deferred({
|
|
140
172
|
readyState: 1
|
|
141
173
|
}));
|
|
142
|
-
(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return _assertClassBrand(_Queue_brand, this, _process).call(this, _classPrivateFieldGet(_start, this)).deferred;
|
|
174
|
+
(_classPrivateFieldGet3 = _classPrivateFieldGet(this, _start)).handler ?? (_classPrivateFieldGet3.handler = _classPrivateFieldGet(this, _end) // wait for any ending task to complete first
|
|
175
|
+
? () => _classPrivateFieldGet(this, _end).promise.then(_classPrivateFieldGet(this, _handlers).start) : _classPrivateFieldGet(this, _handlers).start);
|
|
176
|
+
return _classPrivateMethodGet(this, _process, _process2).call(this, _classPrivateFieldGet(this, _start)).deferred;
|
|
146
177
|
}
|
|
147
178
|
|
|
148
179
|
// intialize an ending task or return an existing one
|
|
149
180
|
end() {
|
|
150
|
-
var
|
|
151
|
-
_classPrivateFieldGet(
|
|
181
|
+
var _classPrivateFieldGet4;
|
|
182
|
+
_classPrivateFieldGet(this, _end) ?? _classPrivateFieldSet(this, _end, deferred({
|
|
152
183
|
readyState: 0
|
|
153
184
|
}));
|
|
154
|
-
(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return _assertClassBrand(_Queue_brand, this, _process).call(this, _classPrivateFieldGet(_end, this)).deferred;
|
|
185
|
+
(_classPrivateFieldGet4 = _classPrivateFieldGet(this, _end)).handler ?? (_classPrivateFieldGet4.handler = _classPrivateFieldGet(this, _start) // wait for any starting task to complete first
|
|
186
|
+
? () => _classPrivateFieldGet(this, _start).promise.then(_classPrivateFieldGet(this, _handlers).end) : _classPrivateFieldGet(this, _handlers).end);
|
|
187
|
+
return _classPrivateMethodGet(this, _process, _process2).call(this, _classPrivateFieldGet(this, _end)).deferred;
|
|
158
188
|
}
|
|
189
|
+
|
|
190
|
+
// represents various queue states such as ready, running, or closed
|
|
191
|
+
|
|
159
192
|
// run the queue, starting it if necessary, and start dequeuing tasks
|
|
160
193
|
run() {
|
|
161
|
-
if (!_classPrivateFieldGet(
|
|
194
|
+
if (!_classPrivateFieldGet(this, _start)) this.start();
|
|
162
195
|
// when starting, state is updated afterwards
|
|
163
|
-
if (this.readyState === 0) _classPrivateFieldGet(
|
|
196
|
+
if (this.readyState === 0) _classPrivateFieldGet(this, _start).readyState = 2;
|
|
164
197
|
if (this.readyState === 1) this.readyState = 2;
|
|
165
|
-
while (
|
|
198
|
+
while (_classPrivateMethodGet(this, _dequeue, _dequeue2).call(this)) _classPrivateMethodGet(this, _dequeue, _dequeue2).call(this);
|
|
166
199
|
return this;
|
|
167
200
|
}
|
|
168
201
|
|
|
@@ -174,9 +207,9 @@ export class Queue {
|
|
|
174
207
|
|
|
175
208
|
// close a running queue, optionally aborting it
|
|
176
209
|
close(abort) {
|
|
177
|
-
var
|
|
210
|
+
var _classPrivateFieldGet5;
|
|
178
211
|
// when starting, state is updated afterwards
|
|
179
|
-
if ((
|
|
212
|
+
if ((_classPrivateFieldGet5 = _classPrivateFieldGet(this, _start)) !== null && _classPrivateFieldGet5 !== void 0 && _classPrivateFieldGet5.pending) _classPrivateFieldGet(this, _start).readyState = 3;
|
|
180
213
|
if (this.readyState < 3) this.readyState = 3;
|
|
181
214
|
if (abort) this.clear();
|
|
182
215
|
return this;
|
|
@@ -184,9 +217,9 @@ export class Queue {
|
|
|
184
217
|
|
|
185
218
|
// clear and abort any queued tasks
|
|
186
219
|
clear() {
|
|
187
|
-
let tasks = [..._classPrivateFieldGet(
|
|
188
|
-
this.log.debug(`Clearing ${this.name} queue, queued state: ${_classPrivateFieldGet(
|
|
189
|
-
_classPrivateFieldGet(
|
|
220
|
+
let tasks = [..._classPrivateFieldGet(this, _queued)];
|
|
221
|
+
this.log.debug(`Clearing ${this.name} queue, queued state: ${_classPrivateFieldGet(this, _queued).size}, pending state: ${_classPrivateFieldGet(this, _pending).size}`);
|
|
222
|
+
_classPrivateFieldGet(this, _queued).clear();
|
|
190
223
|
for (let task of tasks) {
|
|
191
224
|
task.ctrl.abort();
|
|
192
225
|
task.reject(task.ctrl.signal.reason);
|
|
@@ -195,10 +228,10 @@ export class Queue {
|
|
|
195
228
|
|
|
196
229
|
// process a single item task when started
|
|
197
230
|
process(item) {
|
|
198
|
-
var
|
|
199
|
-
let task =
|
|
200
|
-
if (task && !_classPrivateFieldGet(
|
|
201
|
-
(
|
|
231
|
+
var _classPrivateFieldGet6;
|
|
232
|
+
let task = _classPrivateMethodGet(this, _find, _find2).call(this, item);
|
|
233
|
+
if (task && !_classPrivateFieldGet(this, _start)) this.start();
|
|
234
|
+
(_classPrivateFieldGet6 = _classPrivateFieldGet(this, _start)) === null || _classPrivateFieldGet6 === void 0 ? void 0 : _classPrivateFieldGet6.promise.then(() => _classPrivateMethodGet(this, _process, _process2).call(this, task));
|
|
202
235
|
return task === null || task === void 0 ? void 0 : task.deferred;
|
|
203
236
|
}
|
|
204
237
|
|
|
@@ -208,10 +241,10 @@ export class Queue {
|
|
|
208
241
|
// callback every 10ms during checks with the current number of pending tasks
|
|
209
242
|
idle(callback) {
|
|
210
243
|
return yieldFor(() => {
|
|
211
|
-
var
|
|
212
|
-
callback === null || callback === void 0 ? void 0 : callback(_classPrivateFieldGet(
|
|
213
|
-
let starting = ((
|
|
214
|
-
return !starting && !_classPrivateFieldGet(
|
|
244
|
+
var _classPrivateFieldGet7;
|
|
245
|
+
callback === null || callback === void 0 ? void 0 : callback(_classPrivateFieldGet(this, _pending).size);
|
|
246
|
+
let starting = ((_classPrivateFieldGet7 = _classPrivateFieldGet(this, _start)) === null || _classPrivateFieldGet7 === void 0 ? void 0 : _classPrivateFieldGet7.pending) === true;
|
|
247
|
+
return !starting && !_classPrivateFieldGet(this, _pending).size;
|
|
215
248
|
}, {
|
|
216
249
|
idle: 10
|
|
217
250
|
});
|
|
@@ -220,57 +253,57 @@ export class Queue {
|
|
|
220
253
|
// process items up to the latest queued item, starting the queue if necessary;
|
|
221
254
|
// returns a generator that yields until the flushed item has finished processing
|
|
222
255
|
flush(callback) {
|
|
223
|
-
this.log.debug(`Flushing ${this.name} queue, queued state: ${_classPrivateFieldGet(
|
|
256
|
+
this.log.debug(`Flushing ${this.name} queue, queued state: ${_classPrivateFieldGet(this, _queued).size}, pending state: ${_classPrivateFieldGet(this, _pending).size}`);
|
|
224
257
|
let interrupt =
|
|
225
258
|
// check for existing interrupts
|
|
226
|
-
[..._classPrivateFieldGet(
|
|
259
|
+
[..._classPrivateFieldGet(this, _pending)].find(t => t.stop) ?? [..._classPrivateFieldGet(this, _queued)].find(t => t.stop);
|
|
227
260
|
|
|
228
261
|
// get the latest queued or pending task to track
|
|
229
|
-
let flush = [..._classPrivateFieldGet(
|
|
262
|
+
let flush = [..._classPrivateFieldGet(this, _queued)].pop() ?? [..._classPrivateFieldGet(this, _pending)].pop();
|
|
230
263
|
// determine if the queue should be stopped after flushing
|
|
231
264
|
if (flush) flush.stop = (interrupt === null || interrupt === void 0 ? void 0 : interrupt.stop) ?? this.readyState < 2;
|
|
232
265
|
// remove the old interrupt to avoid stopping early
|
|
233
266
|
if (interrupt) delete interrupt.stop;
|
|
234
267
|
// start the queue if not started
|
|
235
|
-
if (!_classPrivateFieldGet(
|
|
268
|
+
if (!_classPrivateFieldGet(this, _start)) this.start();
|
|
236
269
|
// run the queue if stopped
|
|
237
270
|
if (flush !== null && flush !== void 0 && flush.stop) this.run();
|
|
238
271
|
|
|
239
272
|
// will yield with the callback until done flushing
|
|
240
|
-
return
|
|
273
|
+
return _classPrivateMethodGet(this, _until, _until2).call(this, flush, callback);
|
|
241
274
|
}
|
|
242
275
|
|
|
243
276
|
// Repeatedly yields, calling the callback with the position of the task within the queue
|
|
244
277
|
}
|
|
245
|
-
function
|
|
246
|
-
if (!_classPrivateFieldGet(
|
|
247
|
-
if (_classPrivateFieldGet(
|
|
248
|
-
let [task] = _classPrivateFieldGet(
|
|
249
|
-
return
|
|
278
|
+
function _dequeue2() {
|
|
279
|
+
if (!_classPrivateFieldGet(this, _queued).size || this.readyState < 2) return;
|
|
280
|
+
if (_classPrivateFieldGet(this, _pending).size >= this.concurrency) return;
|
|
281
|
+
let [task] = _classPrivateFieldGet(this, _queued);
|
|
282
|
+
return _classPrivateMethodGet(this, _process, _process2).call(this, task);
|
|
250
283
|
}
|
|
251
|
-
function
|
|
252
|
-
let find = _classPrivateFieldGet(
|
|
284
|
+
function _find2(subject) {
|
|
285
|
+
let find = _classPrivateFieldGet(this, _handlers).find
|
|
253
286
|
// use any configured find handler to match items
|
|
254
287
|
? ({
|
|
255
288
|
item
|
|
256
|
-
}) => _classPrivateFieldGet(
|
|
289
|
+
}) => _classPrivateFieldGet(this, _handlers).find(subject, item) : ({
|
|
257
290
|
item
|
|
258
291
|
}) => subject === item;
|
|
259
292
|
return (
|
|
260
293
|
// look at queued then pending items
|
|
261
|
-
[..._classPrivateFieldGet(
|
|
294
|
+
[..._classPrivateFieldGet(this, _queued)].find(find) ?? [..._classPrivateFieldGet(this, _pending)].find(find)
|
|
262
295
|
);
|
|
263
296
|
}
|
|
264
|
-
function
|
|
297
|
+
function _process2(task) {
|
|
265
298
|
var _task$ctrl;
|
|
266
299
|
if (!task || task.promise) return task;
|
|
267
|
-
let queued = _classPrivateFieldGet(
|
|
300
|
+
let queued = _classPrivateFieldGet(this, _queued).has(task);
|
|
268
301
|
// remove queued tasks from the queue
|
|
269
|
-
if (queued) _classPrivateFieldGet(
|
|
302
|
+
if (queued) _classPrivateFieldGet(this, _queued).delete(task);
|
|
270
303
|
// clear queued tasks when ending
|
|
271
|
-
if (task === _classPrivateFieldGet(
|
|
304
|
+
if (task === _classPrivateFieldGet(this, _end)) this.clear();
|
|
272
305
|
// add queued tasks to pending queue
|
|
273
|
-
if (queued) _classPrivateFieldGet(
|
|
306
|
+
if (queued) _classPrivateFieldGet(this, _pending).add(task);
|
|
274
307
|
// stop the queue when necessary
|
|
275
308
|
if (task.stop) this.stop();
|
|
276
309
|
// mark task as pending
|
|
@@ -279,11 +312,11 @@ function _process(task) {
|
|
|
279
312
|
// handle the task using a generator promise
|
|
280
313
|
task.promise = generatePromise(task.handler, (_task$ctrl = task.ctrl) === null || _task$ctrl === void 0 ? void 0 : _task$ctrl.signal, (err, val) => {
|
|
281
314
|
// clean up pending tasks that have not been aborted
|
|
282
|
-
if (queued && !task.ctrl.signal.aborted) _classPrivateFieldGet(
|
|
315
|
+
if (queued && !task.ctrl.signal.aborted) _classPrivateFieldGet(this, _pending).delete(task);
|
|
283
316
|
// update queue state when necessary
|
|
284
317
|
if (task.readyState != null) this.readyState = task.readyState;
|
|
285
318
|
// clean up internal tasks after ending
|
|
286
|
-
if (!this.readyState) _classPrivateFieldSet(
|
|
319
|
+
if (!this.readyState) _classPrivateFieldSet(this, _start, _classPrivateFieldSet(this, _end, null));
|
|
287
320
|
// resolve or reject the deferred task promise
|
|
288
321
|
task[err ? 'reject' : 'resolve'](err ?? val);
|
|
289
322
|
// keep dequeuing when running
|
|
@@ -293,15 +326,15 @@ function _process(task) {
|
|
|
293
326
|
});
|
|
294
327
|
return task;
|
|
295
328
|
}
|
|
296
|
-
async function*
|
|
329
|
+
async function* _until2(task, callback) {
|
|
297
330
|
try {
|
|
298
331
|
yield* yieldFor(() => {
|
|
299
|
-
var
|
|
300
|
-
if ((
|
|
332
|
+
var _classPrivateFieldGet8;
|
|
333
|
+
if ((_classPrivateFieldGet8 = _classPrivateFieldGet(this, _start)) !== null && _classPrivateFieldGet8 !== void 0 && _classPrivateFieldGet8.pending) return false;
|
|
301
334
|
let queued,
|
|
302
|
-
pending = _classPrivateFieldGet(
|
|
335
|
+
pending = _classPrivateFieldGet(this, _pending).size;
|
|
303
336
|
// calculate the position within queued when not pending
|
|
304
|
-
if (task && task.pending == null) queued = positionOf(_classPrivateFieldGet(
|
|
337
|
+
if (task && task.pending == null) queued = positionOf(_classPrivateFieldGet(this, _queued), task);
|
|
305
338
|
// call the callback and return true when not queued or pending
|
|
306
339
|
let position = (queued ?? 0) + pending;
|
|
307
340
|
callback === null || callback === void 0 ? void 0 : callback(position);
|
package/dist/server.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
|
|
2
2
|
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
|
|
3
3
|
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
|
|
4
|
+
function _classPrivateFieldGet2(e, t) { var r = _classPrivateFieldGet(t, e); return _classApplyDescriptorGet(e, r); }
|
|
5
|
+
function _classApplyDescriptorGet(e, t) { return t.get ? t.get.call(e) : t.value; }
|
|
6
|
+
function _classPrivateMethodGet(s, a, r) { return _assertClassBrand(a, s), r; }
|
|
7
|
+
function _classPrivateFieldSet(e, t, r) { var s = _classPrivateFieldGet(t, e); return _classApplyDescriptorSet(e, s, r), r; }
|
|
4
8
|
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
|
|
5
|
-
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
|
|
6
9
|
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
|
10
|
+
function _classApplyDescriptorSet(e, t, l) { if (t.set) t.set.call(e, l);else { if (!t.writable) throw new TypeError("attempted to set read only private field"); t.value = l; } }
|
|
7
11
|
import fs from 'fs';
|
|
8
12
|
import path from 'path';
|
|
9
13
|
import http from 'http';
|
|
@@ -99,7 +103,8 @@ export class ServerError extends Error {
|
|
|
99
103
|
var _sockets = /*#__PURE__*/new WeakMap();
|
|
100
104
|
var _defaultPort = /*#__PURE__*/new WeakMap();
|
|
101
105
|
var _routes = /*#__PURE__*/new WeakMap();
|
|
102
|
-
var
|
|
106
|
+
var _route = /*#__PURE__*/new WeakSet();
|
|
107
|
+
var _handleRequest = /*#__PURE__*/new WeakSet();
|
|
103
108
|
export class Server extends http.Server {
|
|
104
109
|
constructor({
|
|
105
110
|
port
|
|
@@ -108,40 +113,48 @@ export class Server extends http.Server {
|
|
|
108
113
|
IncomingMessage,
|
|
109
114
|
ServerResponse
|
|
110
115
|
});
|
|
111
|
-
|
|
112
|
-
_classPrivateMethodInitSpec(this,
|
|
113
|
-
_classPrivateFieldInitSpec(this, _sockets,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
116
|
+
_classPrivateMethodInitSpec(this, _handleRequest);
|
|
117
|
+
_classPrivateMethodInitSpec(this, _route);
|
|
118
|
+
_classPrivateFieldInitSpec(this, _sockets, {
|
|
119
|
+
writable: true,
|
|
120
|
+
value: new Set()
|
|
121
|
+
});
|
|
122
|
+
_classPrivateFieldInitSpec(this, _defaultPort, {
|
|
123
|
+
writable: true,
|
|
124
|
+
value: void 0
|
|
125
|
+
});
|
|
126
|
+
_classPrivateFieldInitSpec(this, _routes, {
|
|
127
|
+
writable: true,
|
|
128
|
+
value: [{
|
|
129
|
+
priority: -1,
|
|
130
|
+
handle: (req, res, next) => {
|
|
131
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
132
|
+
if (req.method === 'OPTIONS') {
|
|
133
|
+
let allowHeaders = req.headers['access-control-request-headers'] || '*';
|
|
134
|
+
let allowMethods = [...new Set(_classPrivateFieldGet2(this, _routes).flatMap(route => (!route.match || route.match(req.url.pathname)) && route.methods || []))].join(', ');
|
|
135
|
+
res.setHeader('Access-Control-Allow-Headers', allowHeaders);
|
|
136
|
+
res.setHeader('Access-Control-Allow-Methods', allowMethods);
|
|
137
|
+
res.writeHead(204).end();
|
|
138
|
+
} else {
|
|
139
|
+
res.setHeader('Access-Control-Expose-Headers', '*');
|
|
140
|
+
return next();
|
|
141
|
+
}
|
|
129
142
|
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
_classPrivateFieldSet(
|
|
143
|
+
}, {
|
|
144
|
+
priority: 3,
|
|
145
|
+
handle: req => ServerError.throw(404)
|
|
146
|
+
}]
|
|
147
|
+
});
|
|
148
|
+
_classPrivateFieldSet(this, _defaultPort, port);
|
|
136
149
|
|
|
137
150
|
// handle requests on end
|
|
138
151
|
this.on('request', (req, res) => {
|
|
139
|
-
req.on('end', () =>
|
|
152
|
+
req.on('end', () => _classPrivateMethodGet(this, _handleRequest, _handleRequest2).call(this, req, res));
|
|
140
153
|
});
|
|
141
154
|
// track open connections to terminate when the server closes
|
|
142
155
|
this.on('connection', socket => {
|
|
143
|
-
let handleClose = () =>
|
|
144
|
-
|
|
156
|
+
let handleClose = () => _classPrivateFieldGet2(this, _sockets).delete(socket);
|
|
157
|
+
_classPrivateFieldGet2(this, _sockets).add(socket.on('close', handleClose));
|
|
145
158
|
});
|
|
146
159
|
}
|
|
147
160
|
|
|
@@ -153,7 +166,7 @@ export class Server extends http.Server {
|
|
|
153
166
|
// return the listening port or any default port
|
|
154
167
|
get port() {
|
|
155
168
|
var _super$address;
|
|
156
|
-
return ((_super$address = super.address()) === null || _super$address === void 0 ? void 0 : _super$address.port) ??
|
|
169
|
+
return ((_super$address = super.address()) === null || _super$address === void 0 ? void 0 : _super$address.port) ?? _classPrivateFieldGet2(this, _defaultPort);
|
|
157
170
|
}
|
|
158
171
|
|
|
159
172
|
// return a string representation of the server address
|
|
@@ -168,7 +181,7 @@ export class Server extends http.Server {
|
|
|
168
181
|
}
|
|
169
182
|
|
|
170
183
|
// return a promise that resolves when the server is listening
|
|
171
|
-
listen(port =
|
|
184
|
+
listen(port = _classPrivateFieldGet2(this, _defaultPort)) {
|
|
172
185
|
return new Promise((resolve, reject) => {
|
|
173
186
|
let handle = err => off() && err ? reject(err) : resolve(this);
|
|
174
187
|
let off = () => this.off('error', handle).off('listening', handle);
|
|
@@ -179,16 +192,21 @@ export class Server extends http.Server {
|
|
|
179
192
|
// return a promise that resolves when the server closes
|
|
180
193
|
close() {
|
|
181
194
|
return new Promise(resolve => {
|
|
182
|
-
|
|
195
|
+
_classPrivateFieldGet2(this, _sockets).forEach(socket => socket.destroy());
|
|
183
196
|
super.close(resolve);
|
|
184
197
|
});
|
|
185
198
|
}
|
|
199
|
+
|
|
200
|
+
// initial routes include cors and 404 handling
|
|
201
|
+
|
|
202
|
+
// adds a route in the correct priority order
|
|
203
|
+
|
|
186
204
|
// set request routing and handling for pathnames and methods
|
|
187
205
|
route(method, pathname, handle) {
|
|
188
206
|
if (arguments.length === 1) [handle, method] = [method];
|
|
189
207
|
if (arguments.length === 2) [handle, pathname] = [pathname];
|
|
190
208
|
if (arguments.length === 2 && !Array.isArray(method) && method[0] === '/') [pathname, method] = [method];
|
|
191
|
-
return
|
|
209
|
+
return _classPrivateMethodGet(this, _route, _route2).call(this, {
|
|
192
210
|
priority: !pathname ? 0 : !method ? 1 : 2,
|
|
193
211
|
methods: method && [].concat(method).map(m => m.toUpperCase()),
|
|
194
212
|
match: pathname && pathToMatch(pathname),
|
|
@@ -215,7 +233,7 @@ export class Server extends http.Server {
|
|
|
215
233
|
throw new ServerError(400);
|
|
216
234
|
}
|
|
217
235
|
});
|
|
218
|
-
return
|
|
236
|
+
return _classPrivateMethodGet(this, _route, _route2).call(this, {
|
|
219
237
|
priority: 2,
|
|
220
238
|
methods: ['GET'],
|
|
221
239
|
match: pathname => mountPattern.test(pathname),
|
|
@@ -239,12 +257,12 @@ export class Server extends http.Server {
|
|
|
239
257
|
}
|
|
240
258
|
|
|
241
259
|
// create a url rewriter from provided rewrite rules
|
|
242
|
-
function
|
|
243
|
-
let i =
|
|
244
|
-
|
|
260
|
+
function _route2(route) {
|
|
261
|
+
let i = _classPrivateFieldGet2(this, _routes).findIndex(r => r.priority >= route.priority);
|
|
262
|
+
_classPrivateFieldGet2(this, _routes).splice(i, 0, route);
|
|
245
263
|
return this;
|
|
246
264
|
}
|
|
247
|
-
async function
|
|
265
|
+
async function _handleRequest2(req, res) {
|
|
248
266
|
// support node < 15.7.0
|
|
249
267
|
res.req ?? (res.req = req);
|
|
250
268
|
try {
|
|
@@ -260,7 +278,7 @@ async function _handleRequest(req, res) {
|
|
|
260
278
|
result && (result = !match || match(req.url.pathname));
|
|
261
279
|
if (result) req.params = result.params;
|
|
262
280
|
return result ? handle(req, res, next) : next();
|
|
263
|
-
}(
|
|
281
|
+
}(_classPrivateFieldGet2(this, _routes));
|
|
264
282
|
} catch (error) {
|
|
265
283
|
var _req$headers$accept, _req$headers$content;
|
|
266
284
|
let {
|
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/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/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.1-
|
|
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": "
|
|
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.1-
|
|
47
|
-
"@percy/config": "1.29.1-
|
|
48
|
-
"@percy/dom": "1.29.1-
|
|
49
|
-
"@percy/logger": "1.29.1-
|
|
50
|
-
"@percy/webdriver-utils": "1.29.1-
|
|
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": "
|
|
63
|
+
"gitHead": "d325b7bbe56764dbde494477d1f4f3bfdc562d6e"
|
|
64
64
|
}
|