@stablyai/internal-playwright 0.1.13 → 0.1.15

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.
@@ -38,7 +38,7 @@ var import_path = __toESM(require("path"));
38
38
  var import_utils = require("playwright-core/lib/utils");
39
39
  var import_utils2 = require("playwright-core/lib/utils");
40
40
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
41
- var import_healingService = require("playwright-core/src/server/stably/auto_heal/healingService");
41
+ var import_healingService = require("playwright-core/lib/server/stably/auto_heal/healingService");
42
42
  var import_util = require("../util");
43
43
  var import_matcherHint = require("./matcherHint");
44
44
  var import_globals = require("../common/globals");
@@ -63,17 +63,10 @@ class SnapshotHelper {
63
63
  name = nameFromOptions;
64
64
  }
65
65
  this.name = Array.isArray(name) ? name.join(import_path.default.sep) : name || "";
66
- const resolvedPaths = testInfo._resolveSnapshotPaths(
67
- matcherName === "toHaveScreenshot" ? "screenshot" : "snapshot",
68
- name,
69
- "updateSnapshotIndex",
70
- anonymousSnapshotExtension
71
- );
66
+ const resolvedPaths = testInfo._resolveSnapshotPaths(matcherName === "toHaveScreenshot" ? "screenshot" : "snapshot", name, "updateSnapshotIndex", anonymousSnapshotExtension);
72
67
  this.expectedPath = resolvedPaths.absoluteSnapshotPath;
73
68
  this.attachmentBaseName = resolvedPaths.relativeOutputPath;
74
- const outputBasePath = testInfo._getOutputPath(
75
- resolvedPaths.relativeOutputPath
76
- );
69
+ const outputBasePath = testInfo._getOutputPath(resolvedPaths.relativeOutputPath);
77
70
  this.legacyExpectedPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-expected");
78
71
  this.previousPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-previous");
79
72
  this.actualPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-actual");
@@ -90,13 +83,9 @@ class SnapshotHelper {
90
83
  delete this.options._comparator;
91
84
  }
92
85
  if (this.options.maxDiffPixels !== void 0 && this.options.maxDiffPixels < 0)
93
- throw new Error(
94
- "`maxDiffPixels` option value must be non-negative integer"
95
- );
86
+ throw new Error("`maxDiffPixels` option value must be non-negative integer");
96
87
  if (this.options.maxDiffPixelRatio !== void 0 && (this.options.maxDiffPixelRatio < 0 || this.options.maxDiffPixelRatio > 1))
97
- throw new Error(
98
- "`maxDiffPixelRatio` option value must be between 0 and 1"
99
- );
88
+ throw new Error("`maxDiffPixelRatio` option value must be between 0 and 1");
100
89
  this.matcherName = matcherName;
101
90
  this.locator = locator;
102
91
  this.updateSnapshots = testInfo.config.updateSnapshots;
@@ -115,9 +104,7 @@ class SnapshotHelper {
115
104
  message: () => message,
116
105
  log
117
106
  };
118
- return Object.fromEntries(
119
- Object.entries(unfiltered).filter(([_, v]) => v !== void 0)
120
- );
107
+ return Object.fromEntries(Object.entries(unfiltered).filter(([_, v]) => v !== void 0));
121
108
  }
