@percy/core 1.31.14-beta.3 → 1.31.14-beta.4

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 CHANGED
@@ -151,6 +151,91 @@ export const configSchema = {
151
151
  sync: {
152
152
  type: 'boolean'
153
153
  },
154
+ readiness: {
155
+ type: 'object',
156
+ additionalProperties: false,
157
+ properties: {
158
+ preset: {
159
+ type: 'string',
160
+ enum: ['balanced', 'strict', 'fast', 'disabled']
161
+ },
162
+ stabilityWindowMs: {
163
+ type: 'integer',
164
+ minimum: 50,
165
+ maximum: 30000
166
+ },
167
+ jsIdleWindowMs: {
168
+ type: 'integer',
169
+ minimum: 50,
170
+ maximum: 30000
171
+ },
172
+ networkIdleWindowMs: {
173
+ type: 'integer',
174
+ minimum: 50,
175
+ maximum: 10000
176
+ },
177
+ timeoutMs: {
178
+ type: 'integer',
179
+ minimum: 1000,
180
+ maximum: 60000
181
+ },
182
+ domStability: {
183
+ type: 'boolean'
184
+ },
185
+ imageReady: {
186
+ type: 'boolean'
187
+ },
188
+ fontReady: {
189
+ type: 'boolean'
190
+ },
191
+ jsIdle: {
192
+ type: 'boolean'
193
+ },
194
+ readySelectors: {
195
+ type: 'array',
196
+ items: {
197
+ oneOf: [{
198
+ type: 'string'
199
+ }, {
200
+ type: 'object',
201
+ additionalProperties: false,
202
+ properties: {
203
+ css: {
204
+ type: 'string'
205
+ },
206
+ xpath: {
207
+ type: 'string'
208
+ }
209
+ }
210
+ }]
211
+ }
212
+ },
213
+ notPresentSelectors: {
214
+ type: 'array',
215
+ items: {
216
+ oneOf: [{
217
+ type: 'string'
218
+ }, {
219
+ type: 'object',
220
+ additionalProperties: false,
221
+ properties: {
222
+ css: {
223
+ type: 'string'
224
+ },
225
+ xpath: {
226
+ type: 'string'
227
+ }
228
+ }
229
+ }]
230
+ }
231
+ },
232
+ maxTimeoutMs: {
233
+ type: 'integer',
234
+ minimum: 1000,
235
+ maximum: 60000
236
+ }
237
+ }
238
+ },
154
239
  responsiveSnapshotCapture: {
155
240
  type: 'boolean',
156
241
  default: false
@@ -612,6 +697,9 @@ export const snapshotSchema = {
612
697
  sync: {
613
698
  $ref: '/config/snapshot#/properties/sync'
614
699
  },
700
+ readiness: {
701
+ $ref: '/config/snapshot#/properties/readiness'
702
+ },
615
703
  responsiveSnapshotCapture: {
616
704
  $ref: '/config/snapshot#/properties/responsiveSnapshotCapture'
617
705
  },
@@ -945,6 +1033,11 @@ export const snapshotSchema = {
945
1033
  type: 'string'
946
1034
  }
947
1035
  },
1036
+ readiness_diagnostics: {
1037
+ type: 'object',
1038
+ normalize: false,
1039
+ description: 'Diagnostics from readiness checks run before serialization. ' + 'normalize: false preserves the snake_case wire format the SDKs send (timed_out, ' + 'total_duration_ms, etc.) instead of camelCasing inner keys at validate time.'
1040
+ },
948
1041
  corsIframes: {
949
1042
  type: 'array',
950
1043
  items: {
package/dist/page.js CHANGED
@@ -232,6 +232,7 @@ export class Page {
232
232
  execute,
233
233
  ...snapshot
234
234
  }) {
235
+ var _this$browser;
235
236
  let {
236
237
  name,
237
238
  width,
@@ -291,8 +292,24 @@ export class Page {
291
292
  }
292
293
  await this.insertPercyDom();
293
294
 
294
- // serialize and capture a DOM snapshot
295
- this.log.debug('Serialize DOM', this.meta);
295
+ // Run readiness checks before serializing — wait for page stability
296
+ let readiness = snapshot.readiness || ((_this$browser = this.browser) === null || _this$browser === void 0 || (_this$browser = _this$browser.percy) === null || _this$browser === void 0 || (_this$browser = _this$browser.config) === null || _this$browser === void 0 || (_this$browser = _this$browser.snapshot) === null || _this$browser === void 0 ? void 0 : _this$browser.readiness);
297
+ let readinessDiagnostics;
298
+ if (readiness && readiness.preset !== 'disabled') {
299
+ var _readinessDiagnostics;
300
+ this.log.debug('Waiting for readiness', this.meta);
301
+ readinessDiagnostics = await this.eval(/* istanbul ignore next: no instrumenting injected code */
302
+ async (_, config) => {
303
+ var _PercyDOM;
304
+ // eslint-disable-next-line no-undef
305
+ if (typeof ((_PercyDOM = PercyDOM) === null || _PercyDOM === void 0 ? void 0 : _PercyDOM.waitForReady) === 'function') return PercyDOM.waitForReady(config);
306
+ }, readiness).catch(e => {
307
+ this.log.debug(`Readiness check failed: ${e}`, this.meta);
308
+ });
309
+ if ((_readinessDiagnostics = readinessDiagnostics) !== null && _readinessDiagnostics !== void 0 && _readinessDiagnostics.timed_out) {
310
+ this.log.debug('Readiness timed out, capturing anyway', this.meta);
311
+ }
312
+ }
296
313
  let capture = await this.eval(serializeDomCapture, {
297
314
  enableJavaScript,
298
315
  disableShadowDOM,
@@ -304,6 +321,13 @@ export class Page {
304
321
  ignoreIframeSelectors,
305
322
  pseudoClassEnabledElements
306
323
  });
324
+
325
+ // Attach readiness diagnostics onto the captured DOM snapshot so the backend/UI can surface
326
+ // readiness metrics. Only valid when domSnapshot is the structured object form — the legacy
327
+ // string form (HTML only) has no place to embed diagnostics.
328
+ if (readinessDiagnostics && capture !== null && capture !== void 0 && capture.domSnapshot && typeof capture.domSnapshot === 'object') {
329
+ capture.domSnapshot.readiness_diagnostics = readinessDiagnostics;
330
+ }
307
331
  return {
308
332
  ...snapshot,
309
333
  ...capture
package/dist/snapshot.js CHANGED
@@ -231,6 +231,27 @@ export function validateSnapshotOptions(options) {
231
231
  log.warn('Encountered snapshot serialization warnings:');
232
232
  for (let w of domWarnings) log.warn(`- ${w}`);
233
233
  }
234
+
235
+ // log readiness diagnostics when present.
236
+ // domSnapshot is a union of `string` (legacy SDK payload — HTML only) and `object`
237
+ // ({ html, warnings, readiness_diagnostics, ... }). Diagnostics only exist on the object form;
238
+ // gate explicitly on typeof so the intent is obvious to readers.
239
+ // The schema marks readiness_diagnostics with normalize: false to preserve the snake_case wire
240
+ // format. The dual-read fallback below is defensive — it keeps the log working even if a future
241
+ // SDK sends camelCase keys, or if a path in PercyConfig.migrate skips the normalize: false hint.
242
+ let domSnapshotObj = migrated.domSnapshot && typeof migrated.domSnapshot === 'object' ? migrated.domSnapshot : null;
243
+ let readinessDiag = (domSnapshotObj === null || domSnapshotObj === void 0 ? void 0 : domSnapshotObj.readiness_diagnostics) ?? (domSnapshotObj === null || domSnapshotObj === void 0 ? void 0 : domSnapshotObj.readinessDiagnostics);
244
+ if (readinessDiag) {
245
+ let timedOut = readinessDiag.timed_out ?? readinessDiag.timedOut;
246
+ let durationMs = readinessDiag.total_duration_ms ?? readinessDiag.totalDurationMs;
247
+ let presetName = readinessDiag.preset || 'custom';
248
+ if (timedOut) {
249
+ log.warn(`Readiness timed out after ${durationMs}ms (preset: ${presetName})`);
250
+ } else {
251
+ log.debug(`Readiness passed in ${durationMs}ms (preset: ${presetName})`);
252
+ }
253
+ }
254
+
234
255
  // warn on validation errors
235
256
  let errors = PercyConfig.validate(migrated, schema);
236
257
  if ((errors === null || errors === void 0 ? void 0 : errors.length) > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/core",
3
- "version": "1.31.14-beta.3",
3
+ "version": "1.31.14-beta.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,12 +44,12 @@
44
44
  "test:types": "tsd"
45
45
  },
46
46
  "dependencies": {
47
- "@percy/client": "1.31.14-beta.3",
48
- "@percy/config": "1.31.14-beta.3",
49
- "@percy/dom": "1.31.14-beta.3",
50
- "@percy/logger": "1.31.14-beta.3",
51
- "@percy/monitoring": "1.31.14-beta.3",
52
- "@percy/webdriver-utils": "1.31.14-beta.3",
47
+ "@percy/client": "1.31.14-beta.4",
48
+ "@percy/config": "1.31.14-beta.4",
49
+ "@percy/dom": "1.31.14-beta.4",
50
+ "@percy/logger": "1.31.14-beta.4",
51
+ "@percy/monitoring": "1.31.14-beta.4",
52
+ "@percy/webdriver-utils": "1.31.14-beta.4",
53
53
  "content-disposition": "^0.5.4",
54
54
  "cross-spawn": "^7.0.3",
55
55
  "extract-zip": "^2.0.1",
@@ -63,7 +63,7 @@
63
63
  "yaml": "^2.4.1"
64
64
  },
65
65
  "optionalDependencies": {
66
- "@percy/cli-doctor": "1.31.14-beta.3"
66
+ "@percy/cli-doctor": "1.31.14-beta.4"
67
67
  },
68
- "gitHead": "a17d4a1453c6bef282fd3da38082b670e125a5be"
68
+ "gitHead": "b52f1d2fb6272c0b3694e1e9ff584c5622a118c7"
69
69
  }