@percy/client 1.10.4 → 1.12.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 +34 -1
- package/dist/client.js +118 -12
- package/package.json +4 -4
- package/test/helpers.js +8 -0
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ builds. Can also be used to query for a project's builds using a read access tok
|
|
|
7
7
|
- [Usage](#usage)
|
|
8
8
|
- [Create a build](#create-a-build)
|
|
9
9
|
- [Create, upload, and finalize snapshots](#create-upload-and-finalize-snapshots)
|
|
10
|
+
- [Create, upload, and finalize comparisons](#create-upload-and-finalize-comparisons)
|
|
10
11
|
- [Finalize a build](#finalize-a-build)
|
|
11
12
|
- [Query for a build*](#query-for-a-build)
|
|
12
13
|
- [Query for a project's builds*](#query-for-a-projects-builds)
|
|
@@ -59,7 +60,39 @@ await client.sendSnapshot(buildId, snapshotOptions)
|
|
|
59
60
|
- `mimetype` — Resource mimetype (**required**)
|
|
60
61
|
- `content` — Resource content (**required**)
|
|
61
62
|
- `sha` — Resource content sha
|
|
62
|
-
- `root` — Boolean indicating a root resource
|
|
63
|
+
- `root` — Boolean indicating a root resource## Create, upload, and finalize snapshots
|
|
64
|
+
|
|
65
|
+
## Create, upload, and finalize comparisons
|
|
66
|
+
|
|
67
|
+
This method combines the work of creating a snapshot, creating an associated comparison, uploading
|
|
68
|
+
associated comparison tiles, and finally finalizing the comparison.
|
|
69
|
+
|
|
70
|
+
``` js
|
|
71
|
+
await client.sendComparison(buildId, comparisonOptions)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### Options
|
|
75
|
+
|
|
76
|
+
- `name` — Snapshot name (**required**)
|
|
77
|
+
- `clientInfo` — Additional client info
|
|
78
|
+
- `environmentInfo` — Additional environment info
|
|
79
|
+
- `externalDebugUrl` — External debug URL
|
|
80
|
+
- `tag` — Tagged information about this comparison
|
|
81
|
+
- `name` — The tag name for this comparison, e.g. "iPhone 14 Pro" (**required**)
|
|
82
|
+
- `osName` - OS name for the comparison tag; e.g. "iOS"
|
|
83
|
+
- `osVersion` - OS version for the comparison tag; e.g. "16"
|
|
84
|
+
- `width` - The width for this type of comparison
|
|
85
|
+
- `height` - The height for this type of comparison
|
|
86
|
+
- `orientation` - Either "portrait" or "landscape"
|
|
87
|
+
- `tiles` — Array of comparison tiles
|
|
88
|
+
- `sha` — Tile file contents SHA-256 hash
|
|
89
|
+
- `filepath` — Tile filepath in the filesystem (required when missing `content`)
|
|
90
|
+
- `content` — Tile contents as a string or buffer (required when missing `filepath`)
|
|
91
|
+
- `statusBarHeight` — Height of any status bar in this tile
|
|
92
|
+
- `navBarHeight` — Height of any nav bar in this tile
|
|
93
|
+
- `headerHeight` — Height of any header area in this tile
|
|
94
|
+
- `footerHeight` — Height of any footer area in this tile
|
|
95
|
+
- `fullscreen` — Boolean indicating this is a fullscreen tile
|
|
63
96
|
|
|
64
97
|
## Finalize a build
|
|
65
98
|
|
package/dist/client.js
CHANGED
|
@@ -7,13 +7,13 @@ import { pool, request, sha256hash, base64encode, getPackageJSON } from './utils
|
|
|
7
7
|
const {
|
|
8
8
|
PERCY_CLIENT_API_URL = 'https://percy.io/api/v1'
|
|
9
9
|
} = process.env;
|
|
10
|
-
const pkg = getPackageJSON(import.meta.url); // Validate
|
|
10
|
+
const pkg = getPackageJSON(import.meta.url); // Validate ID arguments
|
|
11
11
|
|
|
12
|
-
function
|
|
13
|
-
if (!id) throw new Error(
|
|
12
|
+
function validateId(type, id) {
|
|
13
|
+
if (!id) throw new Error(`Missing ${type} ID`);
|
|
14
14
|
|
|
15
15
|
if (!(typeof id === 'string' || typeof id === 'number')) {
|
|
16
|
-
throw new Error(
|
|
16
|
+
throw new Error(`Invalid ${type} ID`);
|
|
17
17
|
}
|
|
18
18
|
} // Validate project path arguments
|
|
19
19
|
|
|
@@ -157,7 +157,7 @@ export class PercyClient {
|
|
|
157
157
|
async finalizeBuild(buildId, {
|
|
158
158
|
all = false
|
|
159
159
|
} = {}) {
|
|
160
|
-
|
|
160
|
+
validateId('build', buildId);
|
|
161
161
|
let qs = all ? 'all-shards=true' : '';
|
|
162
162
|
this.log.debug(`Finalizing build ${buildId}...`);
|
|
163
163
|
return this.post(`builds/${buildId}/finalize?${qs}`);
|
|
@@ -165,7 +165,7 @@ export class PercyClient {
|
|
|
165
165
|
|
|
166
166
|
|
|
167
167
|
async getBuild(buildId) {
|
|
168
|
-
|
|
168
|
+
validateId('build', buildId);
|
|
169
169
|
this.log.debug(`Get build ${buildId}`);
|
|
170
170
|
return this.get(`builds/${buildId}`);
|
|
171
171
|
} // Retrieves project builds optionally filtered. Requires a read access token.
|
|
@@ -252,9 +252,9 @@ export class PercyClient {
|
|
|
252
252
|
filepath,
|
|
253
253
|
content
|
|
254
254
|
} = {}) {
|
|
255
|
-
|
|
255
|
+
validateId('build', buildId);
|
|
256
256
|
this.log.debug(`Uploading resource: ${url}...`);
|
|
257
|
-
if (filepath) content = fs.
|
|
257
|
+
if (filepath) content = await fs.promises.readFile(filepath);
|
|
258
258
|
return this.post(`builds/${buildId}/resources`, {
|
|
259
259
|
data: {
|
|
260
260
|
type: 'resources',
|
|
@@ -268,7 +268,7 @@ export class PercyClient {
|
|
|
268
268
|
|
|
269
269
|
|
|
270
270
|
async uploadResources(buildId, resources) {
|
|
271
|
-
|
|
271
|
+
validateId('build', buildId);
|
|
272
272
|
this.log.debug(`Uploading resources for ${buildId}...`);
|
|
273
273
|
return pool(function* () {
|
|
274
274
|
for (let resource of resources) {
|
|
@@ -288,7 +288,7 @@ export class PercyClient {
|
|
|
288
288
|
environmentInfo,
|
|
289
289
|
resources = []
|
|
290
290
|
} = {}) {
|
|
291
|
-
|
|
291
|
+
validateId('build', buildId);
|
|
292
292
|
this.addClientInfo(clientInfo);
|
|
293
293
|
this.addEnvironmentInfo(environmentInfo);
|
|
294
294
|
|
|
@@ -297,6 +297,12 @@ export class PercyClient {
|
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
this.log.debug(`Creating snapshot: ${name}...`);
|
|
300
|
+
|
|
301
|
+
for (let resource of resources) {
|
|
302
|
+
if (resource.sha || resource.content || !resource.filepath) continue;
|
|
303
|
+
resource.content = await fs.promises.readFile(resource.filepath);
|
|
304
|
+
}
|
|
305
|
+
|
|
300
306
|
return this.post(`builds/${buildId}/snapshots`, {
|
|
301
307
|
data: {
|
|
302
308
|
type: 'snapshots',
|
|
@@ -311,10 +317,11 @@ export class PercyClient {
|
|
|
311
317
|
resources: {
|
|
312
318
|
data: resources.map(r => ({
|
|
313
319
|
type: 'resources',
|
|
314
|
-
id: r.sha
|
|
320
|
+
id: r.sha ?? (r.content && sha256hash(r.content)),
|
|
315
321
|
attributes: {
|
|
316
322
|
'resource-url': r.url || null,
|
|
317
323
|
'is-root': r.root || null,
|
|
324
|
+
'for-widths': r.widths || null,
|
|
318
325
|
mimetype: r.mimetype || null
|
|
319
326
|
}
|
|
320
327
|
}))
|
|
@@ -326,7 +333,7 @@ export class PercyClient {
|
|
|
326
333
|
|
|
327
334
|
|
|
328
335
|
async finalizeSnapshot(snapshotId) {
|
|
329
|
-
|
|
336
|
+
validateId('snapshot', snapshotId);
|
|
330
337
|
this.log.debug(`Finalizing snapshot ${snapshotId}...`);
|
|
331
338
|
return this.post(`snapshots/${snapshotId}/finalize`);
|
|
332
339
|
} // Convenience method for creating a snapshot for the active build, uploading
|
|
@@ -352,5 +359,104 @@ export class PercyClient {
|
|
|
352
359
|
return snapshot;
|
|
353
360
|
}
|
|
354
361
|
|
|
362
|
+
async createComparison(snapshotId, {
|
|
363
|
+
tag,
|
|
364
|
+
tiles = [],
|
|
365
|
+
externalDebugUrl
|
|
366
|
+
} = {}) {
|
|
367
|
+
validateId('snapshot', snapshotId);
|
|
368
|
+
this.log.debug(`Creating comparision: ${tag.name}...`);
|
|
369
|
+
|
|
370
|
+
for (let tile of tiles) {
|
|
371
|
+
if (tile.sha || tile.content || !tile.filepath) continue;
|
|
372
|
+
tile.content = await fs.promises.readFile(tile.filepath);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return this.post(`snapshots/${snapshotId}/comparisons`, {
|
|
376
|
+
data: {
|
|
377
|
+
type: 'comparisons',
|
|
378
|
+
attributes: {
|
|
379
|
+
'external-debug-url': externalDebugUrl || null
|
|
380
|
+
},
|
|
381
|
+
relationships: {
|
|
382
|
+
tag: {
|
|
383
|
+
data: {
|
|
384
|
+
type: 'tag',
|
|
385
|
+
attributes: {
|
|
386
|
+
name: tag.name || null,
|
|
387
|
+
width: tag.width || null,
|
|
388
|
+
height: tag.height || null,
|
|
389
|
+
'os-name': tag.osName || null,
|
|
390
|
+
'os-version': tag.osVersion || null,
|
|
391
|
+
orientation: tag.orientation || null
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
tiles: {
|
|
396
|
+
data: tiles.map(t => ({
|
|
397
|
+
type: 'tiles',
|
|
398
|
+
attributes: {
|
|
399
|
+
sha: t.sha || t.content && sha256hash(t.content),
|
|
400
|
+
'status-bar-height': t.statusBarHeight || null,
|
|
401
|
+
'nav-bar-height': t.navBarHeight || null,
|
|
402
|
+
'header-height': t.headerHeight || null,
|
|
403
|
+
'footer-height': t.footerHeight || null,
|
|
404
|
+
fullscreen: t.fullscreen || null
|
|
405
|
+
}
|
|
406
|
+
}))
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
async uploadComparisonTile(comparisonId, {
|
|
414
|
+
index = 0,
|
|
415
|
+
total = 1,
|
|
416
|
+
filepath,
|
|
417
|
+
content
|
|
418
|
+
} = {}) {
|
|
419
|
+
validateId('comparison', comparisonId);
|
|
420
|
+
this.log.debug(`Uploading comparison tile: ${index + 1}/${total} (${comparisonId})...`);
|
|
421
|
+
if (filepath) content = await fs.promises.readFile(filepath);
|
|
422
|
+
return this.post(`comparisons/${comparisonId}/tiles`, {
|
|
423
|
+
data: {
|
|
424
|
+
type: 'tiles',
|
|
425
|
+
attributes: {
|
|
426
|
+
'base64-content': base64encode(content),
|
|
427
|
+
index
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async uploadComparisonTiles(comparisonId, tiles) {
|
|
434
|
+
validateId('comparison', comparisonId);
|
|
435
|
+
this.log.debug(`Uploading comparison tiles for ${comparisonId}...`);
|
|
436
|
+
return pool(function* () {
|
|
437
|
+
for (let index = 0; index < tiles.length; index++) {
|
|
438
|
+
yield this.uploadComparisonTile(comparisonId, {
|
|
439
|
+
index,
|
|
440
|
+
total: tiles.length,
|
|
441
|
+
...tiles[index]
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}, this, 2);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async finalizeComparison(comparisonId) {
|
|
448
|
+
validateId('comparison', comparisonId);
|
|
449
|
+
this.log.debug(`Finalizing comparison ${comparisonId}...`);
|
|
450
|
+
return this.post(`comparisons/${comparisonId}/finalize`);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async sendComparison(buildId, options) {
|
|
454
|
+
let snapshot = await this.createSnapshot(buildId, options);
|
|
455
|
+
let comparison = await this.createComparison(snapshot.data.id, options);
|
|
456
|
+
await this.uploadComparisonTiles(comparison.data.id, options.tiles);
|
|
457
|
+
await this.finalizeComparison(comparison.data.id);
|
|
458
|
+
return comparison;
|
|
459
|
+
}
|
|
460
|
+
|
|
355
461
|
}
|
|
356
462
|
export default PercyClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"test:coverage": "yarn test --coverage"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@percy/env": "1.
|
|
35
|
-
"@percy/logger": "1.
|
|
34
|
+
"@percy/env": "1.12.0",
|
|
35
|
+
"@percy/logger": "1.12.0"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "4303b74df91f60e36065141289d2ef2277d1d6fc"
|
|
38
38
|
}
|
package/test/helpers.js
CHANGED