@percy/core 1.28.2-beta.0 → 1.28.2-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/config.js +7 -0
- package/dist/discovery.js +60 -37
- package/dist/network.js +10 -1
- package/dist/percy.js +4 -2
- package/dist/queue.js +7 -1
- package/dist/snapshot.js +2 -1
- package/dist/utils.js +23 -0
- package/package.json +7 -7
package/dist/config.js
CHANGED
|
@@ -255,6 +255,10 @@ export const configSchema = {
|
|
|
255
255
|
type: 'integer',
|
|
256
256
|
minimum: 1
|
|
257
257
|
},
|
|
258
|
+
retry: {
|
|
259
|
+
type: 'boolean',
|
|
260
|
+
default: false
|
|
261
|
+
},
|
|
258
262
|
launchOptions: {
|
|
259
263
|
type: 'object',
|
|
260
264
|
additionalProperties: false,
|
|
@@ -357,6 +361,9 @@ export const snapshotSchema = {
|
|
|
357
361
|
},
|
|
358
362
|
devicePixelRatio: {
|
|
359
363
|
$ref: '/config/discovery#/properties/devicePixelRatio'
|
|
364
|
+
},
|
|
365
|
+
retry: {
|
|
366
|
+
$ref: '/config/discovery#/properties/retry'
|
|
360
367
|
}
|
|
361
368
|
}
|
|
362
369
|
}
|
package/dist/discovery.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logger from '@percy/logger';
|
|
2
2
|
import Queue from './queue.js';
|
|
3
|
-
import { normalizeURL, hostnameMatches, createResource, createRootResource, createPercyCSSResource, createLogResource, yieldAll, snapshotLogName } from './utils.js';
|
|
3
|
+
import { normalizeURL, hostnameMatches, createResource, createRootResource, createPercyCSSResource, createLogResource, yieldAll, snapshotLogName, withRetries } from './utils.js';
|
|
4
4
|
|
|
5
5
|
// Logs verbose debug logs detailing various snapshot options.
|
|
6
6
|
function debugSnapshotOptions(snapshot) {
|
|
@@ -152,6 +152,7 @@ function processSnapshotResources({
|
|
|
152
152
|
// Triggers the capture of resource requests for a page by iterating over snapshot widths to resize
|
|
153
153
|
// the page and calling any provided execute options.
|
|
154
154
|
async function* captureSnapshotResources(page, snapshot, options) {
|
|
155
|
+
const log = logger('core:discovery');
|
|
155
156
|
let {
|
|
156
157
|
discovery,
|
|
157
158
|
additionalSnapshots = [],
|
|
@@ -161,7 +162,8 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
161
162
|
capture,
|
|
162
163
|
captureWidths,
|
|
163
164
|
deviceScaleFactor,
|
|
164
|
-
mobile
|
|
165
|
+
mobile,
|
|
166
|
+
captureForDevices
|
|
165
167
|
} = options;
|
|
166
168
|
|
|
167
169
|
// used to take snapshots and remove any discovered root resource
|
|
@@ -215,6 +217,21 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
215
217
|
} = snap;
|
|
216
218
|
let [width] = widths;
|
|
217
219
|
|
|
220
|
+
// iterate over device to trigger reqeusts and capture other dpr width
|
|
221
|
+
if (captureForDevices) {
|
|
222
|
+
for (const device of captureForDevices) {
|
|
223
|
+
yield waitForDiscoveryNetworkIdle(page, discovery);
|
|
224
|
+
// 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
|
|
225
|
+
yield* captureSnapshotResources(page, {
|
|
226
|
+
...snapshot,
|
|
227
|
+
widths: [device.width]
|
|
228
|
+
}, {
|
|
229
|
+
deviceScaleFactor: device.deviceScaleFactor,
|
|
230
|
+
mobile: true
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
218
235
|
// iterate over widths to trigger reqeusts and capture other widths
|
|
219
236
|
if (isBaseSnapshot || captureWidths) {
|
|
220
237
|
for (let i = 0; i < widths.length - 1; i++) {
|
|
@@ -239,12 +256,8 @@ async function* captureSnapshotResources(page, snapshot, options) {
|
|
|
239
256
|
}
|
|
240
257
|
|
|
241
258
|
// recursively trigger resource requests for any alternate device pixel ratio
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
yield* captureSnapshotResources(page, snapshot, {
|
|
245
|
-
deviceScaleFactor: discovery.devicePixelRatio,
|
|
246
|
-
mobile: true
|
|
247
|
-
});
|
|
259
|
+
if (discovery.devicePixelRatio) {
|
|
260
|
+
log.deprecated('discovery.devicePixelRatio is deprecated percy will now auto capture resource in all devicePixelRatio, Ignoring configuration');
|
|
248
261
|
}
|
|
249
262
|
|
|
250
263
|
// wait for final network idle when not capturing DOM
|
|
@@ -327,39 +340,49 @@ export function createDiscoveryQueue(percy) {
|
|
|
327
340
|
/* istanbul ignore next: tested, but coverage is stripped */
|
|
328
341
|
let assetDiscoveryPageEnableJS = snapshot.cliEnableJavaScript && !snapshot.domSnapshot || (snapshot.enableJavaScript ?? !snapshot.domSnapshot);
|
|
329
342
|
percy.log.debug(`Asset discovery Browser Page enable JS: ${assetDiscoveryPageEnableJS}`);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
await withRetries(async function* () {
|
|
344
|
+
// create a new browser page
|
|
345
|
+
let page = yield percy.browser.page({
|
|
346
|
+
enableJavaScript: assetDiscoveryPageEnableJS,
|
|
347
|
+
networkIdleTimeout: snapshot.discovery.networkIdleTimeout,
|
|
348
|
+
requestHeaders: snapshot.discovery.requestHeaders,
|
|
349
|
+
authorization: snapshot.discovery.authorization,
|
|
350
|
+
userAgent: snapshot.discovery.userAgent,
|
|
351
|
+
captureMockedServiceWorker: snapshot.discovery.captureMockedServiceWorker,
|
|
352
|
+
meta: snapshot.meta,
|
|
353
|
+
// enable network inteception
|
|
354
|
+
intercept: {
|
|
355
|
+
enableJavaScript: snapshot.enableJavaScript,
|
|
356
|
+
disableCache: snapshot.discovery.disableCache,
|
|
357
|
+
allowedHostnames: snapshot.discovery.allowedHostnames,
|
|
358
|
+
disallowedHostnames: snapshot.discovery.disallowedHostnames,
|
|
359
|
+
getResource: u => snapshot.resources.get(u) || cache.get(u),
|
|
360
|
+
saveResource: r => {
|
|
361
|
+
snapshot.resources.set(r.url, r);
|
|
362
|
+
if (!r.root) {
|
|
363
|
+
cache.set(r.url, r);
|
|
364
|
+
}
|
|
350
365
|
}
|
|
351
366
|
}
|
|
367
|
+
});
|
|
368
|
+
try {
|
|
369
|
+
yield* captureSnapshotResources(page, snapshot, {
|
|
370
|
+
captureWidths: !snapshot.domSnapshot && percy.deferUploads,
|
|
371
|
+
capture: callback,
|
|
372
|
+
captureForDevices: percy.deviceDetails || []
|
|
373
|
+
});
|
|
374
|
+
} finally {
|
|
375
|
+
// always close the page when done
|
|
376
|
+
await page.close();
|
|
352
377
|
}
|
|
378
|
+
}, {
|
|
379
|
+
count: snapshot.discovery.retry ? 3 : 1,
|
|
380
|
+
onRetry: () => {
|
|
381
|
+
percy.log.info(`Retrying snapshot: ${snapshotLogName(snapshot.name, snapshot.meta)}`, snapshot.meta);
|
|
382
|
+
},
|
|
383
|
+
signal: snapshot._ctrl.signal,
|
|
384
|
+
throwOn: ['AbortError']
|
|
353
385
|
});
|
|
354
|
-
try {
|
|
355
|
-
yield* captureSnapshotResources(page, snapshot, {
|
|
356
|
-
captureWidths: !snapshot.domSnapshot && percy.deferUploads,
|
|
357
|
-
capture: callback
|
|
358
|
-
});
|
|
359
|
-
} finally {
|
|
360
|
-
// always close the page when done
|
|
361
|
-
await page.close();
|
|
362
|
-
}
|
|
363
386
|
}).handle('error', ({
|
|
364
387
|
name,
|
|
365
388
|
meta
|
package/dist/network.js
CHANGED
|
@@ -28,6 +28,7 @@ export class Network {
|
|
|
28
28
|
#requests = new Map();
|
|
29
29
|
#authentications = new Set();
|
|
30
30
|
#aborted = new Set();
|
|
31
|
+
#finishedUrls = new Set();
|
|
31
32
|
constructor(page, options) {
|
|
32
33
|
this.page = page;
|
|
33
34
|
this.timeout = options.networkIdleTimeout ?? 100;
|
|
@@ -78,6 +79,12 @@ export class Network {
|
|
|
78
79
|
throw new Error(`Network error: ${this.page.session.closedReason}`);
|
|
79
80
|
}
|
|
80
81
|
requests = Array.from(this.#requests.values()).filter(filter);
|
|
82
|
+
// remove requests which are finished at least once
|
|
83
|
+
// this happens when same request is made multiple times by browser in parallel and one of
|
|
84
|
+
// them gets stuck in pending state in browser [ need to debug why ]. So we dont receive
|
|
85
|
+
// loadingFinished event, causing it to show up in Active requests, but we can only store one
|
|
86
|
+
// response per url so as long as we have captured one, we dont care about other such requests
|
|
87
|
+
requests = requests.filter(req => !this.#finishedUrls.has(req.url));
|
|
81
88
|
return requests.length === 0;
|
|
82
89
|
}, {
|
|
83
90
|
timeout: Network.TIMEOUT,
|
|
@@ -120,10 +127,12 @@ export class Network {
|
|
|
120
127
|
// Called when a request should be removed from various trackers
|
|
121
128
|
_forgetRequest({
|
|
122
129
|
requestId,
|
|
123
|
-
interceptId
|
|
130
|
+
interceptId,
|
|
131
|
+
url
|
|
124
132
|
}, keepPending) {
|
|
125
133
|
this.#requests.delete(requestId);
|
|
126
134
|
this.#authentications.delete(interceptId);
|
|
135
|
+
this.#finishedUrls.add(url);
|
|
127
136
|
if (!keepPending) {
|
|
128
137
|
this.#pending.delete(requestId);
|
|
129
138
|
}
|
package/dist/percy.js
CHANGED
|
@@ -145,12 +145,14 @@ export class Percy {
|
|
|
145
145
|
if (this.readyState != null) return;
|
|
146
146
|
this.readyState = 0;
|
|
147
147
|
try {
|
|
148
|
+
var _this$build;
|
|
148
149
|
// start the snapshots queue immediately when not delayed or deferred
|
|
149
150
|
if (!this.delayUploads && !this.deferUploads) yield this.#snapshots.start();
|
|
150
151
|
// do not start the discovery queue when not needed
|
|
151
152
|
if (!this.skipDiscovery) yield this.#discovery.start();
|
|
152
153
|
// start a local API server for SDK communication
|
|
153
154
|
if (this.server) yield this.server.listen();
|
|
155
|
+
if (this.projectType === 'web') this.deviceDetails = yield this.client.getDeviceDetails((_this$build = this.build) === null || _this$build === void 0 ? void 0 : _this$build.id);
|
|
154
156
|
const snapshotType = this.projectType === 'web' ? 'snapshot' : 'comparison';
|
|
155
157
|
this.syncQueue = new WaitForJob(snapshotType, this);
|
|
156
158
|
// log and mark this instance as started
|
|
@@ -258,10 +260,10 @@ export class Percy {
|
|
|
258
260
|
// snapshots. Once asset discovery has completed for the provided snapshots, the queued task will
|
|
259
261
|
// resolve and an upload task will be queued separately.
|
|
260
262
|
snapshot(options, snapshotPromise = {}) {
|
|
261
|
-
var _this$
|
|
263
|
+
var _this$build2;
|
|
262
264
|
if (this.readyState !== 1) {
|
|
263
265
|
throw new Error('Not running');
|
|
264
|
-
} else if ((_this$
|
|
266
|
+
} else if ((_this$build2 = this.build) !== null && _this$build2 !== void 0 && _this$build2.error) {
|
|
265
267
|
throw new Error(this.build.error);
|
|
266
268
|
} else if (Array.isArray(options)) {
|
|
267
269
|
return yieldAll(options.map(o => this.yield.snapshot(o, snapshotPromise)));
|
package/dist/queue.js
CHANGED
|
@@ -122,9 +122,15 @@ export class Queue {
|
|
|
122
122
|
|
|
123
123
|
// call or set up other handlers
|
|
124
124
|
let exists = this.cancel(item);
|
|
125
|
+
task.ctrl = new AbortController();
|
|
126
|
+
// duplicate abortion controller on task, so it can can be used in further
|
|
127
|
+
// generators and can be cancelled internally
|
|
128
|
+
// TODO fix this for non object item usecase
|
|
129
|
+
if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
|
|
130
|
+
item._ctrl = task.ctrl;
|
|
131
|
+
}
|
|
125
132
|
task.item = item = _classPrivateFieldGet(this, _handlers).push ? _classPrivateFieldGet(this, _handlers).push(item, exists) : item;
|
|
126
133
|
task.handler = () => _classPrivateFieldGet(this, _handlers).task ? _classPrivateFieldGet(this, _handlers).task(item, ...args) : item;
|
|
127
|
-
task.ctrl = new AbortController();
|
|
128
134
|
|
|
129
135
|
// queue this task & maybe dequeue the next task
|
|
130
136
|
_classPrivateFieldGet(this, _queued).add(task);
|
package/dist/snapshot.js
CHANGED
|
@@ -129,7 +129,8 @@ function getSnapshotOptions(options, {
|
|
|
129
129
|
disableCache: config.discovery.disableCache,
|
|
130
130
|
captureMockedServiceWorker: config.discovery.captureMockedServiceWorker,
|
|
131
131
|
captureSrcset: config.discovery.captureSrcset,
|
|
132
|
-
userAgent: config.discovery.userAgent
|
|
132
|
+
userAgent: config.discovery.userAgent,
|
|
133
|
+
retry: config.discovery.retry
|
|
133
134
|
}
|
|
134
135
|
}, options], (path, prev, next) => {
|
|
135
136
|
var _next, _next2;
|
package/dist/utils.js
CHANGED
|
@@ -328,6 +328,29 @@ export function serializeFunction(fn) {
|
|
|
328
328
|
}
|
|
329
329
|
return fnbody;
|
|
330
330
|
}
|
|
331
|
+
export async function withRetries(fn, {
|
|
332
|
+
count,
|
|
333
|
+
onRetry,
|
|
334
|
+
signal,
|
|
335
|
+
throwOn
|
|
336
|
+
}) {
|
|
337
|
+
count || (count = 1); // default a single try
|
|
338
|
+
let run = 0;
|
|
339
|
+
while (true) {
|
|
340
|
+
run += 1;
|
|
341
|
+
try {
|
|
342
|
+
return await generatePromise(fn, signal);
|
|
343
|
+
} catch (e) {
|
|
344
|
+
// if this error should not be retried on, we want to skip errors
|
|
345
|
+
let throwError = throwOn === null || throwOn === void 0 ? void 0 : throwOn.includes(e.name);
|
|
346
|
+
if (!throwError && run < count) {
|
|
347
|
+
await (onRetry === null || onRetry === void 0 ? void 0 : onRetry());
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
throw e;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
331
354
|
export function snapshotLogName(name, meta) {
|
|
332
355
|
var _meta$snapshot;
|
|
333
356
|
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.28.2-beta.
|
|
3
|
+
"version": "1.28.2-beta.2",
|
|
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.28.2-beta.
|
|
47
|
-
"@percy/config": "1.28.2-beta.
|
|
48
|
-
"@percy/dom": "1.28.2-beta.
|
|
49
|
-
"@percy/logger": "1.28.2-beta.
|
|
50
|
-
"@percy/webdriver-utils": "1.28.2-beta.
|
|
46
|
+
"@percy/client": "1.28.2-beta.2",
|
|
47
|
+
"@percy/config": "1.28.2-beta.2",
|
|
48
|
+
"@percy/dom": "1.28.2-beta.2",
|
|
49
|
+
"@percy/logger": "1.28.2-beta.2",
|
|
50
|
+
"@percy/webdriver-utils": "1.28.2-beta.2",
|
|
51
51
|
"content-disposition": "^0.5.4",
|
|
52
52
|
"cross-spawn": "^7.0.3",
|
|
53
53
|
"extract-zip": "^2.0.1",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"rimraf": "^3.0.2",
|
|
59
59
|
"ws": "^8.0.0"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "7c2bdccd896be9da7d07dd30ead802fbb4ca9fab"
|
|
62
62
|
}
|