122
109
  handleMissingNegated() {
123
110
  const isWriteMissingMode = this.updateSnapshots !== "none";
@@ -137,18 +124,11 @@ class SnapshotHelper {
137
124
  }
138
125
  handleMissing(actual, step) {
139
126
  const isWriteMissingMode = this.updateSnapshots !== "none";
140
- if (isWriteMissingMode) writeFileSync(this.expectedPath, actual);
141
- step?._attachToStep({
142
- name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"),
143
- contentType: this.mimeType,
144
- path: this.expectedPath
145
- });
127
+ if (isWriteMissingMode)
128
+ writeFileSync(this.expectedPath, actual);
129
+ step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"), contentType: this.mimeType, path: this.expectedPath });
146
130
  writeFileSync(this.actualPath, actual);
147
- step?._attachToStep({
148
- name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"),
149
- contentType: this.mimeType,
150
- path: this.actualPath
151
- });
131
+ step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"), contentType: this.mimeType, path: this.actualPath });
152
132
  const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? ", writing actual." : "."}`;
153
133
  if (this.updateSnapshots === "all" || this.updateSnapshots === "changed") {
154
134
  console.log(message);
@@ -169,38 +149,24 @@ class SnapshotHelper {
169
149
  }
170
150
  if (expected !== void 0) {
171
151
  writeFileSync(this.legacyExpectedPath, expected);
172
- step?._attachToStep({
173
- name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"),
174
- contentType: this.mimeType,
175
- path: this.expectedPath
176
- });
152
+ step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"), contentType: this.mimeType, path: this.expectedPath });
177
153
  }
178
154
  if (previous !== void 0) {
179
155
  writeFileSync(this.previousPath, previous);
180
- step?._attachToStep({
181
- name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-previous"),
182
- contentType: this.mimeType,
183
- path: this.previousPath
184
- });
156
+ step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-previous"), contentType: this.mimeType, path: this.previousPath });
185
157
  }
186
158
  if (actual !== void 0) {
187
159
  writeFileSync(this.actualPath, actual);
188
- step?._attachToStep({
189
- name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"),
190
- contentType: this.mimeType,
191
- path: this.actualPath
192
- });
160
+ step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"), contentType: this.mimeType, path: this.actualPath });
193
161
  }
194
162
  if (diff !== void 0) {
195
163
  writeFileSync(this.diffPath, diff);
196
- step?._attachToStep({
197
- name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-diff"),
198
- contentType: this.mimeType,
199
- path: this.diffPath
200
- });
164
+ step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-diff"), contentType: this.mimeType, path: this.diffPath });
201
165
  }
202
- if (log?.length) output.push((0, import_matcherHint.callLogText)(log));
203
- else output.push("");
166
+ if (log?.length)
167
+ output.push((0, import_matcherHint.callLogText)(log));
168
+ else
169
+ output.push("");
204
170
  return this.createMatcherResult(output.join("\n"), false, log);
205
171
  }
206
172
  handleMatching() {
@@ -212,16 +178,9 @@ function toMatchSnapshot(received, nameOrOptions = {}, optOptions = {}) {
212
178
  if (!testInfo)
213
179
  throw new Error(`toMatchSnapshot() must be called during the test`);
214
180
  if (received instanceof Promise)
215
- throw new Error(
216
- "An unresolved Promise was passed to toMatchSnapshot(), make sure to resolve it by adding await to it."
217
- );
181
+ throw new Error("An unresolved Promise was passed to toMatchSnapshot(), make sure to resolve it by adding await to it.");
218
182
  if (testInfo._projectInternal.ignoreSnapshots)
219
- return {
220
- pass: !this.isNot,
221
- message: () => "",
222
- name: "toMatchSnapshot",
223
- expected: nameOrOptions
224
- };
183
+ return { pass: !this.isNot, message: () => "", name: "toMatchSnapshot", expected: nameOrOptions };
225
184
  const configOptions = testInfo._projectInternal.expect?.toMatchSnapshot || {};
226
185
  const helper = new SnapshotHelper(
227
186
  testInfo,
@@ -235,11 +194,7 @@ function toMatchSnapshot(received, nameOrOptions = {}, optOptions = {}) {
235
194
  if (this.isNot) {
236
195
  if (!import_fs.default.existsSync(helper.expectedPath))
237
196
  return helper.handleMissingNegated();
238
- const isDifferent = !!helper.comparator(
239
- received,
240
- import_fs.default.readFileSync(helper.expectedPath),
241
- helper.options
242
- );
197
+ const isDifferent = !!helper.comparator(received, import_fs.default.readFileSync(helper.expectedPath), helper.options);
243
198
  return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
244
199
  }
245
200
  if (!import_fs.default.existsSync(helper.expectedPath))
@@ -250,44 +205,28 @@ function toMatchSnapshot(received, nameOrOptions = {}, optOptions = {}) {
250
205
  return helper.handleMatching();
251
206
  writeFileSync(helper.expectedPath, received);
252
207
  console.log(helper.expectedPath + " is not the same, writing actual.");
253
- return helper.createMatcherResult(
254
- helper.expectedPath + " running with --update-snapshots, writing actual.",
255
- true
256
- );
208
+ return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
257
209
  }
258
210
  if (helper.updateSnapshots === "changed") {
259
211
  const result2 = helper.comparator(received, expected, helper.options);
260
- if (!result2) return helper.handleMatching();
212
+ if (!result2)
213
+ return helper.handleMatching();
261
214
  writeFileSync(helper.expectedPath, received);
262
215
  console.log(helper.expectedPath + " does not match, writing actual.");
263
- return helper.createMatcherResult(
264
- helper.expectedPath + " running with --update-snapshots, writing actual.",
265
- true
266
- );
216
+ return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
267
217
  }
268
218
  const result = helper.comparator(received, expected, helper.options);
269
- if (!result) return helper.handleMatching();
270
- const header = (0, import_matcherHint.formatMatcherMessage)(this, {
271
- matcherName: "toMatchSnapshot",
272
- receiver: (0, import_utils.isString)(received) ? "string" : "Buffer",
273
- expectation: "expected"
274
- });
275
- return helper.handleDifferent(
276
- received,
277
- expected,
278
- void 0,
279
- result.diff,
280
- header,
281
- result.errorMessage,
282
- void 0,
283
- this._stepInfo
284
- );
219
+ if (!result)
220
+ return helper.handleMatching();
221
+ const header = (0, import_matcherHint.formatMatcherMessage)(this, { matcherName: "toMatchSnapshot", receiver: (0, import_utils.isString)(received) ? "string" : "Buffer", expectation: "expected" });
222
+ return helper.handleDifferent(received, expected, void 0, result.diff, header, result.errorMessage, void 0, this._stepInfo);
285
223
  }
286
224
  function toHaveScreenshotStepTitle(nameOrOptions = {}, optOptions = {}) {
287
225
  let name;
288
226
  if (typeof nameOrOptions === "object" && !Array.isArray(nameOrOptions))
289
227
  name = nameOrOptions.name;
290
- else name = nameOrOptions;
228
+ else
229
+ name = nameOrOptions;
291
230
  return Array.isArray(name) ? name.join(import_path.default.sep) : name || "";
292
231
  }
293
232
  async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions = {}) {
@@ -295,30 +234,13 @@ async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions =
295
234
  if (!testInfo)
296
235
  throw new Error(`toHaveScreenshot() must be called during the test`);
297
236
  if (testInfo._projectInternal.ignoreSnapshots)
298
- return {
299
- pass: !this.isNot,
300
- message: () => "",
301
- name: "toHaveScreenshot",
302
- expected: nameOrOptions
303
- };
237
+ return { pass: !this.isNot, message: () => "", name: "toHaveScreenshot", expected: nameOrOptions };
304
238
  (0, import_util.expectTypes)(pageOrLocator, ["Page", "Locator"], "toHaveScreenshot");
305
239
  const [page, locator] = pageOrLocator.constructor.name === "Page" ? [pageOrLocator, void 0] : [pageOrLocator.page(), pageOrLocator];
306
240
  const configOptions = testInfo._projectInternal.expect?.toHaveScreenshot || {};
307
- const helper = new SnapshotHelper(
308
- testInfo,
309
- "toHaveScreenshot",
310
- locator,
311
- void 0,
312
- configOptions,
313
- nameOrOptions,
314
- optOptions
315
- );
241
+ const helper = new SnapshotHelper(testInfo, "toHaveScreenshot", locator, void 0, configOptions, nameOrOptions, optOptions);
316
242
  if (!helper.expectedPath.toLowerCase().endsWith(".png"))
317
- throw new Error(
318
- `Screenshot name "${import_path.default.basename(
319
- helper.expectedPath
320
- )}" must have '.png' extension`
321
- );
243
+ throw new Error(`Screenshot name "${import_path.default.basename(helper.expectedPath)}" must have '.png' extension`);
322
244
  (0, import_util.expectTypes)(pageOrLocator, ["Page", "Locator"], "toHaveScreenshot");
