@argos-ci/vitest 0.5.0 → 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.mjs +68 -38
- package/dist/internal.d.mts +16 -5
- package/dist/internal.mjs +88 -17
- package/dist/plugin.d.mts +1 -2
- package/dist/plugin.mjs +88 -17
- package/package.json +6 -5
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import { getTestRunKey, nextCaptureIndex } from "@argos-ci/util";
|
|
2
2
|
//#region src/test-context.ts
|
|
3
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
|
+
/**
|
|
4
14
|
* Get the current Vitest test task, or `undefined` when not inside a test.
|
|
5
15
|
*
|
|
6
16
|
* Vitest >= 4.1 exposes `TestRunner.getCurrentTest()` from the `vitest` entry
|
|
7
|
-
* point; the `vitest/suite` export is deprecated
|
|
8
|
-
* fall back to `vitest/suite` for older 4.x. Both are
|
|
9
|
-
* importing `@argos-ci/vitest` in a non-Vitest
|
|
10
|
-
* 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.
|
|
11
22
|
*/
|
|
12
23
|
async function getCurrentTest() {
|
|
13
24
|
const runner = (await import("vitest")).TestRunner;
|
|
14
25
|
if (runner?.getCurrentTest) return runner.getCurrentTest();
|
|
15
|
-
return (await import(
|
|
26
|
+
return (await import(
|
|
27
|
+
/* @vite-ignore */
|
|
28
|
+
LEGACY_SUITE_ENTRY
|
|
29
|
+
)).getCurrentTest();
|
|
16
30
|
}
|
|
17
31
|
//#endregion
|
|
18
32
|
//#region src/auto-name.ts
|
|
@@ -239,7 +253,7 @@ function C({ force: e } = {}) {
|
|
|
239
253
|
}
|
|
240
254
|
var y = C();
|
|
241
255
|
//#endregion
|
|
242
|
-
//#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
|
|
243
257
|
function _mergeNamespaces(n, m) {
|
|
244
258
|
m.forEach(function(e) {
|
|
245
259
|
e && typeof e !== "string" && !Array.isArray(e) && Object.keys(e).forEach(function(k) {
|
|
@@ -269,7 +283,7 @@ function getKeysOfEnumerableProperties(object, compareKeys) {
|
|
|
269
283
|
* with spacing, indentation, and comma
|
|
270
284
|
* without surrounding punctuation (for example, braces)
|
|
271
285
|
*/
|
|
272
|
-
function printIteratorEntries(iterator, config, indentation, depth, refs, printer, separator = ": ") {
|
|
286
|
+
function printIteratorEntries(iterator, config, indentation, depth, refs, printer, separator = ": ", length) {
|
|
273
287
|
let result = "";
|
|
274
288
|
let width = 0;
|
|
275
289
|
let current = iterator.next();
|
|
@@ -279,7 +293,7 @@ function printIteratorEntries(iterator, config, indentation, depth, refs, printe
|
|
|
279
293
|
while (!current.done) {
|
|
280
294
|
result += indentationNext;
|
|
281
295
|
if (width++ === config.maxWidth) {
|
|
282
|
-
result += "…";
|
|
296
|
+
result += typeof length === "number" ? `…(${length - width + 1})` : "…";
|
|
283
297
|
break;
|
|
284
298
|
}
|
|
285
299
|
const name = printer(current.value[0], config, indentationNext, depth, refs);
|
|
@@ -298,7 +312,7 @@ function printIteratorEntries(iterator, config, indentation, depth, refs, printe
|
|
|
298
312
|
* with spacing, indentation, and comma
|
|
299
313
|
* without surrounding punctuation (braces or brackets)
|
|
300
314
|
*/
|
|
301
|
-
function printIteratorValues(iterator, config, indentation, depth, refs, printer) {
|
|
315
|
+
function printIteratorValues(iterator, config, indentation, depth, refs, printer, length) {
|
|
302
316
|
let result = "";
|
|
303
317
|
let width = 0;
|
|
304
318
|
let current = iterator.next();
|
|
@@ -308,7 +322,7 @@ function printIteratorValues(iterator, config, indentation, depth, refs, printer
|
|
|
308
322
|
while (!current.done) {
|
|
309
323
|
result += indentationNext;
|
|
310
324
|
if (width++ === config.maxWidth) {
|
|
311
|
-
result += "…";
|
|
325
|
+
result += typeof length === "number" ? `…(${length - width + 1})` : "…";
|
|
312
326
|
break;
|
|
313
327
|
}
|
|
314
328
|
result += printer(current.value, config, indentationNext, depth, refs);
|
|
@@ -336,7 +350,7 @@ function printListItems(list, config, indentation, depth, refs, printer) {
|
|
|
336
350
|
for (let i = 0; i < length; i++) {
|
|
337
351
|
result += indentationNext;
|
|
338
352
|
if (i === config.maxWidth) {
|
|
339
|
-
result +=
|
|
353
|
+
result += `…(${length - i})`;
|
|
340
354
|
break;
|
|
341
355
|
}
|
|
342
356
|
if (isDataView(list) || i in list) result += printer(isDataView(list) ? list.getInt8(i) : list[i], config, indentationNext, depth, refs);
|
|
@@ -352,17 +366,22 @@ function printListItems(list, config, indentation, depth, refs, printer) {
|
|
|
352
366
|
* with spacing, indentation, and comma
|
|
353
367
|
* without surrounding punctuation (for example, braces)
|
|
354
368
|
*/
|
|
355
|
-
function printObjectProperties(val, config, indentation, depth, refs, printer) {
|
|
369
|
+
function printObjectProperties(val, config, indentation, depth, refs, printer, compareKeysOverride = config.compareKeys) {
|
|
356
370
|
let result = "";
|
|
357
|
-
const keys = getKeysOfEnumerableProperties(val,
|
|
371
|
+
const keys = getKeysOfEnumerableProperties(val, compareKeysOverride);
|
|
358
372
|
if (keys.length > 0) {
|
|
359
373
|
result += config.spacingOuter;
|
|
360
374
|
const indentationNext = indentation + config.indent;
|
|
361
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
|
+
}
|
|
362
381
|
const key = keys[i];
|
|
363
|
-
const name = printer(key, config, indentationNext, depth, refs);
|
|
382
|
+
const name = !config.quoteKeys && isUnquotableKey(key) ? key : printer(key, config, indentationNext, depth, refs);
|
|
364
383
|
const value = printer(val[key], config, indentationNext, depth, refs);
|
|
365
|
-
result += `${
|
|
384
|
+
result += `${name}: ${value}`;
|
|
366
385
|
if (i < keys.length - 1) result += `,${config.spacingInner}`;
|
|
367
386
|
else if (!config.min) result += ",";
|
|
368
387
|
}
|
|
@@ -370,6 +389,10 @@ function printObjectProperties(val, config, indentation, depth, refs, printer) {
|
|
|
370
389
|
}
|
|
371
390
|
return result;
|
|
372
391
|
}
|
|
392
|
+
const keyStrRegExp = /^[a-z_]\w*$/i;
|
|
393
|
+
function isUnquotableKey(key) {
|
|
394
|
+
return typeof key === "string" && key !== "__proto__" && keyStrRegExp.test(key);
|
|
395
|
+
}
|
|
373
396
|
const asymmetricMatcher = typeof Symbol === "function" && Symbol.for ? Symbol.for("jest.asymmetricMatcher") : 1267621;
|
|
374
397
|
const SPACE$2 = " ";
|
|
375
398
|
const serialize$5 = (val, config, indentation, depth, refs, printer) => {
|
|
@@ -428,7 +451,7 @@ function printProps(keys, props, config, indentation, depth, refs, printer) {
|
|
|
428
451
|
const colors = config.colors;
|
|
429
452
|
return keys.map((key) => {
|
|
430
453
|
const value = props[key];
|
|
431
|
-
if (typeof value === "string" && value[0] === "_" && value.startsWith("__vitest_") &&
|
|
454
|
+
if (typeof value === "string" && value[0] === "_" && value.startsWith("__vitest_") && /__vitest_\d+__/.test(value)) return "";
|
|
432
455
|
let printed = printer(value, config, indentationNext, depth, refs);
|
|
433
456
|
if (typeof value !== "string") {
|
|
434
457
|
if (printed.includes("\n")) printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation;
|
|
@@ -905,7 +928,7 @@ function printError(val) {
|
|
|
905
928
|
* The first port of call for printing an object, handles most of the
|
|
906
929
|
* data-types in JS.
|
|
907
930
|
*/
|
|
908
|
-
function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
|
|
931
|
+
function printBasicValue(val, printFunctionName, escapeRegex, escapeString, singleQuote) {
|
|
909
932
|
if (val === true || val === false) return `${val}`;
|
|
910
933
|
if (val === void 0) return "undefined";
|
|
911
934
|
if (val === null) return "null";
|
|
@@ -913,8 +936,12 @@ function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
|
|
|
913
936
|
if (typeOf === "number") return printNumber(val);
|
|
914
937
|
if (typeOf === "bigint") return printBigInt(val);
|
|
915
938
|
if (typeOf === "string") {
|
|
916
|
-
|
|
917
|
-
|
|
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}`;
|
|
918
945
|
}
|
|
919
946
|
if (typeOf === "function") return printFunction(val, printFunctionName);
|
|
920
947
|
if (typeOf === "symbol") return printSymbol(val);
|
|
@@ -945,10 +972,10 @@ function printComplexValue(val, config, indentation, depth, refs, hasCalledToJSO
|
|
|
945
972
|
if (config.callToJSON && !hitMaxDepth && val.toJSON && typeof val.toJSON === "function" && !hasCalledToJSON) return printer(val.toJSON(), config, indentation, depth, refs, true);
|
|
946
973
|
const toStringed = toString.call(val);
|
|
947
974
|
if (toStringed === "[object Arguments]") return hitMaxDepth ? "[Arguments]" : `${min ? "" : "Arguments "}[${printListItems(val, config, indentation, depth, refs, printer)}]`;
|
|
948
|
-
if (isToStringedArrayType(toStringed)) return hitMaxDepth ? `[${val.constructor.name}]` : `${
|
|
949
|
-
if (toStringed === "[object Map]") return hitMaxDepth ? "[Map]" : `Map {${printIteratorEntries(val.entries(), config, indentation, depth, refs, printer, " => ")}}`;
|
|
950
|
-
if (toStringed === "[object Set]") return hitMaxDepth ? "[Set]" : `Set {${printIteratorValues(val.values(), config, indentation, depth, refs, printer)}}`;
|
|
951
|
-
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)}}`;
|
|
952
979
|
}
|
|
953
980
|
const ErrorPlugin = {
|
|
954
981
|
test: (val) => val && val instanceof Error,
|
|
@@ -964,7 +991,7 @@ const ErrorPlugin = {
|
|
|
964
991
|
...rest
|
|
965
992
|
};
|
|
966
993
|
const name = val.name !== "Error" ? val.name : getConstructorName(val);
|
|
967
|
-
return hitMaxDepth ? `[${name}]` : `${name} {${
|
|
994
|
+
return hitMaxDepth ? `[${name}]` : `${name} {${printObjectProperties(entries, config, indentation, depth, refs, printer, null)}}`;
|
|
968
995
|
}
|
|
969
996
|
};
|
|
970
997
|
function isNewPlugin(plugin) {
|
|
@@ -1000,7 +1027,7 @@ function printer(val, config, indentation, depth, refs, hasCalledToJSON) {
|
|
|
1000
1027
|
const plugin = findPlugin(config.plugins, val);
|
|
1001
1028
|
if (plugin !== null) result = printPlugin(plugin, val, config, indentation, depth, refs);
|
|
1002
1029
|
else {
|
|
1003
|
-
const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString);
|
|
1030
|
+
const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString, config.singleQuote);
|
|
1004
1031
|
if (basicResult !== null) result = basicResult;
|
|
1005
1032
|
else result = printComplexValue(val, config, indentation, depth, refs, hasCalledToJSON);
|
|
1006
1033
|
}
|
|
@@ -1032,7 +1059,11 @@ const DEFAULT_OPTIONS = {
|
|
|
1032
1059
|
printBasicPrototype: true,
|
|
1033
1060
|
printFunctionName: true,
|
|
1034
1061
|
printShadowRoot: true,
|
|
1035
|
-
theme: DEFAULT_THEME
|
|
1062
|
+
theme: DEFAULT_THEME,
|
|
1063
|
+
singleQuote: false,
|
|
1064
|
+
quoteKeys: true,
|
|
1065
|
+
spacingInner: "\n",
|
|
1066
|
+
spacingOuter: "\n"
|
|
1036
1067
|
};
|
|
1037
1068
|
function validateOptions(options) {
|
|
1038
1069
|
for (const key of Object.keys(options)) if (!Object.hasOwn(DEFAULT_OPTIONS, key)) throw new Error(`pretty-format: Unknown option "${key}".`);
|
|
@@ -1077,11 +1108,13 @@ function getConfig(options) {
|
|
|
1077
1108
|
maxWidth: options?.maxWidth ?? DEFAULT_OPTIONS.maxWidth,
|
|
1078
1109
|
min: options?.min ?? DEFAULT_OPTIONS.min,
|
|
1079
1110
|
plugins: options?.plugins ?? DEFAULT_OPTIONS.plugins,
|
|
1080
|
-
printBasicPrototype: options?.printBasicPrototype ??
|
|
1111
|
+
printBasicPrototype: options?.printBasicPrototype ?? !options?.min,
|
|
1081
1112
|
printFunctionName: getPrintFunctionName(options),
|
|
1082
1113
|
printShadowRoot: options?.printShadowRoot ?? true,
|
|
1083
|
-
spacingInner: options?.min ? " " : "\n",
|
|
1084
|
-
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,
|
|
1085
1118
|
maxOutputLength: options?.maxOutputLength ?? DEFAULT_OPTIONS.maxOutputLength,
|
|
1086
1119
|
_outputLengthPerDepth: []
|
|
1087
1120
|
};
|
|
@@ -1095,16 +1128,13 @@ function createIndent(indent) {
|
|
|
1095
1128
|
* @param options Custom settings
|
|
1096
1129
|
*/
|
|
1097
1130
|
function format(val, options) {
|
|
1098
|
-
if (options)
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
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);
|
|
1106
1136
|
if (basicResult !== null) return basicResult;
|
|
1107
|
-
return printComplexValue(val,
|
|
1137
|
+
return printComplexValue(val, config, "", 0, []);
|
|
1108
1138
|
}
|
|
1109
1139
|
const plugins = {
|
|
1110
1140
|
AsymmetricMatcher: plugin$5,
|
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.
|
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
|
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": {
|
|
@@ -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
|
}
|