@percy/core 1.10.3 → 1.11.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/api.js CHANGED
@@ -2,9 +2,15 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { createRequire } from 'module';
4
4
  import logger from '@percy/logger';
5
+ import { normalize } from '@percy/config/utils';
5
6
  import { getPackageJSON, Server } from './utils.js'; // need require.resolve until import.meta.resolve can be transpiled
6
7
 
7
- export const PERCY_DOM = createRequire(import.meta.url).resolve('@percy/dom'); // Create a Percy CLI API server instance
8
+ export const PERCY_DOM = createRequire(import.meta.url).resolve('@percy/dom'); // Returns a URL encoded string of nested query params
9
+
10
+ function encodeURLSearchParams(subj, prefix) {
11
+ return typeof subj === 'object' ? Object.entries(subj).map(([key, value]) => encodeURLSearchParams(value, prefix ? `${prefix}[${key}]` : key)).join('&') : `${prefix}=${encodeURIComponent(subj)}`;
12
+ } // Create a Percy CLI API server instance
13
+
8
14
 
9
15
  export function createPercyServer(percy, port) {
10
16
  let pkg = getPackageJSON(import.meta.url);
@@ -71,7 +77,7 @@ export function createPercyServer(percy, port) {
71
77
  });
72
78
  }) // get or set config options
73
79
  .route(['get', 'post'], '/percy/config', async (req, res) => res.json(200, {
74
- config: req.body ? await percy.setConfig(req.body) : percy.config,
80
+ config: req.body ? percy.set(req.body) : percy.config,
75
81
  success: true
76
82
  })) // responds once idle (may take a long time)