323
245
  const style = await loadScreenshotStyles(helper.options.stylePath);
324
246
  const timeout = helper.options.timeout ?? this.timeout;
@@ -342,38 +264,19 @@ async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions =
342
264
  };
343
265
  const hasSnapshot = import_fs.default.existsSync(helper.expectedPath);
344
266
  if (this.isNot) {
345
- if (!hasSnapshot) return helper.handleMissingNegated();
346
- expectScreenshotOptions.expected = await import_fs.default.promises.readFile(
347
- helper.expectedPath
348
- );
267
+ if (!hasSnapshot)
268
+ return helper.handleMissingNegated();
269
+ expectScreenshotOptions.expected = await import_fs.default.promises.readFile(helper.expectedPath);
349
270
  const isDifferent = !(await page._expectScreenshot(expectScreenshotOptions)).errorMessage;
350
271
  return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
351
272
  }
352
273
  if (helper.updateSnapshots === "none" && !hasSnapshot)
353
- return helper.createMatcherResult(
354
- `A snapshot doesn't exist at ${helper.expectedPath}.`,
355
- false
356
- );
274
+ return helper.createMatcherResult(`A snapshot doesn't exist at ${helper.expectedPath}.`, false);
357
275
  if (!hasSnapshot) {
358
276
  const { actual: actual2, previous: previous2, diff: diff2, errorMessage: errorMessage2, log: log2, timedOut: timedOut2 } = await page._expectScreenshot(expectScreenshotOptions);
359
277
  if (errorMessage2) {
360
- const header2 = (0, import_matcherHint.formatMatcherMessage)(this, {
361
- matcherName: "toHaveScreenshot",
362
- locator,
363
- expectation: "expected",
364
- timeout,
365
- timedOut: timedOut2
366
- });
367
- return helper.handleDifferent(
368
- actual2,
369
- void 0,
370
- previous2,
371
- diff2,
372
- header2,
373
- errorMessage2,
374
- log2,
375
- this._stepInfo
376
- );
278
+ const header2 = (0, import_matcherHint.formatMatcherMessage)(this, { matcherName: "toHaveScreenshot", locator, expectation: "expected", timeout, timedOut: timedOut2 });
279
+ return helper.handleDifferent(actual2, void 0, previous2, diff2, header2, errorMessage2, log2, this._stepInfo);
377
280
  }
378
281
  return helper.handleMissing(actual2, this._stepInfo);
379
282
  }
