@percy/core 1.0.0-beta.9 → 1.0.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/README.md +226 -67
- package/package.json +43 -29
- package/dist/config.js +0 -69
- package/dist/discoverer.js +0 -367
- package/dist/index.js +0 -29
- package/dist/percy-css.js +0 -33
- package/dist/percy.js +0 -428
- package/dist/queue.js +0 -103
- package/dist/server.js +0 -82
- package/dist/utils/assert.js +0 -50
- package/dist/utils/bytes.js +0 -24
- package/dist/utils/idle.js +0 -20
- package/dist/utils/install-browser.js +0 -76
- package/dist/utils/resources.js +0 -75
- package/dist/utils/url.js +0 -64
- package/types/index.d.ts +0 -71
package/dist/percy.js
DELETED
|
@@ -1,428 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _client = _interopRequireDefault(require("@percy/client"));
|
|
9
|
-
|
|
10
|
-
var _config = _interopRequireDefault(require("@percy/config"));
|
|
11
|
-
|
|
12
|
-
var _logger = _interopRequireDefault(require("@percy/logger"));
|
|
13
|
-
|
|
14
|
-
var _config2 = require("./config");
|
|
15
|
-
|
|
16
|
-
var _discoverer = _interopRequireDefault(require("./discoverer"));
|
|
17
|
-
|
|
18
|
-
var _percyCss = _interopRequireDefault(require("./percy-css"));
|
|
19
|
-
|
|
20
|
-
var _server = require("./server");
|
|
21
|
-
|
|
22
|
-
var _queue = _interopRequireDefault(require("./queue"));
|
|
23
|
-
|
|
24
|
-
var _assert = _interopRequireDefault(require("./utils/assert"));
|
|
25
|
-
|
|
26
|
-
var _resources = require("./utils/resources");
|
|
27
|
-
|
|
28
|
-
var _url = require("./utils/url");
|
|
29
|
-
|
|
30
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
31
|
-
|
|
32
|
-
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
33
|
-
|
|
34
|
-
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; }
|
|
35
|
-
|
|
36
|
-
// Register core config options
|
|
37
|
-
_config.default.addSchema(_config2.schema); // A Percy instance will create a new build when started, handle snapshot
|
|
38
|
-
// creation, asset discovery, and resource uploads, and will finalize the build
|
|
39
|
-
// when stopped. Snapshots are processed concurrently and the build is not
|
|
40
|
-
// finalized until all snapshots have been handled.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
var _captures = new WeakMap();
|
|
44
|
-
|
|
45
|
-
var _snapshots = new WeakMap();
|
|
46
|
-
|
|
47
|
-
var _stopping = new WeakMap();
|
|
48
|
-
|
|
49
|
-
var _running = new WeakMap();
|
|
50
|
-
|
|
51
|
-
class Percy {
|
|
52
|
-
// Static shortcut to create and start an instance in one call
|
|
53
|
-
static async start(options) {
|
|
54
|
-
let instance = new this(options);
|
|
55
|
-
await instance.start();
|
|
56
|
-
return instance;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
constructor({
|
|
60
|
-
// provided to @percy/client
|
|
61
|
-
token,
|
|
62
|
-
clientInfo = '',
|
|
63
|
-
environmentInfo = '',
|
|
64
|
-
// snapshot server options
|
|
65
|
-
server = true,
|
|
66
|
-
port = 5338,
|
|
67
|
-
// capture concurrency
|
|
68
|
-
concurrency = 5,
|
|
69
|
-
// initial log level
|
|
70
|
-
loglevel,
|
|
71
|
-
// configuration filepath
|
|
72
|
-
config,
|
|
73
|
-
// options such as `snapshot` and `discovery` that are valid Percy config
|
|
74
|
-
// options which will become accessible via the `#config` property
|
|
75
|
-
...options
|
|
76
|
-
} = {}) {
|
|
77
|
-
_captures.set(this, {
|
|
78
|
-
writable: true,
|
|
79
|
-
value: null
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
_snapshots.set(this, {
|
|
83
|
-
writable: true,
|
|
84
|
-
value: null
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
_stopping.set(this, {
|
|
88
|
-
writable: true,
|
|
89
|
-
value: false
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
_running.set(this, {
|
|
93
|
-
writable: true,
|
|
94
|
-
value: false
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
if (loglevel) {
|
|
98
|
-
this.loglevel(loglevel);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (server) {
|
|
102
|
-
this.port = port;
|
|
103
|
-
this.app = (0, _server.createServerApp)(this);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
_classPrivateFieldSet(this, _snapshots, new _queue.default());
|
|
107
|
-
|
|
108
|
-
_classPrivateFieldSet(this, _captures, new _queue.default(concurrency));
|
|
109
|
-
|
|
110
|
-
this.config = config === false ? _config.default.getDefaults(options) : _config.default.load({
|
|
111
|
-
path: config,
|
|
112
|
-
overrides: options
|
|
113
|
-
});
|
|
114
|
-
this.discoverer = new _discoverer.default(this.config.discovery);
|
|
115
|
-
this.client = new _client.default({
|
|
116
|
-
token,
|
|
117
|
-
clientInfo,
|
|
118
|
-
environmentInfo
|
|
119
|
-
});
|
|
120
|
-
} // Shortcut for controlling the global logger's log level.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
loglevel(level) {
|
|
124
|
-
return _logger.default.loglevel(level);
|
|
125
|
-
} // Snapshot server API address
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
apiAddress() {
|
|
129
|
-
var _this$server, _address;
|
|
130
|
-
|
|
131
|
-
let {
|
|
132
|
-
address
|
|
133
|
-
} = ((_this$server = this.server) === null || _this$server === void 0 ? void 0 : _this$server.address()) || {};
|
|
134
|
-
address = ((_address = address) === null || _address === void 0 ? void 0 : _address.includes(':')) ? `[${address}]` : address;
|
|
135
|
-
return address && `http://${address}:${this.port}/percy`;
|
|
136
|
-
} // Returns a boolean indicating if this instance is running.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
isRunning() {
|
|
140
|
-
return _classPrivateFieldGet(this, _running);
|
|
141
|
-
} // Starts the local API server, the asset discovery process, and creates a new
|
|
142
|
-
// Percy build. When an error is encountered, the discoverer and server are closed.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
async start() {
|
|
146
|
-
// throws when the token is missing
|
|
147
|
-
this.client.getToken();
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
// if there is an exress app, a server should be started
|
|
151
|
-
if (this.app) {
|
|
152
|
-
this.server = await (0, _server.startServer)(this.app, this.port);
|
|
153
|
-
} // launch the discoverer browser and create a percy build
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
await this.discoverer.launch();
|
|
157
|
-
await this.client.createBuild(); // log build details
|
|
158
|
-
|
|
159
|
-
let build = this.client.build;
|
|
160
|
-
let meta = {
|
|
161
|
-
build: {
|
|
162
|
-
id: build.id
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
_logger.default.info('Percy has started!', meta);
|
|
167
|
-
|
|
168
|
-
_logger.default.info(`Created build #${build.number}: ${build.url}`, meta); // mark this process as running
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
_classPrivateFieldSet(this, _running, true);
|
|
172
|
-
} catch (error) {
|
|
173
|
-
var _this$server2;
|
|
174
|
-
|
|
175
|
-
// on error, close any running browser or server
|
|
176
|
-
await this.discoverer.close();
|
|
177
|
-
(_this$server2 = this.server) === null || _this$server2 === void 0 ? void 0 : _this$server2.close(); // throw an easier-to understand error when the port is taken
|
|
178
|
-
|
|
179
|
-
if (error.code === 'EADDRINUSE') {
|
|
180
|
-
throw new Error('Percy is already running or the port is in use');
|
|
181
|
-
} else {
|
|
182
|
-
throw error;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
} // Stops the local API server and discoverer once snapshots have completed and
|
|
186
|
-
// finalizes the Percy build. Does nothing if not running.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
async stop() {
|
|
190
|
-
// do nothing if not running or already stopping
|
|
191
|
-
if (this.isRunning() && !_classPrivateFieldGet(this, _stopping)) {
|
|
192
|
-
var _this$server3;
|
|
193
|
-
|
|
194
|
-
_classPrivateFieldSet(this, _stopping, true);
|
|
195
|
-
|
|
196
|
-
let build = this.client.build;
|
|
197
|
-
let meta = {
|
|
198
|
-
build: {
|
|
199
|
-
id: build.id
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
_logger.default.info('Stopping percy...', meta); // log about queued captures or uploads
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (_classPrivateFieldGet(this, _captures).length) {
|
|
207
|
-
_logger.default.info(`Waiting for ${_classPrivateFieldGet(this, _captures).length} page(s) to finish snapshotting`, meta);
|
|
208
|
-
} else if (_classPrivateFieldGet(this, _snapshots).length) {
|
|
209
|
-
_logger.default.info(`Waiting for ${_classPrivateFieldGet(this, _snapshots).length} snapshot(s) to finish uploading`, meta);
|
|
210
|
-
} // wait for any queued captures or snapshots
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
await this.idle(); // close the server and browser
|
|
214
|
-
|
|
215
|
-
(_this$server3 = this.server) === null || _this$server3 === void 0 ? void 0 : _this$server3.close();
|
|
216
|
-
await this.discoverer.close();
|
|
217
|
-
|
|
218
|
-
_classPrivateFieldSet(this, _running, false); // log build info
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
await this.client.finalizeBuild();
|
|
222
|
-
|
|
223
|
-
_logger.default.info(`Finalized build #${build.number}: ${build.url}`, meta);
|
|
224
|
-
|
|
225
|
-
_logger.default.info('Done!');
|
|
226
|
-
}
|
|
227
|
-
} // Resolves when captures and snapshots are idle.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
async idle() {
|
|
231
|
-
await Promise.all([_classPrivateFieldGet(this, _captures).idle(), _classPrivateFieldGet(this, _snapshots).idle()]);
|
|
232
|
-
} // Handles asset discovery for the URL and DOM snapshot at each requested
|
|
233
|
-
// width with the provided options. Resolves when the snapshot has been taken
|
|
234
|
-
// and asset discovery is finished, but does not gaurantee that the snapshot
|
|
235
|
-
// will be succesfully uploaded.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
snapshot({
|
|
239
|
-
url,
|
|
240
|
-
name,
|
|
241
|
-
domSnapshot,
|
|
242
|
-
widths,
|
|
243
|
-
minHeight,
|
|
244
|
-
percyCSS,
|
|
245
|
-
requestHeaders,
|
|
246
|
-
enableJavaScript,
|
|
247
|
-
clientInfo,
|
|
248
|
-
environmentInfo
|
|
249
|
-
}) {
|
|
250
|
-
var _widths, _widths2, _minHeight, _ref, _enableJavaScript;
|
|
251
|
-
|
|
252
|
-
// required assertions
|
|
253
|
-
(0, _assert.default)(this.isRunning(), 'Not running');
|
|
254
|
-
(0, _assert.default)(url, 'Missing required argument: url');
|
|
255
|
-
(0, _assert.default)(name, 'Missing required argument: name');
|
|
256
|
-
(0, _assert.default)(domSnapshot, 'Missing required argument: domSnapshot'); // fallback to instance snapshot widths
|
|
257
|
-
|
|
258
|
-
widths = ((_widths = widths) === null || _widths === void 0 ? void 0 : _widths.length) ? widths : this.config.snapshot.widths;
|
|
259
|
-
(0, _assert.default)((_widths2 = widths) === null || _widths2 === void 0 ? void 0 : _widths2.length, 'Missing required argument: widths');
|
|
260
|
-
(0, _assert.default)(widths.length <= 10, 'too many widths'); // normalize the URL
|
|
261
|
-
|
|
262
|
-
url = (0, _url.normalizeURL)(url); // fallback to instance minimum height
|
|
263
|
-
|
|
264
|
-
minHeight = (_minHeight = minHeight) !== null && _minHeight !== void 0 ? _minHeight : this.config.snapshot.minHeight; // combine snapshot Percy CSS with instance Percy CSS
|
|
265
|
-
|
|
266
|
-
percyCSS = [this.config.snapshot.percyCSS, percyCSS].filter(Boolean).join('\n'); // combine snapshot request headers with instance request headers
|
|
267
|
-
|
|
268
|
-
requestHeaders = { ...this.config.snapshot.requestHeaders,
|
|
269
|
-
...requestHeaders
|
|
270
|
-
}; // fallback to instance enable JS flag
|
|
271
|
-
|
|
272
|
-
enableJavaScript = (_ref = (_enableJavaScript = enableJavaScript) !== null && _enableJavaScript !== void 0 ? _enableJavaScript : this.config.snapshot.enableJavaScript) !== null && _ref !== void 0 ? _ref : false; // useful meta info for the logfile
|
|
273
|
-
|
|
274
|
-
let meta = {
|
|
275
|
-
snapshot: {
|
|
276
|
-
name
|
|
277
|
-
},
|
|
278
|
-
build: {
|
|
279
|
-
id: this.client.build.id
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
_logger.default.debug('---------');
|
|
284
|
-
|
|
285
|
-
_logger.default.debug('Handling snapshot:', meta);
|
|
286
|
-
|
|
287
|
-
_logger.default.debug(`-> name: ${name}`, meta);
|
|
288
|
-
|
|
289
|
-
_logger.default.debug(`-> url: ${url}`, meta);
|
|
290
|
-
|
|
291
|
-
_logger.default.debug(`-> widths: ${widths.join('px, ')}px`, meta);
|
|
292
|
-
|
|
293
|
-
_logger.default.debug(`-> clientInfo: ${clientInfo}`, meta);
|
|
294
|
-
|
|
295
|
-
_logger.default.debug(`-> environmentInfo: ${environmentInfo}`, meta);
|
|
296
|
-
|
|
297
|
-
_logger.default.debug(`-> requestHeaders: ${JSON.stringify(requestHeaders)}`, meta);
|
|
298
|
-
|
|
299
|
-
_logger.default.debug(`-> domSnapshot:\n${domSnapshot.length <= 1024 ? domSnapshot : domSnapshot.substr(0, 1024) + '... [truncated]'}`, meta); // use a promise as a try-catch so we can do the remaining work
|
|
300
|
-
// asynchronously, but perform the above synchronously
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
return Promise.resolve().then(async () => {
|
|
304
|
-
// inject Percy CSS
|
|
305
|
-
let [percyDOM, percyCSSResource] = (0, _percyCss.default)(url, domSnapshot, percyCSS, meta); // use a map so resources remain unique by url
|
|
306
|
-
|
|
307
|
-
let resources = new Map([[url, (0, _resources.createRootResource)(url, percyDOM)]]); // include the Percy CSS resource if there was one
|
|
308
|
-
|
|
309
|
-
if (percyCSSResource) resources.set('percy-css', percyCSSResource); // gather resources at each width concurrently
|
|
310
|
-
|
|
311
|
-
await Promise.all(widths.map(width => this.discoverer.gatherResources(resources, {
|
|
312
|
-
rootUrl: url,
|
|
313
|
-
rootDom: domSnapshot,
|
|
314
|
-
enableJavaScript,
|
|
315
|
-
requestHeaders,
|
|
316
|
-
width,
|
|
317
|
-
meta
|
|
318
|
-
}))); // include a log resource for debugging
|
|
319
|
-
|
|
320
|
-
let logs = await _logger.default.query({
|
|
321
|
-
filter: ({
|
|
322
|
-
snapshot: s
|
|
323
|
-
}) => (s === null || s === void 0 ? void 0 : s.name) === name
|
|
324
|
-
});
|
|
325
|
-
resources.set('percy-logs', (0, _resources.createLogResource)(logs)); // log that the snapshot has been taken before uploading it
|
|
326
|
-
|
|
327
|
-
_logger.default.info(`Snapshot taken: ${name}`, meta); // upload within the async snapshot queue
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
_classPrivateFieldGet(this, _snapshots).push(() => this.client.sendSnapshot({
|
|
331
|
-
name,
|
|
332
|
-
widths,
|
|
333
|
-
minHeight,
|
|
334
|
-
enableJavaScript,
|
|
335
|
-
clientInfo,
|
|
336
|
-
environmentInfo,
|
|
337
|
-
resources: Array.from(resources.values())
|
|
338
|
-
}).catch(error => {
|
|
339
|
-
_logger.default.error(`Encountered an error uploading snapshot: ${name}`, meta);
|
|
340
|
-
|
|
341
|
-
_logger.default.error(error);
|
|
342
|
-
}));
|
|
343
|
-
}).catch(error => {
|
|
344
|
-
_logger.default.error(`Encountered an error taking snapshot: ${name}`, meta);
|
|
345
|
-
|
|
346
|
-
_logger.default.error(error);
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
capture({
|
|
351
|
-
url,
|
|
352
|
-
name,
|
|
353
|
-
waitFor,
|
|
354
|
-
execute,
|
|
355
|
-
snapshots = [],
|
|
356
|
-
...options
|
|
357
|
-
}) {
|
|
358
|
-
(0, _assert.default)(this.isRunning(), 'Not running');
|
|
359
|
-
(0, _assert.default)(url, `Missing URL for${name ? ` ${name}` : ' snapshots'}`);
|
|
360
|
-
snapshots = name ? [{
|
|
361
|
-
name,
|
|
362
|
-
execute
|
|
363
|
-
}].concat(snapshots) : snapshots;
|
|
364
|
-
(0, _assert.default)(snapshots.length && snapshots.every(s => s.name), `Missing name for ${url}`); // the entire capture process happens within the async capture queue
|
|
365
|
-
|
|
366
|
-
return _classPrivateFieldGet(this, _captures).push(async () => {
|
|
367
|
-
let results = [];
|
|
368
|
-
let page;
|
|
369
|
-
|
|
370
|
-
try {
|
|
371
|
-
// borrow a page from the discoverer
|
|
372
|
-
page = await this.discoverer.page(); // allow @percy/dom injection
|
|
373
|
-
|
|
374
|
-
await page.setBypassCSP(true); // set any request headers
|
|
375
|
-
|
|
376
|
-
await page.setExtraHTTPHeaders(options.requestHeaders || {}); // @todo - resize viewport
|
|
377
|
-
// go to and wait for network idle
|
|
378
|
-
|
|
379
|
-
await page.goto(url, {
|
|
380
|
-
waitUntil: 'networkidle2'
|
|
381
|
-
}); // inject @percy/dom for serialization
|
|
382
|
-
|
|
383
|
-
await page.addScriptTag({
|
|
384
|
-
path: require.resolve('@percy/dom')
|
|
385
|
-
}); // wait for any other elements or timeout before snapshotting
|
|
386
|
-
|
|
387
|
-
if (waitFor) await page.waitFor(waitFor); // multiple snapshots can be captured on a single page
|
|
388
|
-
|
|
389
|
-
for (let {
|
|
390
|
-
name,
|
|
391
|
-
execute
|
|
392
|
-
} of snapshots) {
|
|
393
|
-
// optionally execute a script to interact with the page
|
|
394
|
-
if (execute) await execute(page); // serialize and capture a DOM snapshot
|
|
395
|
-
|
|
396
|
-
/* istanbul ignore next: no instrumenting injected code */
|
|
397
|
-
|
|
398
|
-
let domSnapshot = await page.evaluate(({
|
|
399
|
-
enableJavaScript
|
|
400
|
-
}) =>
|
|
401
|
-
/* eslint-disable-next-line no-undef */
|
|
402
|
-
PercyDOM.serialize({
|
|
403
|
-
enableJavaScript
|
|
404
|
-
}), options); // snapshots are awaited on concurrently after sequentially capturing their DOM
|
|
405
|
-
|
|
406
|
-
results.push(this.snapshot({ ...options,
|
|
407
|
-
url,
|
|
408
|
-
name,
|
|
409
|
-
domSnapshot
|
|
410
|
-
}));
|
|
411
|
-
}
|
|
412
|
-
} catch (error) {
|
|
413
|
-
_logger.default.error(`Encountered an error for page: ${url}`);
|
|
414
|
-
|
|
415
|
-
_logger.default.error(error);
|
|
416
|
-
} finally {
|
|
417
|
-
var _page;
|
|
418
|
-
|
|
419
|
-
// await on any resulting snapshots
|
|
420
|
-
await Promise.all(results);
|
|
421
|
-
await ((_page = page) === null || _page === void 0 ? void 0 : _page.close());
|
|
422
|
-
}
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
exports.default = Percy;
|
package/dist/queue.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _idle = _interopRequireDefault(require("./utils/idle"));
|
|
9
|
-
|
|
10
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
-
|
|
12
|
-
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; }
|
|
13
|
-
|
|
14
|
-
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
15
|
-
|
|
16
|
-
var _queue = new WeakMap();
|
|
17
|
-
|
|
18
|
-
var _pending = new WeakMap();
|
|
19
|
-
|
|
20
|
-
// Concurrent task-based queue for handling snapshots and asset discovery.
|
|
21
|
-
class Queue {
|
|
22
|
-
// Defaults to inifinite concurrency
|
|
23
|
-
constructor(concurrency = Infinity) {
|
|
24
|
-
_queue.set(this, {
|
|
25
|
-
writable: true,
|
|
26
|
-
value: []
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
_pending.set(this, {
|
|
30
|
-
writable: true,
|
|
31
|
-
value: 0
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
this.concurrency = concurrency;
|
|
35
|
-
} // Pushing a new task to the queue will attempt to run it unless the
|
|
36
|
-
// concurrency limit has been reached. The returned promise will resolve or
|
|
37
|
-
// reject when the task has succeeded or thrown an error.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
push(task) {
|
|
41
|
-
return new Promise((resolve, reject) => {
|
|
42
|
-
_classPrivateFieldGet(this, _queue).push({
|
|
43
|
-
task,
|
|
44
|
-
resolve,
|
|
45
|
-
reject
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
this._dequeue();
|
|
49
|
-
});
|
|
50
|
-
} // Returns the amount of queued and pending tasks.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
get length() {
|
|
54
|
-
return _classPrivateFieldGet(this, _queue).length + _classPrivateFieldGet(this, _pending);
|
|
55
|
-
} // Resolves when there are no more queued or pending tasks.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
idle() {
|
|
59
|
-
return (0, _idle.default)(() => this.length);
|
|
60
|
-
} // Clears the active queue. Tasks that were queued will not be executed and
|
|
61
|
-
// tasks that are pending (have already executed) will be allowed to finish.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
clear() {
|
|
65
|
-
_classPrivateFieldSet(this, _queue, []);
|
|
66
|
-
|
|
67
|
-
return this.length;
|
|
68
|
-
} // Begins processing the queue by running the oldest task first. Pending tasks
|
|
69
|
-
// are tracked and no tasks will run unless there are less pending than the
|
|
70
|
-
// concurrency limit. More tasks are dequeued when the current task
|
|
71
|
-
// finishes. Resolves when the current task finishes although this method
|
|
72
|
-
// should never be awaited on so multiple tasks can run concurrently.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
async _dequeue() {
|
|
76
|
-
var _this$pending;
|
|
77
|
-
|
|
78
|
-
if (_classPrivateFieldGet(this, _pending) >= this.concurrency) return;
|
|
79
|
-
|
|
80
|
-
let item = _classPrivateFieldGet(this, _queue).shift();
|
|
81
|
-
|
|
82
|
-
if (!item) return;
|
|
83
|
-
_classPrivateFieldSet(this, _pending, (_this$pending = +_classPrivateFieldGet(this, _pending)) + 1), _this$pending;
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
var _this$pending2;
|
|
87
|
-
|
|
88
|
-
let value = await item.task();
|
|
89
|
-
_classPrivateFieldSet(this, _pending, (_this$pending2 = +_classPrivateFieldGet(this, _pending)) - 1), _this$pending2;
|
|
90
|
-
item.resolve(value);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
var _this$pending3;
|
|
93
|
-
|
|
94
|
-
_classPrivateFieldSet(this, _pending, (_this$pending3 = +_classPrivateFieldGet(this, _pending)) - 1), _this$pending3;
|
|
95
|
-
item.reject(error);
|
|
96
|
-
} finally {
|
|
97
|
-
this._dequeue();
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
exports.default = Queue;
|
package/dist/server.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.createServerApp = createServerApp;
|
|
7
|
-
exports.startServer = startServer;
|
|
8
|
-
|
|
9
|
-
// Handles async routes with a middleware pattern to catch and forward errors
|
|
10
|
-
function asyncRoute(handler) {
|
|
11
|
-
return (req, res, next) => handler(req, res, next).catch(next);
|
|
12
|
-
} // Lazily creates and returns an express app for communicating with the Percy
|
|
13
|
-
// instance using a local API
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
function createServerApp(percy) {
|
|
17
|
-
// lazily required to speed up imports when the server is not needed
|
|
18
|
-
let express = require('express');
|
|
19
|
-
|
|
20
|
-
let cors = require('cors');
|
|
21
|
-
|
|
22
|
-
let bodyParser = require('body-parser');
|
|
23
|
-
|
|
24
|
-
return express().use(cors()).use(bodyParser.urlencoded({
|
|
25
|
-
extended: true
|
|
26
|
-
})).use(bodyParser.json({
|
|
27
|
-
limit: '50mb'
|
|
28
|
-
})) // healthcheck returns meta info as well
|
|
29
|
-
.get('/percy/healthcheck', (_, res) => {
|
|
30
|
-
res.json({
|
|
31
|
-
success: true,
|
|
32
|
-
config: percy.config,
|
|
33
|
-
loglevel: percy.loglevel(),
|
|
34
|
-
build: percy.client.build
|
|
35
|
-
});
|
|
36
|
-
}) // responds when idle
|
|
37
|
-
.get('/percy/idle', asyncRoute(async (_, res) => {
|
|
38
|
-
await percy.idle();
|
|
39
|
-
res.json({
|
|
40
|
-
success: true
|
|
41
|
-
});
|
|
42
|
-
})) // serves @percy/dom as a convenience
|
|
43
|
-
.get('/percy/dom.js', (_, res) => {
|
|
44
|
-
res.sendFile(require.resolve('@percy/dom'));
|
|
45
|
-
}) // forward snapshot requests
|
|
46
|
-
.post('/percy/snapshot', asyncRoute(async (req, res) => {
|
|
47
|
-
await percy.snapshot(req.body);
|
|
48
|
-
res.json({
|
|
49
|
-
success: true
|
|
50
|
-
});
|
|
51
|
-
})) // stops the instance
|
|
52
|
-
.post('/percy/stop', asyncRoute(async (_, res) => {
|
|
53
|
-
await percy.stop();
|
|
54
|
-
res.json({
|
|
55
|
-
success: true
|
|
56
|
-
});
|
|
57
|
-
})) // other routes 404
|
|
58
|
-
.use('*', (_, res) => {
|
|
59
|
-
res.status(404).json({
|
|
60
|
-
success: false,
|
|
61
|
-
error: 'Not found'
|
|
62
|
-
});
|
|
63
|
-
}) // generic error handler
|
|
64
|
-
.use(({
|
|
65
|
-
message
|
|
66
|
-
}, req, res, next) => {
|
|
67
|
-
res.status(500).json({
|
|
68
|
-
success: false,
|
|
69
|
-
error: message
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
} // Promised based helper for starting an app at the specified port. Resolves
|
|
73
|
-
// when the server is listening, rejects if there are any errors when starting.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
function startServer(app, port) {
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
let server = app.listen(port);
|
|
79
|
-
server.once('listening', () => resolve(server));
|
|
80
|
-
server.once('error', reject);
|
|
81
|
-
});
|
|
82
|
-
}
|
package/dist/utils/assert.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = percyAssert;
|
|
7
|
-
|
|
8
|
-
var _assert = require("assert");
|
|
9
|
-
|
|
10
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
11
|
-
|
|
12
|
-
// Percy assertions errors contain extra meta data and have specific lookup keys
|
|
13
|
-
// for different computed assertion error messages.
|
|
14
|
-
class PercyAssertionError extends Error {
|
|
15
|
-
constructor(lookup, meta = {}) {
|
|
16
|
-
var _PercyAssertionError$, _PercyAssertionError$2, _PercyAssertionError$3;
|
|
17
|
-
|
|
18
|
-
super((_PercyAssertionError$ = (_PercyAssertionError$2 = (_PercyAssertionError$3 = PercyAssertionError.dict)[lookup]) === null || _PercyAssertionError$2 === void 0 ? void 0 : _PercyAssertionError$2.call(_PercyAssertionError$3, meta)) !== null && _PercyAssertionError$ !== void 0 ? _PercyAssertionError$ : lookup);
|
|
19
|
-
this.name = this.constructor.name;
|
|
20
|
-
this.meta = meta;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
toString() {
|
|
24
|
-
return this.message;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
} // Wraps native assert to throw a Percy assertion error with optional meta.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
_defineProperty(PercyAssertionError, "dict", {
|
|
31
|
-
'disallowed status': ({
|
|
32
|
-
status
|
|
33
|
-
}) => `Disallowed response status [${status}]`,
|
|
34
|
-
'is empty': () => 'Empty response',
|
|
35
|
-
'is remote': () => 'Remote resource',
|
|
36
|
-
'no response': () => 'No response',
|
|
37
|
-
'too many bytes': ({
|
|
38
|
-
size
|
|
39
|
-
}) => `Max file size exceeded [${size}]`,
|
|
40
|
-
'too many redirects': ({
|
|
41
|
-
length
|
|
42
|
-
}) => `Too many redirects [${length}]`,
|
|
43
|
-
'too many widths': ({
|
|
44
|
-
widths
|
|
45
|
-
}) => `Too many widths requested: maximum is 10, requested ${widths}`
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
function percyAssert(condition, lookup, meta) {
|
|
49
|
-
(0, _assert.strict)(condition, new PercyAssertionError(lookup, meta));
|
|
50
|
-
}
|
package/dist/utils/bytes.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = readableBytes;
|
|
7
|
-
|
|
8
|
-
// Converts a raw byte integer into a human readable string.
|
|
9
|
-
function readableBytes(bytes) {
|
|
10
|
-
let units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
11
|
-
let thresh = 1024;
|
|
12
|
-
let u = -1;
|
|
13
|
-
|
|
14
|
-
if (Math.abs(bytes) < thresh) {
|
|
15
|
-
return `${bytes}B`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
while (Math.abs(bytes) >= thresh && u < units.length - 1) {
|
|
19
|
-
bytes /= thresh;
|
|
20
|
-
++u;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return `${bytes.toFixed(1)}${units[u]}`;
|
|
24
|
-
}
|