@percy/core 1.0.0-beta.76 → 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 +86 -18
- package/package.json +24 -14
- package/dist/api.js +0 -76
- package/dist/browser.js +0 -363
- package/dist/config.js +0 -358
- package/dist/discovery.js +0 -130
- package/dist/index.js +0 -15
- package/dist/install.js +0 -173
- package/dist/network.js +0 -365
- package/dist/page.js +0 -293
- package/dist/percy.js +0 -427
- package/dist/queue.js +0 -196
- package/dist/server.js +0 -471
- package/dist/session.js +0 -140
- package/dist/snapshot.js +0 -279
- package/dist/utils.js +0 -170
- package/post-install.js +0 -23
- package/test/helpers/server.js +0 -35
- package/types/index.d.ts +0 -101
package/dist/snapshot.js
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.discoverSnapshotResources = discoverSnapshotResources;
|
|
7
|
-
exports.getSnapshotConfig = getSnapshotConfig;
|
|
8
|
-
|
|
9
|
-
var _logger = _interopRequireDefault(require("@percy/logger"));
|
|
10
|
-
|
|
11
|
-
var _config = _interopRequireDefault(require("@percy/config"));
|
|
12
|
-
|
|
13
|
-
var _utils = require("@percy/config/dist/utils");
|
|
14
|
-
|
|
15
|
-
var _utils2 = require("./utils");
|
|
16
|
-
|
|
17
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
-
|
|
19
|
-
// Validates and returns snapshot options merged with percy config options.
|
|
20
|
-
function getSnapshotConfig(percy, options) {
|
|
21
|
-
var _ref, _snapshot$widths;
|
|
22
|
-
|
|
23
|
-
if (!options.url) throw new Error('Missing required URL for snapshot');
|
|
24
|
-
let {
|
|
25
|
-
config
|
|
26
|
-
} = percy;
|
|
27
|
-
let uri = new URL(options.url);
|
|
28
|
-
let name = options.name || `${uri.pathname}${uri.search}${uri.hash}`;
|
|
29
|
-
let meta = {
|
|
30
|
-
snapshot: {
|
|
31
|
-
name
|
|
32
|
-
},
|
|
33
|
-
build: percy.build
|
|
34
|
-
};
|
|
35
|
-
let log = (0, _logger.default)('core:snapshot'); // migrate deprecated snapshot config options
|
|
36
|
-
|
|
37
|
-
let {
|
|
38
|
-
clientInfo,
|
|
39
|
-
environmentInfo,
|
|
40
|
-
...snapshot
|
|
41
|
-
} = _config.default.migrate(options, '/snapshot'); // throw an error when missing required widths
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!((_ref = (_snapshot$widths = snapshot.widths) !== null && _snapshot$widths !== void 0 ? _snapshot$widths : percy.config.snapshot.widths) !== null && _ref !== void 0 && _ref.length)) {
|
|
45
|
-
throw new Error('Missing required widths for snapshot');
|
|
46
|
-
} // validate and scrub according to dom snaphot presence
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let errors = _config.default.validate(snapshot, snapshot.domSnapshot ? '/snapshot/dom' : '/snapshot');
|
|
50
|
-
|
|
51
|
-
if (errors) {
|
|
52
|
-
log.warn('Invalid snapshot options:', meta);
|
|
53
|
-
|
|
54
|
-
for (let e of errors) log.warn(`- ${e.path}: ${e.message}`, meta);
|
|
55
|
-
} // inherit options from the percy config
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return (0, _utils.merge)([config.snapshot, {
|
|
59
|
-
name,
|
|
60
|
-
meta,
|
|
61
|
-
clientInfo,
|
|
62
|
-
environmentInfo,
|
|
63
|
-
// only specific discovery options are used per-snapshot
|
|
64
|
-
discovery: {
|
|
65
|
-
allowedHostnames: [uri.hostname, ...config.discovery.allowedHostnames],
|
|
66
|
-
networkIdleTimeout: config.discovery.networkIdleTimeout,
|
|
67
|
-
requestHeaders: config.discovery.requestHeaders,
|
|
68
|
-
authorization: config.discovery.authorization,
|
|
69
|
-
disableCache: config.discovery.disableCache,
|
|
70
|
-
userAgent: config.discovery.userAgent
|
|
71
|
-
}
|
|
72
|
-
}, snapshot], (path, prev, next) => {
|
|
73
|
-
switch (path.map(k => k.toString()).join('.')) {
|
|
74
|
-
case 'widths':
|
|
75
|
-
// override and sort widths
|
|
76
|
-
return [path, next.sort((a, b) => a - b)];
|
|
77
|
-
|
|
78
|
-
case 'percyCSS':
|
|
79
|
-
// concatenate percy css
|
|
80
|
-
return [path, [prev, next].filter(Boolean).join('\n')];
|
|
81
|
-
|
|
82
|
-
case 'execute':
|
|
83
|
-
// shorthand for execute.beforeSnapshot
|
|
84
|
-
return Array.isArray(next) || typeof next !== 'object' ? [path.concat('beforeSnapshot'), next] : [path];
|
|
85
|
-
} // ensure additional snapshots have complete names
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (path[0] === 'additionalSnapshots' && path.length === 2) {
|
|
89
|
-
let {
|
|
90
|
-
prefix = '',
|
|
91
|
-
suffix = '',
|
|
92
|
-
...n
|
|
93
|
-
} = next;
|
|
94
|
-
next = {
|
|
95
|
-
name: `${prefix}${name}${suffix}`,
|
|
96
|
-
...n
|
|
97
|
-
};
|
|
98
|
-
return [path, next];
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
} // Returns a complete and valid snapshot config object and logs verbose debug logs detailing various
|
|
102
|
-
// snapshot options. When `showInfo` is true, specific messages will be logged as info logs rather
|
|
103
|
-
// than debug logs.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
function debugSnapshotConfig(snapshot, showInfo) {
|
|
107
|
-
let log = (0, _logger.default)('core:snapshot'); // log snapshot info
|
|
108
|
-
|
|
109
|
-
log.debug('---------', snapshot.meta);
|
|
110
|
-
if (showInfo) log.info(`Snapshot found: ${snapshot.name}`, snapshot.meta);else log.debug(`Handling snapshot: ${snapshot.name}`, snapshot.meta); // will log debug info for an object property if its value is defined
|
|
111
|
-
|
|
112
|
-
let debugProp = (obj, prop, format = String) => {
|
|
113
|
-
let val = prop.split('.').reduce((o, k) => o === null || o === void 0 ? void 0 : o[k], obj);
|
|
114
|
-
|
|
115
|
-
if (val != null) {
|
|
116
|
-
// join formatted array values with a space
|
|
117
|
-
val = [].concat(val).map(format).join(', ');
|
|
118
|
-
log.debug(`- ${prop}: ${val}`, snapshot.meta);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
debugProp(snapshot, 'url');
|
|
123
|
-
debugProp(snapshot, 'widths', v => `${v}px`);
|
|
124
|
-
debugProp(snapshot, 'minHeight', v => `${v}px`);
|
|
125
|
-
debugProp(snapshot, 'enableJavaScript');
|
|
126
|
-
debugProp(snapshot, 'waitForTimeout');
|
|
127
|
-
debugProp(snapshot, 'waitForSelector');
|
|
128
|
-
debugProp(snapshot, 'execute.afterNavigation');
|
|
129
|
-
debugProp(snapshot, 'execute.beforeResize');
|
|
130
|
-
debugProp(snapshot, 'execute.afterResize');
|
|
131
|
-
debugProp(snapshot, 'execute.beforeSnapshot');
|
|
132
|
-
debugProp(snapshot, 'discovery.allowedHostnames');
|
|
133
|
-
debugProp(snapshot, 'discovery.requestHeaders', JSON.stringify);
|
|
134
|
-
debugProp(snapshot, 'discovery.authorization', JSON.stringify);
|
|
135
|
-
debugProp(snapshot, 'discovery.disableCache');
|
|
136
|
-
debugProp(snapshot, 'discovery.userAgent');
|
|
137
|
-
debugProp(snapshot, 'clientInfo');
|
|
138
|
-
debugProp(snapshot, 'environmentInfo');
|
|
139
|
-
debugProp(snapshot, 'domSnapshot', Boolean);
|
|
140
|
-
|
|
141
|
-
for (let added of snapshot.additionalSnapshots || []) {
|
|
142
|
-
if (showInfo) log.info(`Snapshot found: ${added.name}`, snapshot.meta);else log.debug(`Additional snapshot: ${added.name}`, snapshot.meta);
|
|
143
|
-
debugProp(added, 'waitForTimeout');
|
|
144
|
-
debugProp(added, 'waitForSelector');
|
|
145
|
-
debugProp(added, 'execute');
|
|
146
|
-
}
|
|
147
|
-
} // Calls the provided callback with additional resources
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
function handleSnapshotResources(snapshot, map, callback) {
|
|
151
|
-
let resources = [...map.values()]; // sort the root resource first
|
|
152
|
-
|
|
153
|
-
let [root] = resources.splice(resources.findIndex(r => r.root), 1);
|
|
154
|
-
resources.unshift(root); // inject Percy CSS
|
|
155
|
-
|
|
156
|
-
if (snapshot.percyCSS) {
|
|
157
|
-
let css = (0, _utils2.createPercyCSSResource)(root.url, snapshot.percyCSS);
|
|
158
|
-
resources.push(css); // replace root contents and associated properties
|
|
159
|
-
|
|
160
|
-
Object.assign(root, (0, _utils2.createRootResource)(root.url, root.content.replace(/(<\/body>)(?!.*\1)/is, `<link data-percy-specific-css rel="stylesheet" href="${css.pathname}"/>` + '$&')));
|
|
161
|
-
} // include associated snapshot logs matched by meta information
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
resources.push((0, _utils2.createLogResource)(_logger.default.query(log => {
|
|
165
|
-
var _log$meta$snapshot;
|
|
166
|
-
|
|
167
|
-
return ((_log$meta$snapshot = log.meta.snapshot) === null || _log$meta$snapshot === void 0 ? void 0 : _log$meta$snapshot.name) === snapshot.meta.snapshot.name;
|
|
168
|
-
})));
|
|
169
|
-
return callback(snapshot, resources);
|
|
170
|
-
} // Wait for a page's asset discovery network to idle
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
function waitForDiscoveryNetworkIdle(page, options) {
|
|
174
|
-
let {
|
|
175
|
-
allowedHostnames,
|
|
176
|
-
networkIdleTimeout
|
|
177
|
-
} = options;
|
|
178
|
-
|
|
179
|
-
let filter = r => (0, _utils2.hostnameMatches)(allowedHostnames, r.url);
|
|
180
|
-
|
|
181
|
-
return page.network.idle(filter, networkIdleTimeout);
|
|
182
|
-
} // Used to cache resources across core instances
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const RESOURCE_CACHE_KEY = Symbol('resource-cache'); // Discovers resources for a snapshot using a browser page to intercept requests. The callback
|
|
186
|
-
// function will be called with the snapshot name (for additional snapshots) and an array of
|
|
187
|
-
// discovered resources. When additional snapshots are provided, the callback will be called once
|
|
188
|
-
// for each snapshot.
|
|
189
|
-
|
|
190
|
-
async function* discoverSnapshotResources(percy, snapshot, callback) {
|
|
191
|
-
var _snapshot$enableJavaS;
|
|
192
|
-
|
|
193
|
-
debugSnapshotConfig(snapshot, percy.dryRun); // when dry-running, invoke the callback for each snapshot and immediately return
|
|
194
|
-
|
|
195
|
-
let allSnapshots = [snapshot, ...(snapshot.additionalSnapshots || [])];
|
|
196
|
-
if (percy.dryRun) return allSnapshots.map(s => callback(s)); // keep a global resource cache across snapshots
|
|
197
|
-
|
|
198
|
-
let cache = percy[RESOURCE_CACHE_KEY] || (percy[RESOURCE_CACHE_KEY] = new Map()); // copy widths to prevent mutation later
|
|
199
|
-
|
|
200
|
-
let widths = snapshot.widths.slice(); // preload the root resource for existing dom snapshots
|
|
201
|
-
|
|
202
|
-
let resources = new Map(snapshot.domSnapshot && [(0, _utils2.createRootResource)(snapshot.url, snapshot.domSnapshot)].map(resource => [resource.url, resource])); // open a new browser page
|
|
203
|
-
|
|
204
|
-
let page = yield percy.browser.page({
|
|
205
|
-
enableJavaScript: (_snapshot$enableJavaS = snapshot.enableJavaScript) !== null && _snapshot$enableJavaS !== void 0 ? _snapshot$enableJavaS : !snapshot.domSnapshot,
|
|
206
|
-
networkIdleTimeout: snapshot.discovery.networkIdleTimeout,
|
|
207
|
-
requestHeaders: snapshot.discovery.requestHeaders,
|
|
208
|
-
authorization: snapshot.discovery.authorization,
|
|
209
|
-
userAgent: snapshot.discovery.userAgent,
|
|
210
|
-
meta: snapshot.meta,
|
|
211
|
-
// enable network inteception
|
|
212
|
-
intercept: {
|
|
213
|
-
enableJavaScript: snapshot.enableJavaScript,
|
|
214
|
-
disableCache: snapshot.discovery.disableCache,
|
|
215
|
-
allowedHostnames: snapshot.discovery.allowedHostnames,
|
|
216
|
-
getResource: u => resources.get(u) || cache.get(u),
|
|
217
|
-
saveResource: r => resources.set(r.url, r) && cache.set(r.url, r)
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
var _snapshot$execute;
|
|
223
|
-
|
|
224
|
-
// set the initial page size
|
|
225
|
-
yield page.resize({
|
|
226
|
-
width: widths.shift(),
|
|
227
|
-
height: snapshot.minHeight
|
|
228
|
-
}); // navigate to the url
|
|
229
|
-
|
|
230
|
-
yield page.goto(snapshot.url);
|
|
231
|
-
yield page.evaluate((_snapshot$execute = snapshot.execute) === null || _snapshot$execute === void 0 ? void 0 : _snapshot$execute.afterNavigation); // trigger resize events for other widths
|
|
232
|
-
|
|
233
|
-
for (let width of widths) {
|
|
234
|
-
var _snapshot$execute2, _snapshot$execute3;
|
|
235
|
-
|
|
236
|
-
yield page.evaluate((_snapshot$execute2 = snapshot.execute) === null || _snapshot$execute2 === void 0 ? void 0 : _snapshot$execute2.beforeResize);
|
|
237
|
-
yield waitForDiscoveryNetworkIdle(page, snapshot.discovery);
|
|
238
|
-
yield page.resize({
|
|
239
|
-
width,
|
|
240
|
-
height: snapshot.minHeight
|
|
241
|
-
});
|
|
242
|
-
yield page.evaluate((_snapshot$execute3 = snapshot.execute) === null || _snapshot$execute3 === void 0 ? void 0 : _snapshot$execute3.afterResize);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (snapshot.domSnapshot) {
|
|
246
|
-
// ensure discovery has finished and handle resources
|
|
247
|
-
yield waitForDiscoveryNetworkIdle(page, snapshot.discovery);
|
|
248
|
-
handleSnapshotResources(snapshot, resources, callback);
|
|
249
|
-
} else {
|
|
250
|
-
let {
|
|
251
|
-
enableJavaScript
|
|
252
|
-
} = snapshot; // capture snapshots sequentially
|
|
253
|
-
|
|
254
|
-
for (let snap of allSnapshots) {
|
|
255
|
-
// will wait for timeouts, selectors, and additional network activity
|
|
256
|
-
let {
|
|
257
|
-
url,
|
|
258
|
-
dom
|
|
259
|
-
} = yield page.snapshot({
|
|
260
|
-
enableJavaScript,
|
|
261
|
-
...snap
|
|
262
|
-
});
|
|
263
|
-
resources.set(url, (0, _utils2.createRootResource)(url, dom)); // shallow merge with root snapshot options
|
|
264
|
-
|
|
265
|
-
handleSnapshotResources({ ...snapshot,
|
|
266
|
-
...snap
|
|
267
|
-
}, resources, callback); // remove the previously captured dom snapshot
|
|
268
|
-
|
|
269
|
-
resources.delete(url);
|
|
270
|
-
}
|
|
271
|
-
} // page clean up
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
await page.close();
|
|
275
|
-
} catch (error) {
|
|
276
|
-
await page.close();
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
}
|
package/dist/utils.js
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.createLogResource = createLogResource;
|
|
7
|
-
exports.createPercyCSSResource = createPercyCSSResource;
|
|
8
|
-
exports.createResource = createResource;
|
|
9
|
-
exports.createRootResource = createRootResource;
|
|
10
|
-
exports.generatePromise = generatePromise;
|
|
11
|
-
exports.hostname = hostname;
|
|
12
|
-
Object.defineProperty(exports, "hostnameMatches", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () {
|
|
15
|
-
return _utils.hostnameMatches;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
exports.normalizeURL = normalizeURL;
|
|
19
|
-
Object.defineProperty(exports, "request", {
|
|
20
|
-
enumerable: true,
|
|
21
|
-
get: function () {
|
|
22
|
-
return _request.request;
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
exports.waitFor = waitFor;
|
|
26
|
-
|
|
27
|
-
var _utils = require("@percy/client/dist/utils");
|
|
28
|
-
|
|
29
|
-
var _request = require("@percy/client/dist/request");
|
|
30
|
-
|
|
31
|
-
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; }
|
|
32
|
-
|
|
33
|
-
// Returns the hostname portion of a URL.
|
|
34
|
-
function hostname(url) {
|
|
35
|
-
return new URL(url).hostname;
|
|
36
|
-
} // Normalizes a URL by stripping hashes to ensure unique resources.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
function normalizeURL(url) {
|
|
40
|
-
let {
|
|
41
|
-
protocol,
|
|
42
|
-
host,
|
|
43
|
-
pathname,
|
|
44
|
-
search
|
|
45
|
-
} = new URL(url);
|
|
46
|
-
return `${protocol}//${host}${pathname}${search}`;
|
|
47
|
-
} // Creates a local resource object containing the resource URL, mimetype, content, sha, and any
|
|
48
|
-
// other additional resources attributes.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
function createResource(url, content, mimetype, attrs) {
|
|
52
|
-
return { ...attrs,
|
|
53
|
-
sha: (0, _utils.sha256hash)(content),
|
|
54
|
-
mimetype,
|
|
55
|
-
content,
|
|
56
|
-
url
|
|
57
|
-
};
|
|
58
|
-
} // Creates a root resource object with an additional `root: true` property. The URL is normalized
|
|
59
|
-
// here as a convenience since root resources are usually created outside of asset discovery.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
function createRootResource(url, content) {
|
|
63
|
-
return createResource(normalizeURL(url), content, 'text/html', {
|
|
64
|
-
root: true
|
|
65
|
-
});
|
|
66
|
-
} // Creates a Percy CSS resource object.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
function createPercyCSSResource(url, css) {
|
|
70
|
-
let {
|
|
71
|
-
href,
|
|
72
|
-
pathname
|
|
73
|
-
} = new URL(`/percy-specific.${Date.now()}.css`, url);
|
|
74
|
-
return createResource(href, css, 'text/css', {
|
|
75
|
-
pathname
|
|
76
|
-
});
|
|
77
|
-
} // Creates a log resource object.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
function createLogResource(logs) {
|
|
81
|
-
return createResource(`/percy.${Date.now()}.log`, JSON.stringify(logs), 'text/plain');
|
|
82
|
-
} // Creates a thennable, cancelable, generator instance
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function generatePromise(gen) {
|
|
86
|
-
var _gen, _gen2;
|
|
87
|
-
|
|
88
|
-
// ensure a generator is provided
|
|
89
|
-
if (typeof gen === 'function') gen = gen();
|
|
90
|
-
if (typeof ((_gen = gen) === null || _gen === void 0 ? void 0 : _gen.then) === 'function') return gen;
|
|
91
|
-
if (typeof ((_gen2 = gen) === null || _gen2 === void 0 ? void 0 : _gen2.next) !== 'function' || !(typeof gen[Symbol.iterator] === 'function' || typeof gen[Symbol.asyncIterator] === 'function')) return Promise.resolve(gen); // used to trigger cancelation
|
|
92
|
-
|
|
93
|
-
class Canceled extends Error {
|
|
94
|
-
constructor(...args) {
|
|
95
|
-
super(...args);
|
|
96
|
-
|
|
97
|
-
_defineProperty(this, "name", 'Canceled');
|
|
98
|
-
|
|
99
|
-
_defineProperty(this, "canceled", true);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
} // recursively runs the generator, maybe throwing an error when canceled
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
let handleNext = async (g, last) => {
|
|
106
|
-
let canceled = g.cancel.triggered;
|
|
107
|
-
let {
|
|
108
|
-
done,
|
|
109
|
-
value
|
|
110
|
-
} = canceled ? await g.throw(canceled) : await g.next(last);
|
|
111
|
-
if (canceled) delete g.cancel.triggered;
|
|
112
|
-
return done ? value : handleNext(g, value);
|
|
113
|
-
}; // handle cancelation errors by calling any cancel handlers
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
let cancelable = async function* () {
|
|
117
|
-
try {
|
|
118
|
-
return yield* gen;
|
|
119
|
-
} catch (error) {
|
|
120
|
-
if (error.canceled) {
|
|
121
|
-
let cancelers = cancelable.cancelers || [];
|
|
122
|
-
|
|
123
|
-
for (let c of cancelers) await c(error);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
}(); // augment the cancelable generator with promise-like and cancel methods
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return Object.assign(cancelable, {
|
|
132
|
-
run: () => cancelable.promise || (cancelable.promise = handleNext(cancelable)),
|
|
133
|
-
then: (resolve, reject) => cancelable.run().then(resolve, reject),
|
|
134
|
-
catch: reject => cancelable.run().catch(reject),
|
|
135
|
-
cancel: message => {
|
|
136
|
-
cancelable.cancel.triggered = new Canceled(message);
|
|
137
|
-
return cancelable;
|
|
138
|
-
},
|
|
139
|
-
canceled: handler => {
|
|
140
|
-
(cancelable.cancelers || (cancelable.cancelers = [])).push(handler);
|
|
141
|
-
return cancelable;
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
} // Resolves when the predicate function returns true within the timeout. If an idle option is
|
|
145
|
-
// provided, the predicate will be checked again before resolving, after the idle period. The poll
|
|
146
|
-
// option determines how often the predicate check will be run.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
function waitFor(predicate, options) {
|
|
150
|
-
let {
|
|
151
|
-
poll = 10,
|
|
152
|
-
timeout,
|
|
153
|
-
idle
|
|
154
|
-
} = Number.isInteger(options) ? {
|
|
155
|
-
timeout: options
|
|
156
|
-
} : options || {};
|
|
157
|
-
return generatePromise(async function* check(start, done) {
|
|
158
|
-
while (true) {
|
|
159
|
-
if (timeout && Date.now() - start >= timeout) {
|
|
160
|
-
throw new Error(`Timeout of ${timeout}ms exceeded.`);
|
|
161
|
-
} else if (!predicate()) {
|
|
162
|
-
yield new Promise(r => setTimeout(r, poll, done = false));
|
|
163
|
-
} else if (idle && !done) {
|
|
164
|
-
yield new Promise(r => setTimeout(r, idle, done = true));
|
|
165
|
-
} else {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}(Date.now()));
|
|
170
|
-
}
|
package/post-install.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// Automatically download and install Chromium if the PERCY_POSTINSTALL_BROWSER environment variable
|
|
2
|
-
// is present and truthy, or if this module is required directly from within another module. Useful
|
|
3
|
-
// when running in CI environments with heavy caching of node_modules.
|
|
4
|
-
if (process.env.PERCY_POSTINSTALL_BROWSER || require.main !== module) {
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
|
|
8
|
-
// the src directory indicates postinstall during development
|
|
9
|
-
const isDev = fs.existsSync(path.join(__dirname, 'src'));
|
|
10
|
-
|
|
11
|
-
// register babel transforms for development install
|
|
12
|
-
if (isDev) require('../../scripts/babel-register');
|
|
13
|
-
|
|
14
|
-
// require dev or production modules
|
|
15
|
-
const install = require(isDev ? './src/install' : './dist/install');
|
|
16
|
-
const log = require(isDev ? '../logger/src' : '@percy/logger')('core:post-install');
|
|
17
|
-
|
|
18
|
-
// install chromium
|
|
19
|
-
install.chromium().catch(error => {
|
|
20
|
-
log.error('Encountered an error while installing Chromium');
|
|
21
|
-
log.error(error);
|
|
22
|
-
});
|
|
23
|
-
}
|
package/test/helpers/server.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// aliased to src for coverage during tests without needing to compile this file
|
|
2
|
-
const { default: Server } = require('@percy/core/dist/server');
|
|
3
|
-
|
|
4
|
-
function createTestServer({ default: defaultReply, ...replies }, port = 8000) {
|
|
5
|
-
let server = new Server();
|
|
6
|
-
|
|
7
|
-
// alternate route handling
|
|
8
|
-
let handleReply = reply => async (req, res) => {
|
|
9
|
-
let [status, headers, body] = typeof reply === 'function' ? await reply(req) : reply;
|
|
10
|
-
if (!Buffer.isBuffer(body) && typeof body !== 'string') body = JSON.stringify(body);
|
|
11
|
-
return res.send(status, headers, body);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// map replies to alternate route handlers
|
|
15
|
-
server.reply = (p, reply) => (replies[p] = handleReply(reply));
|
|
16
|
-
for (let [p, reply] of Object.entries(replies)) server.reply(p, reply);
|
|
17
|
-
if (defaultReply) defaultReply = handleReply(defaultReply);
|
|
18
|
-
|
|
19
|
-
// track requests and route replies
|
|
20
|
-
server.requests = [];
|
|
21
|
-
server.route(async (req, res, next) => {
|
|
22
|
-
let pathname = req.url.pathname;
|
|
23
|
-
if (req.url.search) pathname += req.url.search;
|
|
24
|
-
server.requests.push(req.body ? [pathname, req.body] : [pathname]);
|
|
25
|
-
let reply = replies[req.url.pathname] || defaultReply;
|
|
26
|
-
return reply ? await reply(req, res) : next();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// automatically listen
|
|
30
|
-
return server.listen(port);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// support commonjs environments
|
|
34
|
-
module.exports = createTestServer;
|
|
35
|
-
module.exports.createTestServer = createTestServer;
|
package/types/index.d.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// utility types
|
|
2
|
-
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
|
3
|
-
type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
|
|
4
|
-
|
|
5
|
-
type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'silent';
|
|
6
|
-
|
|
7
|
-
interface Pojo {
|
|
8
|
-
[x: string]: any;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface AuthCredentials {
|
|
12
|
-
username: string;
|
|
13
|
-
password: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface DiscoveryOptions {
|
|
17
|
-
requestHeaders?: Pojo;
|
|
18
|
-
authorization?: AuthCredentials;
|
|
19
|
-
allowedHostnames?: string[];
|
|
20
|
-
disableCache?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface DiscoveryLaunchOptions {
|
|
24
|
-
executable?: string;
|
|
25
|
-
args?: string[];
|
|
26
|
-
timeout?: number;
|
|
27
|
-
headless?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface AllDiscoveryOptions extends DiscoveryOptions {
|
|
31
|
-
networkIdleTimeout?: number;
|
|
32
|
-
concurrency?: number;
|
|
33
|
-
launchOptions?: DiscoveryLaunchOptions;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface CommonSnapshotOptions {
|
|
37
|
-
widths?: number[];
|
|
38
|
-
minHeight?: number;
|
|
39
|
-
percyCSS?: string;
|
|
40
|
-
enableJavaScript?: boolean;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface SnapshotOptions extends CommonSnapshotOptions {
|
|
44
|
-
discovery?: DiscoveryOptions;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
type ClientEnvInfo = {
|
|
48
|
-
clientInfo?: string,
|
|
49
|
-
environmentInfo?: string
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export type PercyConfigOptions<C = Pojo> = C & {
|
|
53
|
-
snapshot?: CommonSnapshotOptions,
|
|
54
|
-
discovery?: AllDiscoveryOptions
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type PercyOptions<C = Pojo> = {
|
|
58
|
-
token?: string,
|
|
59
|
-
server?: boolean,
|
|
60
|
-
port?: number,
|
|
61
|
-
concurrency?: number,
|
|
62
|
-
loglevel?: LogLevel,
|
|
63
|
-
config?: undefined | string | false
|
|
64
|
-
} & ClientEnvInfo & PercyConfigOptions<C>;
|
|
65
|
-
|
|
66
|
-
type SnapshotExec = () => void | Promise<void>;
|
|
67
|
-
|
|
68
|
-
type AdditionalSnapshot = (XOR<XOR<
|
|
69
|
-
{ name: string },
|
|
70
|
-
{ prefix: string, suffix?: string }>,
|
|
71
|
-
{ suffix: string, prefix?: string }>
|
|
72
|
-
) & { execute: SnapshotExec };
|
|
73
|
-
|
|
74
|
-
declare class Percy {
|
|
75
|
-
static start(options?: PercyOptions): Promise<Percy>;
|
|
76
|
-
constructor(options?: PercyOptions);
|
|
77
|
-
loglevel(): LogLevel;
|
|
78
|
-
loglevel(level: LogLevel): void;
|
|
79
|
-
config: PercyConfigOptions;
|
|
80
|
-
setConfig(config: ClientEnvInfo & PercyConfigOptions): PercyConfigOptions;
|
|
81
|
-
start(): Promise<void>;
|
|
82
|
-
stop(force?: boolean): Promise<void>;
|
|
83
|
-
idle(): Promise<void>;
|
|
84
|
-
close(): void;
|
|
85
|
-
|
|
86
|
-
snapshot(options: {
|
|
87
|
-
url: string,
|
|
88
|
-
name?: string,
|
|
89
|
-
clientInfo?: string,
|
|
90
|
-
environmentInfo?: string
|
|
91
|
-
} & XOR<{
|
|
92
|
-
domSnapshot: string
|
|
93
|
-
}, {
|
|
94
|
-
waitForTimeout?: number,
|
|
95
|
-
waitForSelector?: string,
|
|
96
|
-
execute?: SnapshotExec,
|
|
97
|
-
additionalSnapshots?: AdditionalSnapshot[]
|
|
98
|
-
}> & SnapshotOptions): Promise<void>;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export default Percy;
|