@@ -384,10 +287,7 @@ async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions =
384
287
  writeFileSync(helper.expectedPath, actualBuffer);
385
288
  writeFileSync(helper.actualPath, actualBuffer);
386
289
  console.log(helper.expectedPath + " is re-generated, writing actual.");
387
- return helper.createMatcherResult(
388
- helper.expectedPath + " running with --update-snapshots, writing actual.",
389
- true
390
- );
290
+ return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
391
291
  };
392
292
  if (!errorMessage) {
393
293
  if (helper.updateSnapshots === "all" && actual && (0, import_utils.compareBuffersOrStrings)(actual, expected)) {
@@ -397,75 +297,30 @@ async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions =
397
297
  return helper.handleMatching();
398
298
  }
399
299
  if (helper.updateSnapshots === "changed" || helper.updateSnapshots === "all") {
400
- if (actual) return writeFiles(actual);
401
- let header2 = (0, import_matcherHint.formatMatcherMessage)(this, {
402
- matcherName: "toHaveScreenshot",
403
- locator,
404
- expectation: "expected",
405
- timeout,
406
- timedOut
407
- });
300
+ if (actual)
301
+ return writeFiles(actual);
302
+ let header2 = (0, import_matcherHint.formatMatcherMessage)(this, { matcherName: "toHaveScreenshot", locator, expectation: "expected", timeout, timedOut });
408
303
  header2 += " Failed to re-generate expected.\n";
409
- return helper.handleDifferent(
410
- actual,
411
- expectScreenshotOptions.expected,
412
- previous,
413
- diff,
414
- header2,
415
- errorMessage,
416
- log,
417
- this._stepInfo
418
- );
304
+ return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header2, errorMessage, log, this._stepInfo);
419
305
  }
