@argos-ci/vitest 0.4.7 → 0.6.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/index.d.mts +3 -3
- package/dist/index.mjs +100 -44
- package/dist/internal.d.mts +16 -5
- package/dist/internal.mjs +88 -17
- package/dist/plugin.d.mts +3 -4
- package/dist/plugin.mjs +96 -23
- package/dist/{snapshot-file-D8dL3z_T.mjs → snapshot-file-CZE4r9Wl.mjs} +4 -3
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "@argos-ci/core";
|
|
2
1
|
import { ScreenshotMetadata } from "@argos-ci/util";
|
|
2
|
+
import "@argos-ci/core";
|
|
3
3
|
import { ArgosAttachment } from "@argos-ci/playwright";
|
|
4
4
|
import { StabilizationPluginOptions, ViewportOption } from "@argos-ci/browser";
|
|
5
5
|
//#region src/metadata.d.ts
|
|
@@ -142,8 +142,8 @@ type SerializableSnapshotOptions = Omit<VitestSnapshotOptions, "serialize" | "na
|
|
|
142
142
|
//#region src/index.d.ts
|
|
143
143
|
declare module "vitest/browser" {
|
|
144
144
|
interface BrowserCommands {
|
|
145
|
-
argosScreenshot: (name: string, options?: VitestScreenshotOptions, test?: TestMetadata) => Promise<ArgosAttachment[]>;
|
|
146
|
-
argosSnapshot: (name: string, content: string, options?: SerializableSnapshotOptions, test?: TestMetadata) => Promise<ArgosAttachment[]>;
|
|
145
|
+
argosScreenshot: (name: string, options?: VitestScreenshotOptions, test?: TestMetadata, captureIndex?: number | null) => Promise<ArgosAttachment[]>;
|
|
146
|
+
argosSnapshot: (name: string, content: string, options?: SerializableSnapshotOptions, test?: TestMetadata, captureIndex?: number | null) => Promise<ArgosAttachment[]>;
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
|
+
import { getTestRunKey, nextCaptureIndex } from "@argos-ci/util";
|
|
1
2
|
//#region src/test-context.ts
|
|
2
3
|
/**
|
|
4
|
+
* Entry point exposing `getCurrentTest` before Vitest 4.1, and removed
|
|
5
|
+
* altogether in Vitest 5.
|
|
6
|
+
*
|
|
7
|
+
* Held in a variable rather than written inline at the import: Vite's
|
|
8
|
+
* dependency pre-bundler resolves a literal specifier eagerly, and on Vitest 5
|
|
9
|
+
* that fails the whole optimize step over an export that no longer exists —
|
|
10
|
+
* even though the branch importing it cannot run there.
|
|
11
|
+
*/
|
|
12
|
+
const LEGACY_SUITE_ENTRY = "vitest/suite";
|
|
13
|
+
/**
|
|
3
14
|
* Get the current Vitest test task, or `undefined` when not inside a test.
|
|
4
15
|
*
|
|
5
16
|
* Vitest >= 4.1 exposes `TestRunner.getCurrentTest()` from the `vitest` entry
|
|
6
|
-
* point; the `vitest/suite` export is deprecated
|
|
7
|
-
* fall back to `vitest/suite` for older 4.x. Both are
|
|
8
|
-
* importing `@argos-ci/vitest` in a non-Vitest
|
|
9
|
-
* in — only call this once you know Vitest is
|
|
17
|
+
* point; the `vitest/suite` export is deprecated there and gone in Vitest 5. We
|
|
18
|
+
* prefer the new API and fall back to `vitest/suite` for older 4.x. Both are
|
|
19
|
+
* imported dynamically so importing `@argos-ci/vitest` in a non-Vitest
|
|
20
|
+
* environment does not pull Vitest in — only call this once you know Vitest is
|
|
21
|
+
* available.
|
|
10
22
|
*/
|
|
11
23
|
async function getCurrentTest() {
|
|
12
24
|
const runner = (await import("vitest")).TestRunner;
|
|
13
25
|
if (runner?.getCurrentTest) return runner.getCurrentTest();
|
|
14
|
-
return (await import(
|
|
26
|
+
return (await import(
|
|
27
|
+
/* @vite-ignore */
|
|
28
|
+
LEGACY_SUITE_ENTRY
|
|
29
|
+
)).getCurrentTest();
|
|
15
30
|
}
|
|
16
31
|
//#endregion
|
|
17
32
|
//#region src/auto-name.ts
|
|
@@ -137,6 +152,23 @@ async function getTestMetadata() {
|
|
|
137
152
|
if (!task) return null;
|
|
138
153
|
return buildTestMetadata(task);
|
|
139
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Take the next capture index for the current Vitest test, or `null` outside a
|
|
157
|
+
* test. Screenshots and snapshots share the counter, so a test that mixes both
|
|
158
|
+
* still numbers them in the order it produced them.
|
|
159
|
+
*
|
|
160
|
+
* Runs on the test side, where the test context is available; the number then
|
|
161
|
+
* crosses the RPC boundary to the Node command.
|
|
162
|
+
*/
|
|
163
|
+
async function takeCaptureIndex() {
|
|
164
|
+
const task = await getCurrentTest();
|
|
165
|
+
if (!task) return null;
|
|
166
|
+
return nextCaptureIndex(getTestRunKey({
|
|
167
|
+
id: task.id,
|
|
168
|
+
retry: task.result?.retryCount ?? void 0,
|
|
169
|
+
repeat: task.result?.repeatCount ?? void 0
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
140
172
|
//#endregion
|
|
141
173
|
//#region ../../node_modules/.pnpm/tinyrainbow@3.1.1/node_modules/tinyrainbow/dist/index.js
|
|
142
174
|
var b = {
|
|
@@ -221,7 +253,7 @@ function C({ force: e } = {}) {
|
|
|
221
253
|
}
|
|
222
254
|
var y = C();
|
|
223
255
|
//#endregion
|
|
224
|
-
//#region ../../node_modules/.pnpm/@vitest+pretty-format@
|
|
256
|
+
//#region ../../node_modules/.pnpm/@vitest+pretty-format@5.0.0/node_modules/@vitest/pretty-format/dist/index.js
|
|
225
257
|
function _mergeNamespaces(n, m) {
|
|
226
258
|
m.forEach(function(e) {
|
|
227
259
|
e && typeof e !== "string" && !Array.isArray(e) && Object.keys(e).forEach(function(k) {
|
|
@@ -251,7 +283,7 @@ function getKeysOfEnumerableProperties(object, compareKeys) {
|
|
|
251
283
|
* with spacing, indentation, and comma
|
|
252
284
|
* without surrounding punctuation (for example, braces)
|
|
253
285
|
*/
|
|
254
|
-
function printIteratorEntries(iterator, config, indentation, depth, refs, printer, separator = ": ") {
|
|
286
|
+
function printIteratorEntries(iterator, config, indentation, depth, refs, printer, separator = ": ", length) {
|
|
255
287
|
let result = "";
|
|
256
288
|
let width = 0;
|
|
257
289
|
let current = iterator.next();
|
|
@@ -261,7 +293,7 @@ function printIteratorEntries(iterator, config, indentation, depth, refs, printe
|
|
|
261
293
|
while (!current.done) {
|
|
262
294
|
result += indentationNext;
|
|
263
295
|
if (width++ === config.maxWidth) {
|
|
264
|
-
result += "…";
|
|
296
|
+
result += typeof length === "number" ? `…(${length - width + 1})` : "…";
|
|
265
297
|
break;
|
|
266
298
|
}
|
|
267
299
|
const name = printer(current.value[0], config, indentationNext, depth, refs);
|
|
@@ -280,7 +312,7 @@ function printIteratorEntries(iterator, config, indentation, depth, refs, printe
|
|
|
280
312
|
* with spacing, indentation, and comma
|
|
281
313
|
* without surrounding punctuation (braces or brackets)
|
|
282
314
|
*/
|
|
283
|
-
function printIteratorValues(iterator, config, indentation, depth, refs, printer) {
|
|
315
|
+
function printIteratorValues(iterator, config, indentation, depth, refs, printer, length) {
|
|
284
316
|
let result = "";
|
|
285
317
|
let width = 0;
|
|
286
318
|
let current = iterator.next();
|
|
@@ -290,7 +322,7 @@ function printIteratorValues(iterator, config, indentation, depth, refs, printer
|
|
|
290
322
|
while (!current.done) {
|
|
291
323
|
result += indentationNext;
|
|
292
324
|
if (width++ === config.maxWidth) {
|
|
293
|
-
result += "…";
|
|
325
|
+
result += typeof length === "number" ? `…(${length - width + 1})` : "…";
|
|
294
326
|
break;
|
|
295
327
|
}
|
|
296
328
|
result += printer(current.value, config, indentationNext, depth, refs);
|
|
@@ -318,7 +350,7 @@ function printListItems(list, config, indentation, depth, refs, printer) {
|
|
|
318
350
|
for (let i = 0; i < length; i++) {
|
|
319
351
|
result += indentationNext;
|
|
320
352
|
if (i === config.maxWidth) {
|
|
321
|
-
result +=
|
|
353
|
+
result += `…(${length - i})`;
|
|
322
354
|
break;
|
|
323
355
|
}
|
|
324
356
|
if (isDataView(list) || i in list) result += printer(isDataView(list) ? list.getInt8(i) : list[i], config, indentationNext, depth, refs);
|
|
@@ -334,17 +366,22 @@ function printListItems(list, config, indentation, depth, refs, printer) {
|
|
|
334
366
|
* with spacing, indentation, and comma
|
|
335
367
|
* without surrounding punctuation (for example, braces)
|
|
336
368
|
*/
|
|
337
|
-
function printObjectProperties(val, config, indentation, depth, refs, printer) {
|
|
369
|
+
function printObjectProperties(val, config, indentation, depth, refs, printer, compareKeysOverride = config.compareKeys) {
|
|
338
370
|
let result = "";
|
|
339
|
-
const keys = getKeysOfEnumerableProperties(val,
|
|
371
|
+
const keys = getKeysOfEnumerableProperties(val, compareKeysOverride);
|
|
340
372
|
if (keys.length > 0) {
|
|
341
373
|
result += config.spacingOuter;
|
|
342
374
|
const indentationNext = indentation + config.indent;
|
|
343
375
|
for (let i = 0; i < keys.length; i++) {
|
|
376
|
+
result += indentationNext;
|
|
377
|
+
if (i === config.maxWidth) {
|
|
378
|
+
result += `…(${keys.length - i})`;
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
344
381
|
const key = keys[i];
|
|
345
|
-
const name = printer(key, config, indentationNext, depth, refs);
|
|
382
|
+
const name = !config.quoteKeys && isUnquotableKey(key) ? key : printer(key, config, indentationNext, depth, refs);
|
|
346
383
|
const value = printer(val[key], config, indentationNext, depth, refs);
|
|
347
|
-
result += `${
|
|
384
|
+
result += `${name}: ${value}`;
|
|
348
385
|
if (i < keys.length - 1) result += `,${config.spacingInner}`;
|
|
349
386
|
else if (!config.min) result += ",";
|
|
350
387
|
}
|
|
@@ -352,6 +389,10 @@ function printObjectProperties(val, config, indentation, depth, refs, printer) {
|
|
|
352
389
|
}
|
|
353
390
|
return result;
|
|
354
391
|
}
|
|
392
|
+
const keyStrRegExp = /^[a-z_]\w*$/i;
|
|
393
|
+
function isUnquotableKey(key) {
|
|
394
|
+
return typeof key === "string" && key !== "__proto__" && keyStrRegExp.test(key);
|
|
395
|
+
}
|
|
355
396
|
const asymmetricMatcher = typeof Symbol === "function" && Symbol.for ? Symbol.for("jest.asymmetricMatcher") : 1267621;
|
|
356
397
|
const SPACE$2 = " ";
|
|
357
398
|
const serialize$5 = (val, config, indentation, depth, refs, printer) => {
|
|
@@ -410,7 +451,7 @@ function printProps(keys, props, config, indentation, depth, refs, printer) {
|
|
|
410
451
|
const colors = config.colors;
|
|
411
452
|
return keys.map((key) => {
|
|
412
453
|
const value = props[key];
|
|
413
|
-
if (typeof value === "string" && value[0] === "_" && value.startsWith("__vitest_") &&
|
|
454
|
+
if (typeof value === "string" && value[0] === "_" && value.startsWith("__vitest_") && /__vitest_\d+__/.test(value)) return "";
|
|
414
455
|
let printed = printer(value, config, indentationNext, depth, refs);
|
|
415
456
|
if (typeof value !== "string") {
|
|
416
457
|
if (printed.includes("\n")) printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation;
|
|
@@ -887,7 +928,7 @@ function printError(val) {
|
|
|
887
928
|
* The first port of call for printing an object, handles most of the
|
|
888
929
|
* data-types in JS.
|
|
889
930
|
*/
|
|
890
|
-
function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
|
|
931
|
+
function printBasicValue(val, printFunctionName, escapeRegex, escapeString, singleQuote) {
|
|
891
932
|
if (val === true || val === false) return `${val}`;
|
|
892
933
|
if (val === void 0) return "undefined";
|
|
893
934
|
if (val === null) return "null";
|
|
@@ -895,8 +936,12 @@ function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
|
|
|
895
936
|
if (typeOf === "number") return printNumber(val);
|
|
896
937
|
if (typeOf === "bigint") return printBigInt(val);
|
|
897
938
|
if (typeOf === "string") {
|
|
898
|
-
|
|
899
|
-
|
|
939
|
+
const q = singleQuote ? "'" : "\"";
|
|
940
|
+
if (escapeString) {
|
|
941
|
+
const escapePattern = singleQuote ? /['\\]/g : /["\\]/g;
|
|
942
|
+
return `${q}${val.replaceAll(escapePattern, "\\$&")}${q}`;
|
|
943
|
+
}
|
|
944
|
+
return `${q}${val}${q}`;
|
|
900
945
|
}
|
|
901
946
|
if (typeOf === "function") return printFunction(val, printFunctionName);
|
|
902
947
|
if (typeOf === "symbol") return printSymbol(val);
|
|
@@ -927,10 +972,10 @@ function printComplexValue(val, config, indentation, depth, refs, hasCalledToJSO
|
|
|
927
972
|
if (config.callToJSON && !hitMaxDepth && val.toJSON && typeof val.toJSON === "function" && !hasCalledToJSON) return printer(val.toJSON(), config, indentation, depth, refs, true);
|
|
928
973
|
const toStringed = toString.call(val);
|
|
929
974
|
if (toStringed === "[object Arguments]") return hitMaxDepth ? "[Arguments]" : `${min ? "" : "Arguments "}[${printListItems(val, config, indentation, depth, refs, printer)}]`;
|
|
930
|
-
if (isToStringedArrayType(toStringed)) return hitMaxDepth ? `[${val.constructor.name}]` : `${
|
|
931
|
-
if (toStringed === "[object Map]") return hitMaxDepth ? "[Map]" : `Map {${printIteratorEntries(val.entries(), config, indentation, depth, refs, printer, " => ")}}`;
|
|
932
|
-
if (toStringed === "[object Set]") return hitMaxDepth ? "[Set]" : `Set {${printIteratorValues(val.values(), config, indentation, depth, refs, printer)}}`;
|
|
933
|
-
return hitMaxDepth || isWindow(val) ? `[${getConstructorName(val)}]` : `${
|
|
975
|
+
if (isToStringedArrayType(toStringed)) return hitMaxDepth ? `[${val.constructor.name}]` : `${!config.printBasicPrototype && val.constructor.name === "Array" ? "" : `${val.constructor.name} `}[${printListItems(val, config, indentation, depth, refs, printer)}]`;
|
|
976
|
+
if (toStringed === "[object Map]") return hitMaxDepth ? "[Map]" : `Map {${printIteratorEntries(val.entries(), config, indentation, depth, refs, printer, " => ", val.size)}}`;
|
|
977
|
+
if (toStringed === "[object Set]") return hitMaxDepth ? "[Set]" : `Set {${printIteratorValues(val.values(), config, indentation, depth, refs, printer, val.size)}}`;
|
|
978
|
+
return hitMaxDepth || isWindow(val) ? `[${getConstructorName(val)}]` : `${!config.printBasicPrototype && getConstructorName(val) === "Object" ? "" : `${getConstructorName(val)} `}{${printObjectProperties(val, config, indentation, depth, refs, printer)}}`;
|
|
934
979
|
}
|
|
935
980
|
const ErrorPlugin = {
|
|
936
981
|
test: (val) => val && val instanceof Error,
|
|
@@ -946,7 +991,7 @@ const ErrorPlugin = {
|
|
|
946
991
|
...rest
|
|
947
992
|
};
|
|
948
993
|
const name = val.name !== "Error" ? val.name : getConstructorName(val);
|
|
949
|
-
return hitMaxDepth ? `[${name}]` : `${name} {${
|
|
994
|
+
return hitMaxDepth ? `[${name}]` : `${name} {${printObjectProperties(entries, config, indentation, depth, refs, printer, null)}}`;
|
|
950
995
|
}
|
|
951
996
|
};
|
|
952
997
|
function isNewPlugin(plugin) {
|
|
@@ -982,7 +1027,7 @@ function printer(val, config, indentation, depth, refs, hasCalledToJSON) {
|
|
|
982
1027
|
const plugin = findPlugin(config.plugins, val);
|
|
983
1028
|
if (plugin !== null) result = printPlugin(plugin, val, config, indentation, depth, refs);
|
|
984
1029
|
else {
|
|
985
|
-
const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString);
|
|
1030
|
+
const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString, config.singleQuote);
|
|
986
1031
|
if (basicResult !== null) result = basicResult;
|
|
987
1032
|
else result = printComplexValue(val, config, indentation, depth, refs, hasCalledToJSON);
|
|
988
1033
|
}
|
|
@@ -1014,7 +1059,11 @@ const DEFAULT_OPTIONS = {
|
|
|
1014
1059
|
printBasicPrototype: true,
|
|
1015
1060
|
printFunctionName: true,
|
|
1016
1061
|
printShadowRoot: true,
|
|
1017
|
-
theme: DEFAULT_THEME
|
|
1062
|
+
theme: DEFAULT_THEME,
|
|
1063
|
+
singleQuote: false,
|
|
1064
|
+
quoteKeys: true,
|
|
1065
|
+
spacingInner: "\n",
|
|
1066
|
+
spacingOuter: "\n"
|
|
1018
1067
|
};
|
|
1019
1068
|
function validateOptions(options) {
|
|
1020
1069
|
for (const key of Object.keys(options)) if (!Object.hasOwn(DEFAULT_OPTIONS, key)) throw new Error(`pretty-format: Unknown option "${key}".`);
|
|
@@ -1059,11 +1108,13 @@ function getConfig(options) {
|
|
|
1059
1108
|
maxWidth: options?.maxWidth ?? DEFAULT_OPTIONS.maxWidth,
|
|
1060
1109
|
min: options?.min ?? DEFAULT_OPTIONS.min,
|
|
1061
1110
|
plugins: options?.plugins ?? DEFAULT_OPTIONS.plugins,
|
|
1062
|
-
printBasicPrototype: options?.printBasicPrototype ??
|
|
1111
|
+
printBasicPrototype: options?.printBasicPrototype ?? !options?.min,
|
|
1063
1112
|
printFunctionName: getPrintFunctionName(options),
|
|
1064
1113
|
printShadowRoot: options?.printShadowRoot ?? true,
|
|
1065
|
-
spacingInner: options?.min ? " " : "\n",
|
|
1066
|
-
spacingOuter: options?.min ? "" : "\n",
|
|
1114
|
+
spacingInner: options?.spacingInner ?? (options?.min ? " " : "\n"),
|
|
1115
|
+
spacingOuter: options?.spacingOuter ?? (options?.min ? "" : "\n"),
|
|
1116
|
+
singleQuote: options?.singleQuote ?? DEFAULT_OPTIONS.singleQuote,
|
|
1117
|
+
quoteKeys: options?.quoteKeys ?? DEFAULT_OPTIONS.quoteKeys,
|
|
1067
1118
|
maxOutputLength: options?.maxOutputLength ?? DEFAULT_OPTIONS.maxOutputLength,
|
|
1068
1119
|
_outputLengthPerDepth: []
|
|
1069
1120
|
};
|
|
@@ -1077,16 +1128,13 @@ function createIndent(indent) {
|
|
|
1077
1128
|
* @param options Custom settings
|
|
1078
1129
|
*/
|
|
1079
1130
|
function format(val, options) {
|
|
1080
|
-
if (options)
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
const basicResult = printBasicValue(val, getPrintFunctionName(options), getEscapeRegex(options), getEscapeString(options));
|
|
1131
|
+
if (options) validateOptions(options);
|
|
1132
|
+
const config = getConfig(options);
|
|
1133
|
+
const plugin = findPlugin(config.plugins, val);
|
|
1134
|
+
if (plugin !== null) return printPlugin(plugin, val, config, "", 0, []);
|
|
1135
|
+
const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString, config.singleQuote);
|
|
1088
1136
|
if (basicResult !== null) return basicResult;
|
|
1089
|
-
return printComplexValue(val,
|
|
1137
|
+
return printComplexValue(val, config, "", 0, []);
|
|
1090
1138
|
}
|
|
1091
1139
|
const plugins = {
|
|
1092
1140
|
AsymmetricMatcher: plugin$5,
|
|
@@ -1142,9 +1190,13 @@ async function argosScreenshot(nameOrOptions, maybeOptions) {
|
|
|
1142
1190
|
const name = typeof nameOrOptions === "string" ? nameOrOptions : void 0;
|
|
1143
1191
|
const options = typeof nameOrOptions === "string" ? maybeOptions : nameOrOptions;
|
|
1144
1192
|
if (!await checkIsVitestEnv()) return [];
|
|
1145
|
-
const [resolvedName, test] = await Promise.all([
|
|
1193
|
+
const [resolvedName, test, captureIndex] = await Promise.all([
|
|
1194
|
+
resolveAutoName(name, { reservedLength: SCREENSHOT_NAME_RESERVED }),
|
|
1195
|
+
getTestMetadata(),
|
|
1196
|
+
takeCaptureIndex()
|
|
1197
|
+
]);
|
|
1146
1198
|
const { server } = await import("vitest/browser");
|
|
1147
|
-
return server.commands.argosScreenshot(resolvedName, options ?? {}, test);
|
|
1199
|
+
return server.commands.argosScreenshot(resolvedName, options ?? {}, test, captureIndex);
|
|
1148
1200
|
}
|
|
1149
1201
|
/**
|
|
1150
1202
|
* Take an Argos snapshot of any serializable value, mimicking
|
|
@@ -1181,15 +1233,19 @@ async function argosSnapshot(content, options = {}) {
|
|
|
1181
1233
|
if (!await checkIsVitestEnv()) return [];
|
|
1182
1234
|
const rawExtension = options.extension ?? ".txt";
|
|
1183
1235
|
const extension = rawExtension.startsWith(".") ? rawExtension : `.${rawExtension}`;
|
|
1184
|
-
const [resolvedName, test] = await Promise.all([
|
|
1236
|
+
const [resolvedName, test, captureIndex] = await Promise.all([
|
|
1237
|
+
resolveAutoName(options.name, { reservedLength: 9 + extension.length + 11 }),
|
|
1238
|
+
getTestMetadata(),
|
|
1239
|
+
takeCaptureIndex()
|
|
1240
|
+
]);
|
|
1185
1241
|
const serialized = serializeSnapshot(content, options);
|
|
1186
1242
|
const { serialize: _serialize, name: _name, ...serializableOptions } = options;
|
|
1187
1243
|
if (checkIsBrowserEnv()) {
|
|
1188
1244
|
const { server } = await import("vitest/browser");
|
|
1189
|
-
return server.commands.argosSnapshot(resolvedName, serialized, serializableOptions, test);
|
|
1245
|
+
return server.commands.argosSnapshot(resolvedName, serialized, serializableOptions, test, captureIndex);
|
|
1190
1246
|
}
|
|
1191
|
-
const { writeSnapshotFile } = await import("./snapshot-file-
|
|
1192
|
-
return writeSnapshotFile(resolvedName, serialized, serializableOptions, test);
|
|
1247
|
+
const { writeSnapshotFile } = await import("./snapshot-file-CZE4r9Wl.mjs");
|
|
1248
|
+
return writeSnapshotFile(resolvedName, serialized, serializableOptions, test, captureIndex);
|
|
1193
1249
|
}
|
|
1194
1250
|
/**
|
|
1195
1251
|
* Check if we are running in a Vitest environment.
|
package/dist/internal.d.mts
CHANGED
|
@@ -7,14 +7,25 @@ import { ViewportSize } from "@argos-ci/browser";
|
|
|
7
7
|
*/
|
|
8
8
|
declare const VITEST_IFRAME_SELECTOR = "iframe[data-vitest=\"true\"]";
|
|
9
9
|
/**
|
|
10
|
-
* ID of the Vitest "tester" element
|
|
11
|
-
* transform.
|
|
10
|
+
* ID of the Vitest "tester" element wrapping the iframe.
|
|
12
11
|
*/
|
|
13
12
|
declare const VITEST_TESTER_ID = "vitest-tester";
|
|
14
13
|
/**
|
|
15
|
-
*
|
|
16
|
-
* screenshot
|
|
17
|
-
*
|
|
14
|
+
* Undo the scale Vitest applies to the `#vitest-tester` element, so the
|
|
15
|
+
* screenshot is captured at full size instead of shrunk.
|
|
16
|
+
*
|
|
17
|
+
* Only some Vitest versions scale the tester. Up to Vitest 4 a viewport larger
|
|
18
|
+
* than the browser window is emulated by sizing the tester to the requested
|
|
19
|
+
* viewport and shrinking it with a CSS `transform: scale(...)`. From Vitest 5
|
|
20
|
+
* the real browser viewport is resized instead, so the tester carries no
|
|
21
|
+
* transform and there is nothing to undo — which is why an unscaled tester is
|
|
22
|
+
* a no-op rather than an error.
|
|
23
|
+
*
|
|
24
|
+
* Detection reads the *computed* transform, so a scale set from a stylesheet
|
|
25
|
+
* counts too, while the override goes on the inline style, which is the only
|
|
26
|
+
* layer guaranteed to win.
|
|
27
|
+
*
|
|
28
|
+
* @returns A function restoring the transform after the screenshot.
|
|
18
29
|
*/
|
|
19
30
|
declare function resetTesterScale(ctx: BrowserCommandContext): Promise<() => Promise<void>>;
|
|
20
31
|
/**
|
package/dist/internal.mjs
CHANGED
|
@@ -7,11 +7,30 @@ import { readVersionFromPackage } from "@argos-ci/util";
|
|
|
7
7
|
*/
|
|
8
8
|
const VITEST_IFRAME_SELECTOR = "iframe[data-vitest=\"true\"]";
|
|
9
9
|
/**
|
|
10
|
-
* ID of the Vitest "tester" element
|
|
11
|
-
* transform.
|
|
10
|
+
* ID of the Vitest "tester" element wrapping the iframe.
|
|
12
11
|
*/
|
|
13
12
|
const VITEST_TESTER_ID = "vitest-tester";
|
|
14
13
|
/**
|
|
14
|
+
* Dataset key holding the tester's inline `transform` from before Argos reset
|
|
15
|
+
* it.
|
|
16
|
+
*
|
|
17
|
+
* The presence of the key — not the value it holds — is what marks the
|
|
18
|
+
* transform as backed up: the original inline `transform` is usually an empty
|
|
19
|
+
* string, which is indistinguishable from "nothing was saved yet".
|
|
20
|
+
*/
|
|
21
|
+
const TRANSFORM_BACKUP_KEY = "argosBckTransform";
|
|
22
|
+
/**
|
|
23
|
+
* Dataset key counting the screenshots currently holding the tester unscaled.
|
|
24
|
+
*
|
|
25
|
+
* Captures nest: a story calling `argosScreenshot` from its play function runs
|
|
26
|
+
* one inside the automatic screenshot taken after the test. Both share this one
|
|
27
|
+
* element, so without a count the inner restore would hand the scale back while
|
|
28
|
+
* the outer capture is still to come — and the outer screenshot would come out
|
|
29
|
+
* shrunk. Only the first reset saves and overrides the transform, and only the
|
|
30
|
+
* last restore puts it back.
|
|
31
|
+
*/
|
|
32
|
+
const SCALE_HOLD_KEY = "argosScaleHold";
|
|
33
|
+
/**
|
|
15
34
|
* Attribute holding the iframe's inline size from before Argos resized it, as
|
|
16
35
|
* JSON.
|
|
17
36
|
*
|
|
@@ -21,27 +40,79 @@ const VITEST_TESTER_ID = "vitest-tester";
|
|
|
21
40
|
*/
|
|
22
41
|
const SIZE_BACKUP_ATTRIBUTE = "data-argos-size-backup";
|
|
23
42
|
/**
|
|
24
|
-
*
|
|
25
|
-
* screenshot
|
|
26
|
-
*
|
|
43
|
+
* Undo the scale Vitest applies to the `#vitest-tester` element, so the
|
|
44
|
+
* screenshot is captured at full size instead of shrunk.
|
|
45
|
+
*
|
|
46
|
+
* Only some Vitest versions scale the tester. Up to Vitest 4 a viewport larger
|
|
47
|
+
* than the browser window is emulated by sizing the tester to the requested
|
|
48
|
+
* viewport and shrinking it with a CSS `transform: scale(...)`. From Vitest 5
|
|
49
|
+
* the real browser viewport is resized instead, so the tester carries no
|
|
50
|
+
* transform and there is nothing to undo — which is why an unscaled tester is
|
|
51
|
+
* a no-op rather than an error.
|
|
52
|
+
*
|
|
53
|
+
* Detection reads the *computed* transform, so a scale set from a stylesheet
|
|
54
|
+
* counts too, while the override goes on the inline style, which is the only
|
|
55
|
+
* layer guaranteed to win.
|
|
56
|
+
*
|
|
57
|
+
* @returns A function restoring the transform after the screenshot.
|
|
27
58
|
*/
|
|
28
59
|
async function resetTesterScale(ctx) {
|
|
29
|
-
await ctx.page.evaluate(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
tester.style.transform = `scale(1)`;
|
|
35
|
-
}, VITEST_TESTER_ID);
|
|
60
|
+
await ctx.page.evaluate(resetTesterScaleInPage, {
|
|
61
|
+
testerId: VITEST_TESTER_ID,
|
|
62
|
+
backupKey: TRANSFORM_BACKUP_KEY,
|
|
63
|
+
holdKey: SCALE_HOLD_KEY
|
|
64
|
+
});
|
|
36
65
|
return async () => {
|
|
37
|
-
await ctx.page.evaluate(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
66
|
+
await ctx.page.evaluate(restoreTesterScaleInPage, {
|
|
67
|
+
testerId: VITEST_TESTER_ID,
|
|
68
|
+
backupKey: TRANSFORM_BACKUP_KEY,
|
|
69
|
+
holdKey: SCALE_HOLD_KEY
|
|
70
|
+
});
|
|
42
71
|
};
|
|
43
72
|
}
|
|
44
73
|
/**
|
|
74
|
+
* Body of {@link resetTesterScale}, running in the page.
|
|
75
|
+
*
|
|
76
|
+
* Exported for tests only, and self-contained on purpose: it is serialized to
|
|
77
|
+
* the browser by `page.evaluate`, so it can reference nothing but its argument
|
|
78
|
+
* and page globals.
|
|
79
|
+
*/
|
|
80
|
+
function resetTesterScaleInPage(args) {
|
|
81
|
+
const { testerId, backupKey, holdKey } = args;
|
|
82
|
+
const tester = document.getElementById(testerId);
|
|
83
|
+
if (!(tester instanceof HTMLElement)) return;
|
|
84
|
+
const held = Number(tester.dataset[holdKey] ?? "0");
|
|
85
|
+
tester.dataset[holdKey] = String(held + 1);
|
|
86
|
+
if (held > 0) return;
|
|
87
|
+
const { transform } = getComputedStyle(tester);
|
|
88
|
+
if (!transform || transform === "none") return;
|
|
89
|
+
const matrix = new DOMMatrixReadOnly(transform);
|
|
90
|
+
if (matrix.a === 1 && matrix.d === 1) return;
|
|
91
|
+
tester.dataset[backupKey] = tester.style.transform;
|
|
92
|
+
tester.style.transform = "scale(1)";
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Body of the function {@link resetTesterScale} returns, running in the page.
|
|
96
|
+
*
|
|
97
|
+
* Exported for tests only, and self-contained for the same reason as
|
|
98
|
+
* {@link resetTesterScaleInPage}.
|
|
99
|
+
*/
|
|
100
|
+
function restoreTesterScaleInPage(args) {
|
|
101
|
+
const { testerId, backupKey, holdKey } = args;
|
|
102
|
+
const tester = document.getElementById(testerId);
|
|
103
|
+
if (!(tester instanceof HTMLElement)) return;
|
|
104
|
+
const held = Math.max(0, Number(tester.dataset[holdKey] ?? "0") - 1);
|
|
105
|
+
if (held > 0) {
|
|
106
|
+
tester.dataset[holdKey] = String(held);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
delete tester.dataset[holdKey];
|
|
110
|
+
const backup = tester.dataset[backupKey];
|
|
111
|
+
if (backup === void 0) return;
|
|
112
|
+
tester.style.transform = backup;
|
|
113
|
+
delete tester.dataset[backupKey];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
45
116
|
* Resize the Vitest iframe.
|
|
46
117
|
*
|
|
47
118
|
* The story/test renders inside an `<iframe data-vitest="true">` on the host
|
package/dist/plugin.d.mts
CHANGED
|
@@ -3,8 +3,7 @@ import { StabilizationPluginOptions, ViewportOption } from "@argos-ci/browser";
|
|
|
3
3
|
import { ScreenshotMetadata } from "@argos-ci/util";
|
|
4
4
|
import { UploadParameters } from "@argos-ci/core";
|
|
5
5
|
import { Plugin } from "vitest/config";
|
|
6
|
-
import { BrowserCommand, Vitest } from "vitest/node";
|
|
7
|
-
import { Reporter } from "vitest/reporters";
|
|
6
|
+
import { BrowserCommand, Reporter, Vitest } from "vitest/node";
|
|
8
7
|
//#region src/options.d.ts
|
|
9
8
|
/**
|
|
10
9
|
* Configuration for the Argos Vitest reporter.
|
|
@@ -174,7 +173,7 @@ type TestMetadata = ScreenshotMetadata["test"];
|
|
|
174
173
|
* Arguments of the `argosScreenshot` browser command.
|
|
175
174
|
* Only serializable values cross the browser/node RPC boundary.
|
|
176
175
|
*/
|
|
177
|
-
type ArgosScreenshotCommandArgs = [name: string, options?: VitestScreenshotOptions, test?: TestMetadata];
|
|
176
|
+
type ArgosScreenshotCommandArgs = [name: string, options?: VitestScreenshotOptions, test?: TestMetadata, captureIndex?: number | null];
|
|
178
177
|
/**
|
|
179
178
|
* Create the `argosScreenshot` browser command used to capture Argos
|
|
180
179
|
* screenshots from Vitest browser tests.
|
|
@@ -191,7 +190,7 @@ declare const createArgosScreenshotCommand: (pluginOptions?: ArgosVitestPluginOp
|
|
|
191
190
|
* Only serializable values cross the browser/node RPC boundary — the value is
|
|
192
191
|
* already serialized to a string on the browser side.
|
|
193
192
|
*/
|
|
194
|
-
type ArgosSnapshotCommandArgs = [name: string, content: string, options?: SerializableSnapshotOptions, test?: TestMetadata];
|
|
193
|
+
type ArgosSnapshotCommandArgs = [name: string, content: string, options?: SerializableSnapshotOptions, test?: TestMetadata, captureIndex?: number | null];
|
|
195
194
|
/**
|
|
196
195
|
* Create the `argosSnapshot` browser command used to write serialized snapshots
|
|
197
196
|
* from Vitest browser tests. The serialized string is produced on the browser
|
package/dist/plugin.mjs
CHANGED
|
@@ -11,11 +11,30 @@ import { getSnapshotMimeType, readConfig, upload } from "@argos-ci/core";
|
|
|
11
11
|
*/
|
|
12
12
|
const VITEST_IFRAME_SELECTOR = "iframe[data-vitest=\"true\"]";
|
|
13
13
|
/**
|
|
14
|
-
* ID of the Vitest "tester" element
|
|
15
|
-
* transform.
|
|
14
|
+
* ID of the Vitest "tester" element wrapping the iframe.
|
|
16
15
|
*/
|
|
17
16
|
const VITEST_TESTER_ID = "vitest-tester";
|
|
18
17
|
/**
|
|
18
|
+
* Dataset key holding the tester's inline `transform` from before Argos reset
|
|
19
|
+
* it.
|
|
20
|
+
*
|
|
21
|
+
* The presence of the key — not the value it holds — is what marks the
|
|
22
|
+
* transform as backed up: the original inline `transform` is usually an empty
|
|
23
|
+
* string, which is indistinguishable from "nothing was saved yet".
|
|
24
|
+
*/
|
|
25
|
+
const TRANSFORM_BACKUP_KEY = "argosBckTransform";
|
|
26
|
+
/**
|
|
27
|
+
* Dataset key counting the screenshots currently holding the tester unscaled.
|
|
28
|
+
*
|
|
29
|
+
* Captures nest: a story calling `argosScreenshot` from its play function runs
|
|
30
|
+
* one inside the automatic screenshot taken after the test. Both share this one
|
|
31
|
+
* element, so without a count the inner restore would hand the scale back while
|
|
32
|
+
* the outer capture is still to come — and the outer screenshot would come out
|
|
33
|
+
* shrunk. Only the first reset saves and overrides the transform, and only the
|
|
34
|
+
* last restore puts it back.
|
|
35
|
+
*/
|
|
36
|
+
const SCALE_HOLD_KEY = "argosScaleHold";
|
|
37
|
+
/**
|
|
19
38
|
* Attribute holding the iframe's inline size from before Argos resized it, as
|
|
20
39
|
* JSON.
|
|
21
40
|
*
|
|
@@ -25,27 +44,79 @@ const VITEST_TESTER_ID = "vitest-tester";
|
|
|
25
44
|
*/
|
|
26
45
|
const SIZE_BACKUP_ATTRIBUTE = "data-argos-size-backup";
|
|
27
46
|
/**
|
|
28
|
-
*
|
|
29
|
-
* screenshot
|
|
30
|
-
*
|
|
47
|
+
* Undo the scale Vitest applies to the `#vitest-tester` element, so the
|
|
48
|
+
* screenshot is captured at full size instead of shrunk.
|
|
49
|
+
*
|
|
50
|
+
* Only some Vitest versions scale the tester. Up to Vitest 4 a viewport larger
|
|
51
|
+
* than the browser window is emulated by sizing the tester to the requested
|
|
52
|
+
* viewport and shrinking it with a CSS `transform: scale(...)`. From Vitest 5
|
|
53
|
+
* the real browser viewport is resized instead, so the tester carries no
|
|
54
|
+
* transform and there is nothing to undo — which is why an unscaled tester is
|
|
55
|
+
* a no-op rather than an error.
|
|
56
|
+
*
|
|
57
|
+
* Detection reads the *computed* transform, so a scale set from a stylesheet
|
|
58
|
+
* counts too, while the override goes on the inline style, which is the only
|
|
59
|
+
* layer guaranteed to win.
|
|
60
|
+
*
|
|
61
|
+
* @returns A function restoring the transform after the screenshot.
|
|
31
62
|
*/
|
|
32
63
|
async function resetTesterScale(ctx) {
|
|
33
|
-
await ctx.page.evaluate(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
tester.style.transform = `scale(1)`;
|
|
39
|
-
}, VITEST_TESTER_ID);
|
|
64
|
+
await ctx.page.evaluate(resetTesterScaleInPage, {
|
|
65
|
+
testerId: VITEST_TESTER_ID,
|
|
66
|
+
backupKey: TRANSFORM_BACKUP_KEY,
|
|
67
|
+
holdKey: SCALE_HOLD_KEY
|
|
68
|
+
});
|
|
40
69
|
return async () => {
|
|
41
|
-
await ctx.page.evaluate(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
70
|
+
await ctx.page.evaluate(restoreTesterScaleInPage, {
|
|
71
|
+
testerId: VITEST_TESTER_ID,
|
|
72
|
+
backupKey: TRANSFORM_BACKUP_KEY,
|
|
73
|
+
holdKey: SCALE_HOLD_KEY
|
|
74
|
+
});
|
|
46
75
|
};
|
|
47
76
|
}
|
|
48
77
|
/**
|
|
78
|
+
* Body of {@link resetTesterScale}, running in the page.
|
|
79
|
+
*
|
|
80
|
+
* Exported for tests only, and self-contained on purpose: it is serialized to
|
|
81
|
+
* the browser by `page.evaluate`, so it can reference nothing but its argument
|
|
82
|
+
* and page globals.
|
|
83
|
+
*/
|
|
84
|
+
function resetTesterScaleInPage(args) {
|
|
85
|
+
const { testerId, backupKey, holdKey } = args;
|
|
86
|
+
const tester = document.getElementById(testerId);
|
|
87
|
+
if (!(tester instanceof HTMLElement)) return;
|
|
88
|
+
const held = Number(tester.dataset[holdKey] ?? "0");
|
|
89
|
+
tester.dataset[holdKey] = String(held + 1);
|
|
90
|
+
if (held > 0) return;
|
|
91
|
+
const { transform } = getComputedStyle(tester);
|
|
92
|
+
if (!transform || transform === "none") return;
|
|
93
|
+
const matrix = new DOMMatrixReadOnly(transform);
|
|
94
|
+
if (matrix.a === 1 && matrix.d === 1) return;
|
|
95
|
+
tester.dataset[backupKey] = tester.style.transform;
|
|
96
|
+
tester.style.transform = "scale(1)";
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Body of the function {@link resetTesterScale} returns, running in the page.
|
|
100
|
+
*
|
|
101
|
+
* Exported for tests only, and self-contained for the same reason as
|
|
102
|
+
* {@link resetTesterScaleInPage}.
|
|
103
|
+
*/
|
|
104
|
+
function restoreTesterScaleInPage(args) {
|
|
105
|
+
const { testerId, backupKey, holdKey } = args;
|
|
106
|
+
const tester = document.getElementById(testerId);
|
|
107
|
+
if (!(tester instanceof HTMLElement)) return;
|
|
108
|
+
const held = Math.max(0, Number(tester.dataset[holdKey] ?? "0") - 1);
|
|
109
|
+
if (held > 0) {
|
|
110
|
+
tester.dataset[holdKey] = String(held);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
delete tester.dataset[holdKey];
|
|
114
|
+
const backup = tester.dataset[backupKey];
|
|
115
|
+
if (backup === void 0) return;
|
|
116
|
+
tester.style.transform = backup;
|
|
117
|
+
delete tester.dataset[backupKey];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
49
120
|
* Resize the Vitest iframe.
|
|
50
121
|
*
|
|
51
122
|
* The story/test renders inside an `<iframe data-vitest="true">` on the host
|
|
@@ -188,7 +259,7 @@ async function getVitestVersion() {
|
|
|
188
259
|
* and are merged with the serializable per-call options (per-call wins).
|
|
189
260
|
*/
|
|
190
261
|
const createArgosScreenshotCommand = (pluginOptions = {}) => {
|
|
191
|
-
return async (ctx, name, options, test) => {
|
|
262
|
+
return async (ctx, name, options, test, captureIndex) => {
|
|
192
263
|
if (!name) throw new Error("The `name` argument is required.");
|
|
193
264
|
const merged = {
|
|
194
265
|
...pluginOptions,
|
|
@@ -208,7 +279,8 @@ const createArgosScreenshotCommand = (pluginOptions = {}) => {
|
|
|
208
279
|
},
|
|
209
280
|
playwrightLibraries: ["vitest"],
|
|
210
281
|
viewport,
|
|
211
|
-
test
|
|
282
|
+
test,
|
|
283
|
+
captureIndex
|
|
212
284
|
});
|
|
213
285
|
};
|
|
214
286
|
const attachments = [];
|
|
@@ -276,7 +348,7 @@ function normalizeExtension(extension) {
|
|
|
276
348
|
* This is the shared Node-side primitive used by both the browser command (which
|
|
277
349
|
* receives the already-serialized string over RPC) and the Node code path.
|
|
278
350
|
*/
|
|
279
|
-
async function writeSnapshotFile(name, content, options = {}, test) {
|
|
351
|
+
async function writeSnapshotFile(name, content, options = {}, test, captureIndex) {
|
|
280
352
|
if (!name) throw new Error("The `name` argument is required.");
|
|
281
353
|
const root = options.root ?? "./snapshots";
|
|
282
354
|
const extension = normalizeExtension(options.extension ?? DEFAULT_EXTENSION);
|
|
@@ -298,7 +370,8 @@ async function writeSnapshotFile(name, content, options = {}, test) {
|
|
|
298
370
|
version: sdkVersion
|
|
299
371
|
},
|
|
300
372
|
...tags ? { tags } : {},
|
|
301
|
-
...resolvedTest ? { test: resolvedTest } : {}
|
|
373
|
+
...resolvedTest ? { test: resolvedTest } : {},
|
|
374
|
+
...captureIndex != null ? { capture: { index: captureIndex } } : {}
|
|
302
375
|
};
|
|
303
376
|
await createDirectory(dirname(snapshotPath));
|
|
304
377
|
await Promise.all([writeFile(snapshotPath, content, "utf-8"), writeMetadata(snapshotPath, metadata)]);
|
|
@@ -320,12 +393,12 @@ async function writeSnapshotFile(name, content, options = {}, test) {
|
|
|
320
393
|
* side and this command writes it (and its metadata) to disk on the Node side.
|
|
321
394
|
*/
|
|
322
395
|
const createArgosSnapshotCommand = (pluginOptions = {}) => {
|
|
323
|
-
return async (_ctx, name, content, options, test) => {
|
|
396
|
+
return async (_ctx, name, content, options, test, captureIndex) => {
|
|
324
397
|
if (!name) throw new Error("The `name` argument is required.");
|
|
325
398
|
return writeSnapshotFile(name, content, {
|
|
326
399
|
root: pluginOptions.root,
|
|
327
400
|
...options
|
|
328
|
-
}, test);
|
|
401
|
+
}, test, captureIndex);
|
|
329
402
|
};
|
|
330
403
|
};
|
|
331
404
|
//#endregion
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { createDirectory, getGitRepositoryPath, getMetadataPath, getScreenshotName, readVersionFromPackage, writeMetadata } from "@argos-ci/util";
|
|
2
3
|
import { writeFile } from "node:fs/promises";
|
|
3
4
|
import { dirname, relative, resolve } from "node:path";
|
|
4
5
|
import { getSnapshotMimeType } from "@argos-ci/core";
|
|
5
|
-
import { createDirectory, getGitRepositoryPath, getMetadataPath, getScreenshotName, readVersionFromPackage, writeMetadata } from "@argos-ci/util";
|
|
6
6
|
//#region src/version.ts
|
|
7
7
|
const require = createRequire(import.meta.url);
|
|
8
8
|
/**
|
|
@@ -60,7 +60,7 @@ function normalizeExtension(extension) {
|
|
|
60
60
|
* This is the shared Node-side primitive used by both the browser command (which
|
|
61
61
|
* receives the already-serialized string over RPC) and the Node code path.
|
|
62
62
|
*/
|
|
63
|
-
async function writeSnapshotFile(name, content, options = {}, test) {
|
|
63
|
+
async function writeSnapshotFile(name, content, options = {}, test, captureIndex) {
|
|
64
64
|
if (!name) throw new Error("The `name` argument is required.");
|
|
65
65
|
const root = options.root ?? "./snapshots";
|
|
66
66
|
const extension = normalizeExtension(options.extension ?? DEFAULT_EXTENSION);
|
|
@@ -82,7 +82,8 @@ async function writeSnapshotFile(name, content, options = {}, test) {
|
|
|
82
82
|
version: sdkVersion
|
|
83
83
|
},
|
|
84
84
|
...tags ? { tags } : {},
|
|
85
|
-
...resolvedTest ? { test: resolvedTest } : {}
|
|
85
|
+
...resolvedTest ? { test: resolvedTest } : {},
|
|
86
|
+
...captureIndex != null ? { capture: { index: captureIndex } } : {}
|
|
86
87
|
};
|
|
87
88
|
await createDirectory(dirname(snapshotPath));
|
|
88
89
|
await Promise.all([writeFile(snapshotPath, content, "utf-8"), writeMetadata(snapshotPath, metadata)]);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@argos-ci/vitest",
|
|
3
3
|
"description": "Vitest SDK for visual testing with Argos.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"author": "Smooth Code",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@argos-ci/browser": "6.4.5",
|
|
55
|
-
"@argos-ci/core": "6.8.
|
|
56
|
-
"@argos-ci/playwright": "7.
|
|
57
|
-
"@argos-ci/util": "4.
|
|
55
|
+
"@argos-ci/core": "6.8.3",
|
|
56
|
+
"@argos-ci/playwright": "7.5.0",
|
|
57
|
+
"@argos-ci/util": "4.2.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@vitest/browser": ">=4",
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@types/node": "catalog:",
|
|
67
|
-
"@vitest/browser": "^
|
|
68
|
-
"@vitest/browser-playwright": "^
|
|
69
|
-
"@vitest/pretty-format": "^
|
|
67
|
+
"@vitest/browser": "^5.0.0",
|
|
68
|
+
"@vitest/browser-playwright": "^5.0.0",
|
|
69
|
+
"@vitest/pretty-format": "^5.0.0",
|
|
70
70
|
"playwright": "^1.62.1",
|
|
71
71
|
"vitest": "catalog:"
|
|
72
72
|
},
|
|
@@ -77,9 +77,10 @@
|
|
|
77
77
|
"install-playwright": "playwright install chromium --with-deps",
|
|
78
78
|
"build-e2e": "pnpm run install-playwright",
|
|
79
79
|
"e2e": "cross-env BUILD_NAME=\"argos-vitest-e2e-node-$NODE_VERSION-$OS\" UPLOAD_TO_ARGOS=true pnpm run test-e2e",
|
|
80
|
+
"e2e-compat": "cross-env BUILD_NAME=\"argos-vitest4-e2e-node-$NODE_VERSION-$OS\" UPLOAD_TO_ARGOS=true pnpm run test-e2e",
|
|
80
81
|
"check-types": "tsc",
|
|
81
82
|
"check-format": "prettier --check --ignore-unknown --ignore-path=./.gitignore --ignore-path=../../.gitignore --ignore-path=../../.prettierignore .",
|
|
82
83
|
"lint": "eslint ."
|
|
83
84
|
},
|
|
84
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "4a87379645664a85d91dfbb3571bb57b682ec69e"
|
|
85
86
|
}
|