77
83
  .route('get', '/percy/idle', async (req, res) => res.json(200, {
@@ -85,14 +91,46 @@ export function createPercyServer(percy, port) {
85
91
  let content = await fs.promises.readFile(PERCY_DOM, 'utf-8');
86
92
  let wrapper = '(window.PercyAgent = class { snapshot(n, o) { return PercyDOM.serialize(o); } });';
87
93
  return res.send(200, 'applicaton/javascript', content.concat(wrapper));
88
- }) // post one or more snapshots
94
+ }) // post one or more snapshots, optionally async
89
95
  .route('post', '/percy/snapshot', async (req, res) => {
90
96
  let snapshot = percy.snapshot(req.body);
91
97
  if (!req.url.searchParams.has('async')) await snapshot;
92
98
  return res.json(200, {
93
99
  success: true
94
100
  });
95
- }) // stops percy at the end of the current event loop
101
+ }) // post one or more comparisons, optionally waiting
102
+ .route('post', '/percy/comparison', async (req, res) => {
103
+ let upload = percy.upload(req.body);
104
+ if (req.url.searchParams.has('await')) await upload; // generate and include one or more redirect links to comparisons
105
+
106
+ let link = ({
107
+ name,
108
+ tag
109
+ }) => {
110
+ var _percy$build;
111
+
112
+ return [percy.client.apiUrl, '/comparisons/redirect?', encodeURLSearchParams(normalize({
113
+ buildId: (_percy$build = percy.build) === null || _percy$build === void 0 ? void 0 : _percy$build.id,
114
+ snapshot: {
115
+ name
116
+ },
117
+ tag
118
+ }, {
119
+ snake: true
120
+ }))].join('');
121
+ };
122
+
123
+ return res.json(200, Object.assign({
124
+ success: true
125
+ }, req.body ? Array.isArray(req.body) ? {
126
+ links: req.body.map(link)
127
+ } : {
128
+ link: link(req.body)
129
+ } : {}));
130
+ }) // flushes one or more snapshots from the internal queue
131
+ .route('post', '/percy/flush', async (req, res) => res.json(200, {
132
+ success: await percy.flush(req.body).then(() => true)
133
+ })) // stops percy at the end of the current event loop
96
134
  .route('/percy/stop', (req, res) => {
97
135
  setImmediate(() => percy.stop());
98
136
  return res.json(200, {
package/dist/config.js CHANGED
@@ -1,5 +1,14 @@
1
1
  // Common config options used in Percy commands
2
2
  export const configSchema = {
3
+ percy: {
4
+ type: 'object',
5
+ additionalProperties: false,
6
+ properties: {
7
+ deferUploads: {
8
+ type: 'boolean'
9
+ }
10
+ }
11
+ },
3
12
  snapshot: {
4
13
  type: 'object',
5
14
  additionalProperties: false,
@@ -10,7 +19,7 @@ export const configSchema = {
10
19
  items: {
11
20
  type: 'integer',
12
21
  maximum: 2000,
13
- minimum: 10
22
+ minimum: 120
14
23
  }
15
24
  },
16
25
  minHeight: {
@@ -28,9 +37,6 @@ export const configSchema = {
28
37
  },
29
38
  scope: {
30
39
  type: 'string'
31
- },
32
- devicePixelRatio: {
33
- type: 'integer'
34
40
  }
35
41
  }
36
42
  },
@@ -129,6 +135,9 @@ export const configSchema = {
129
135
  userAgent: {
130
136
  type: 'string'
131
137
  },
138
+ devicePixelRatio: {
139
+ type: 'integer'
140
+ },
132
141
  concurrency: {
133
142
  type: 'integer',
134
143
  minimum: 1
@@ -180,9 +189,6 @@ export const snapshotSchema = {
180
189
  enableJavaScript: {
181
190
  $ref: '/config/snapshot#/properties/enableJavaScript'
182
191
  },
183
- devicePixelRatio: {
184
- $ref: '/config/snapshot#/properties/devicePixelRatio'
185
- },
186
192
  discovery: {
187
193
  type: 'object',
188
194
  additionalProperties: false,
@@ -204,6 +210,9 @@ export const snapshotSchema = {
204
210
  },
205
211
  userAgent: {
206
212
  $ref: '/config/discovery#/properties/userAgent'
213
+ },
214
+ devicePixelRatio: {
215
+ $ref: '/config/discovery#/properties/devicePixelRatio'
207
216
  }
208
217
  }
209
218
  }
@@ -388,6 +397,9 @@ export const snapshotSchema = {
388
397
  },
389
398
  domSnapshot: {
390
399
  type: 'string'
400
+ },
401
+ width: {
402
+ $ref: '/config/snapshot#/properties/widths/items'
391
403
  }
392
404
  },
393
405
  errors: {
@@ -470,9 +482,87 @@ export const snapshotSchema = {
470
482
  }
471
483
  }
472
484
  }
485
+ }; // Comparison upload options
486
+
487
+ export const comparisonSchema = {
488
+ type: 'object',
489
+ $id: '/comparison',
490
+ required: ['name', 'tag'],
491
+ additionalProperties: false,
492
+ properties: {
493
+ name: {
494
+ type: 'string'
495
+ },
496
+ externalDebugUrl: {
497
+ type: 'string'
498
+ },
499
+ tag: {
500
+ type: 'object',
501
+ additionalProperties: false,
502
+ required: ['name'],
503
+ properties: {
504
+ name: {
505
+ type: 'string'
506
+ },
507
+ osName: {
508
+ type: 'string'
509
+ },
510
+ osVersion: {
511
+ type: 'string'
512
+ },
513
+ width: {
514
+ type: 'integer',
515
+ maximum: 2000,
516
+ minimum: 120
517
+ },
518
+ height: {
519
+ type: 'integer',
520
+ minimum: 10
521
+ },
522
+ orientation: {
523
+ type: 'string',
524
+ enum: ['portrait', 'landscape']
525
+ }
526
+ }
527
+ },
528
+ tiles: {
529
+ type: 'array',
530
+ items: {
531
+ type: 'object',
532
+ additionalProperties: false,
533
+ properties: {
534
+ filepath: {
535
+ type: 'string'
536
+ },
537
+ content: {
538
+ type: 'string'
539
+ },
540
+ statusBarHeight: {
541
+ type: 'integer',
542
+ minimum: 0
543
+ },
544
+ navBarHeight: {
545
+ type: 'integer',
546
+ minimum: 0
547
+ },
548
+ headerHeight: {
549
+ type: 'integer',
550
+ minimum: 0
551
+ },
552
+ footerHeight: {
553
+ type: 'integer',
554
+ minimum: 0
555
+ },
556
+ fullscreen: {
557
+ type: 'boolean'
558
+ }
559
+ }
560
+ }
561
+ }
562
+ }
473
563
  }; // Grouped schemas for easier registration
474
564
 
475
- export const schemas = [configSchema, snapshotSchema]; // Config migrate function
565
+ export const schemas = [configSchema, snapshotSchema, comparisonSchema]; // Config migrate function
476
566
 
477
567
  export function configMigration(config, util) {
478
568
  /* eslint-disable curly */
@@ -485,41 +575,21 @@ export function configMigration(config, util) {
485
575
  util.map('agent.assetDiscovery.pagePoolSizeMax', 'discovery.concurrency');
486
576
  util.del('agent');
487
577
  } else {
488
- let notice = {
578
+ util.deprecate('snapshot.devicePixelRatio', {
579
+ map: 'discovery.devicePixelRatio',
489
580
  type: 'config',
490
- until: '1.0.0'
491
- }; // snapshot discovery options have moved
492
-
493
- util.deprecate('snapshot.authorization', {
494
- map: 'discovery.authorization',
495
- ...notice
496
- });
497
- util.deprecate('snapshot.requestHeaders', {
498
- map: 'discovery.requestHeaders',
499
- ...notice
581
+ until: '2.0.0'
500
582
  });
501
583
  }
502
584
  } // Snapshot option migrate function
503
585
 
504
586
  export function snapshotMigration(config, util, root = '') {
505
- let notice = {
587
+ // discovery options have moved
588
+ util.deprecate(`${root}.devicePixelRatio`, {
589
+ map: `${root}.discovery.devicePixelRatio`,
506
590
  type: 'snapshot',
507
- until: '1.0.0',
591
+ until: '2.0.0',
508
592
  warn: true
509
- }; // discovery options have moved
510
-
511
- util.deprecate(`${root}.authorization`, {
512
- map: `${root}.discovery.authorization`,
513
- ...notice
514
- });
515
- util.deprecate(`${root}.requestHeaders`, {
516
- map: `${root}.discovery.requestHeaders`,
517
- ...notice
518
- }); // snapshots option was renamed
519
-
520
- util.deprecate(`${root}.snapshots`, {
521
- map: `${root}.additionalSnapshots`,
522
- ...notice
523
593
  });
524
594
  } // Snapshot list options migrate function
525
595
 
@@ -531,18 +601,8 @@ export function snapshotListMigration(config, util) {
531
601
  snapshotMigration(config, util, `snapshots[${i}]`);
532
602
  }
533
603
  }
534
- } // overrides option was renamed
535
-
604
+ } // migrate options
536
605
 
537
- let notice = {
538
- type: 'snapshot',
539
- until: '1.0.0',
540
- warn: true
541
- };
542
- util.deprecate('overrides', {
543
- map: 'options',
544
- ...notice
545
- }); // migrate options
546
606
 
547
607
  if (Array.isArray(config.options)) {
548
608
  for (let i in config.options) {