420
306
  if (helper.options.autoHeal ?? (0, import_healingService.isScreenshotHealingEnabled)()) {
421
307
  if (actual && expected) {
422
308
  try {
423
- const aiScreenshotMatchJudgement = await (0, import_healingService.attemptToHaveScreenshotHealing)(
424
- {
425
- actualScreenshot: actual,
426
- expectedScreenshot: expected
427
- }
428
- );
429
- if (aiScreenshotMatchJudgement) return helper.handleMatching();
430
- } catch (healingError) {
431
- const header2 = (0, import_matcherHint.formatMatcherMessage)(this, {
432
- matcherName: "toHaveScreenshot",
433
- locator,
434
- expectation: "expected",
435
- timeout,
436
- timedOut
309
+ const aiScreenshotMatchJudgement = await (0, import_healingService.attemptToHaveScreenshotHealing)({
310
+ actualScreenshot: actual,
311
+ expectedScreenshot: expected
437
312
  });
313
+ if (aiScreenshotMatchJudgement)
314
+ return helper.handleMatching();
315
+ } catch (healingError) {
316
+ const header2 = (0, import_matcherHint.formatMatcherMessage)(this, { matcherName: "toHaveScreenshot", locator, expectation: "expected", timeout, timedOut });
438
317
  const healErrorMessage = `Screenshot healing failed: ${healingError instanceof Error ? healingError.message : String(healingError)}`;
439
- return helper.handleDifferent(
440
- actual,
441
- expectScreenshotOptions.expected,
442
- previous,
443
- diff,
444
- header2,
445
- healErrorMessage,
446
- log,
447
- this._stepInfo
448
- );
318
+ return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header2, healErrorMessage, log, this._stepInfo);
449
319
  }
450
320
  }
451
321
  }
452
- const header = (0, import_matcherHint.formatMatcherMessage)(this, {
453
- matcherName: "toHaveScreenshot",
454
- locator,
455
- expectation: "expected",
456
- timeout,
457
- timedOut
458
- });
459
- return helper.handleDifferent(
460
- actual,
461
- expectScreenshotOptions.expected,
462
- previous,
463
- diff,
464
- header,
465
- errorMessage,
466
- log,
467
- this._stepInfo
468
- );
322
+ const header = (0, import_matcherHint.formatMatcherMessage)(this, { matcherName: "toHaveScreenshot", locator, expectation: "expected", timeout, timedOut });
323
+ return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header, errorMessage, log, this._stepInfo);
469
324
  }
470
325
  function writeFileSync(aPath, content) {
471
326
  import_fs.default.mkdirSync(import_path.default.dirname(aPath), { recursive: true });
@@ -475,27 +330,25 @@ function indent(lines, tab) {
475
330
  return lines.replace(/^(?=.+$)/gm, tab);
476
331
  }
477
332
  function determineFileExtension(file) {
478
- if (typeof file === "string") return "txt";
333
+ if (typeof file === "string")
334
+ return "txt";
479
335
  if (compareMagicBytes(file, [137, 80, 78, 71, 13, 10, 26, 10]))
480
336
  return "png";
481
- if (compareMagicBytes(file, [255, 216, 255])) return "jpg";
337
+ if (compareMagicBytes(file, [255, 216, 255]))
338
+ return "jpg";
482
339
  return "dat";
483
340
  }
484
341
  function compareMagicBytes(file, magicBytes) {
485
- return Buffer.compare(
486
- Buffer.from(magicBytes),
487
- file.slice(0, magicBytes.length)
488
- ) === 0;
342
+ return Buffer.compare(Buffer.from(magicBytes), file.slice(0, magicBytes.length)) === 0;
489
343
  }
490
344
  async function loadScreenshotStyles(stylePath) {
491
- if (!stylePath) return;
345
+ if (!stylePath)
346
+ return;
492
347
  const stylePaths = Array.isArray(stylePath) ? stylePath : [stylePath];
493
- const styles = await Promise.all(
494
- stylePaths.map(async (stylePath2) => {
495
- const text = await import_fs.default.promises.readFile(stylePath2, "utf8");
496
- return text.trim();
497
- })
498
- );
348
+ const styles = await Promise.all(stylePaths.map(async (stylePath2) => {
349
+ const text = await import_fs.default.promises.readFile(stylePath2, "utf8");
350
+ return text.trim();
351
+ }));
499
352
  return styles.join("\n").trim() || void 0;
500
353
  }
501
354
  // Annotate the CommonJS export names for ESM import in node:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stablyai/internal-playwright",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "A high-level API to automate web browsers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "license": "Apache-2.0",
68
68
  "dependencies": {
69
- "playwright-core": "npm:@stablyai/internal-playwright-core@0.1.13"
69
+ "playwright-core": "npm:@stablyai/internal-playwright-core@0.1.15"
70
70
  },
71
71
  "optionalDependencies": {
72
72
  "fsevents": "2.3.2"