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