@vitest/snapshot 3.1.0-beta.1 → 3.1.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.js CHANGED
@@ -577,221 +577,238 @@ function traceSegmentInternal(segments, memo, line, column, bias) {
577
577
  return index;
578
578
  }
579
579
 
580
+ /**
581
+ * Get original stacktrace without source map support the most performant way.
582
+ * - Create only 1 stack frame.
583
+ * - Rewrite prepareStackTrace to bypass "support-stack-trace" (usually takes ~250ms).
584
+ */
580
585
  function notNullish(v) {
581
- return v != null;
586
+ return v != null;
582
587
  }
583
588
  function isPrimitive(value) {
584
- return value === null || typeof value !== "function" && typeof value !== "object";
589
+ return value === null || typeof value !== "function" && typeof value !== "object";
585
590
  }
586
591
  function isObject(item) {
587
- return item != null && typeof item === "object" && !Array.isArray(item);
592
+ return item != null && typeof item === "object" && !Array.isArray(item);
588
593
  }
594
+ /**
595
+ * If code starts with a function call, will return its last index, respecting arguments.
596
+ * This will return 25 - last ending character of toMatch ")"
597
+ * Also works with callbacks
598
+ * ```
599
+ * toMatch({ test: '123' });
600
+ * toBeAliased('123')
601
+ * ```
602
+ */
589
603
  function getCallLastIndex(code) {
590
- let charIndex = -1;
591
- let inString = null;
592
- let startedBracers = 0;
593
- let endedBracers = 0;
594
- let beforeChar = null;
595
- while (charIndex <= code.length) {
596
- beforeChar = code[charIndex];
597
- charIndex++;
598
- const char = code[charIndex];
599
- const isCharString = char === '"' || char === "'" || char === "`";
600
- if (isCharString && beforeChar !== "\\") {
601
- if (inString === char) {
602
- inString = null;
603
- } else if (!inString) {
604
- inString = char;
605
- }
606
- }
607
- if (!inString) {
608
- if (char === "(") {
609
- startedBracers++;
610
- }
611
- if (char === ")") {
612
- endedBracers++;
613
- }
614
- }
615
- if (startedBracers && endedBracers && startedBracers === endedBracers) {
616
- return charIndex;
617
- }
618
- }
619
- return null;
604
+ let charIndex = -1;
605
+ let inString = null;
606
+ let startedBracers = 0;
607
+ let endedBracers = 0;
608
+ let beforeChar = null;
609
+ while (charIndex <= code.length) {
610
+ beforeChar = code[charIndex];
611
+ charIndex++;
612
+ const char = code[charIndex];
613
+ const isCharString = char === "\"" || char === "'" || char === "`";
614
+ if (isCharString && beforeChar !== "\\") {
615
+ if (inString === char) {
616
+ inString = null;
617
+ } else if (!inString) {
618
+ inString = char;
619
+ }
620
+ }
621
+ if (!inString) {
622
+ if (char === "(") {
623
+ startedBracers++;
624
+ }
625
+ if (char === ")") {
626
+ endedBracers++;
627
+ }
628
+ }
629
+ if (startedBracers && endedBracers && startedBracers === endedBracers) {
630
+ return charIndex;
631
+ }
632
+ }
633
+ return null;
620
634
  }
621
635
 
622
636
  const CHROME_IE_STACK_REGEXP = /^\s*at .*(?:\S:\d+|\(native\))/m;
623
637
  const SAFARI_NATIVE_CODE_REGEXP = /^(?:eval@)?(?:\[native code\])?$/;
624
638
  const stackIgnorePatterns = [
625
- "node:internal",
626
- /\/packages\/\w+\/dist\//,
627
- /\/@vitest\/\w+\/dist\//,
628
- "/vitest/dist/",
629
- "/vitest/src/",
630
- "/vite-node/dist/",
631
- "/vite-node/src/",
632
- "/node_modules/chai/",
633
- "/node_modules/tinypool/",
634
- "/node_modules/tinyspy/",
635
- // browser related deps
636
- "/deps/chunk-",
637
- "/deps/@vitest",
638
- "/deps/loupe",
639
- "/deps/chai",
640
- /node:\w+/,
641
- /__vitest_test__/,
642
- /__vitest_browser__/,
643
- /\/deps\/vitest_/
639
+ "node:internal",
640
+ /\/packages\/\w+\/dist\//,
641
+ /\/@vitest\/\w+\/dist\//,
642
+ "/vitest/dist/",
643
+ "/vitest/src/",
644
+ "/vite-node/dist/",
645
+ "/vite-node/src/",
646
+ "/node_modules/chai/",
647
+ "/node_modules/tinypool/",
648
+ "/node_modules/tinyspy/",
649
+ "/deps/chunk-",
650
+ "/deps/@vitest",
651
+ "/deps/loupe",
652
+ "/deps/chai",
653
+ /node:\w+/,
654
+ /__vitest_test__/,
655
+ /__vitest_browser__/,
656
+ /\/deps\/vitest_/
644
657
  ];
645
658
  function extractLocation(urlLike) {
646
- if (!urlLike.includes(":")) {
647
- return [urlLike];
648
- }
649
- const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
650
- const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, ""));
651
- if (!parts) {
652
- return [urlLike];
653
- }
654
- let url = parts[1];
655
- if (url.startsWith("async ")) {
656
- url = url.slice(6);
657
- }
658
- if (url.startsWith("http:") || url.startsWith("https:")) {
659
- const urlObj = new URL(url);
660
- urlObj.searchParams.delete("import");
661
- urlObj.searchParams.delete("browserv");
662
- url = urlObj.pathname + urlObj.hash + urlObj.search;
663
- }
664
- if (url.startsWith("/@fs/")) {
665
- const isWindows = /^\/@fs\/[a-zA-Z]:\//.test(url);
666
- url = url.slice(isWindows ? 5 : 4);
667
- }
668
- return [url, parts[2] || void 0, parts[3] || void 0];
659
+ if (!urlLike.includes(":")) {
660
+ return [urlLike];
661
+ }
662
+ const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
663
+ const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, ""));
664
+ if (!parts) {
665
+ return [urlLike];
666
+ }
667
+ let url = parts[1];
668
+ if (url.startsWith("async ")) {
669
+ url = url.slice(6);
670
+ }
671
+ if (url.startsWith("http:") || url.startsWith("https:")) {
672
+ const urlObj = new URL(url);
673
+ urlObj.searchParams.delete("import");
674
+ urlObj.searchParams.delete("browserv");
675
+ url = urlObj.pathname + urlObj.hash + urlObj.search;
676
+ }
677
+ if (url.startsWith("/@fs/")) {
678
+ const isWindows = /^\/@fs\/[a-zA-Z]:\//.test(url);
679
+ url = url.slice(isWindows ? 5 : 4);
680
+ }
681
+ return [
682
+ url,
683
+ parts[2] || undefined,
684
+ parts[3] || undefined
685
+ ];
669
686
  }
670
687
  function parseSingleFFOrSafariStack(raw) {
671
- let line = raw.trim();
672
- if (SAFARI_NATIVE_CODE_REGEXP.test(line)) {
673
- return null;
674
- }
675
- if (line.includes(" > eval")) {
676
- line = line.replace(
677
- / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,
678
- ":$1"
679
- );
680
- }
681
- if (!line.includes("@") && !line.includes(":")) {
682
- return null;
683
- }
684
- const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(@)/;
685
- const matches = line.match(functionNameRegex);
686
- const functionName = matches && matches[1] ? matches[1] : void 0;
687
- const [url, lineNumber, columnNumber] = extractLocation(
688
- line.replace(functionNameRegex, "")
689
- );
690
- if (!url || !lineNumber || !columnNumber) {
691
- return null;
692
- }
693
- return {
694
- file: url,
695
- method: functionName || "",
696
- line: Number.parseInt(lineNumber),
697
- column: Number.parseInt(columnNumber)
698
- };
688
+ let line = raw.trim();
689
+ if (SAFARI_NATIVE_CODE_REGEXP.test(line)) {
690
+ return null;
691
+ }
692
+ if (line.includes(" > eval")) {
693
+ line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ":$1");
694
+ }
695
+ if (!line.includes("@") && !line.includes(":")) {
696
+ return null;
697
+ }
698
+ const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(@)/;
699
+ const matches = line.match(functionNameRegex);
700
+ const functionName = matches && matches[1] ? matches[1] : undefined;
701
+ const [url, lineNumber, columnNumber] = extractLocation(line.replace(functionNameRegex, ""));
702
+ if (!url || !lineNumber || !columnNumber) {
703
+ return null;
704
+ }
705
+ return {
706
+ file: url,
707
+ method: functionName || "",
708
+ line: Number.parseInt(lineNumber),
709
+ column: Number.parseInt(columnNumber)
710
+ };
699
711
  }
700
712
  function parseSingleV8Stack(raw) {
701
- let line = raw.trim();
702
- if (!CHROME_IE_STACK_REGEXP.test(line)) {
703
- return null;
704
- }
705
- if (line.includes("(eval ")) {
706
- line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
707
- }
708
- let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
709
- const location = sanitizedLine.match(/ (\(.+\)$)/);
710
- sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
711
- const [url, lineNumber, columnNumber] = extractLocation(
712
- location ? location[1] : sanitizedLine
713
- );
714
- let method = location && sanitizedLine || "";
715
- let file = url && ["eval", "<anonymous>"].includes(url) ? void 0 : url;
716
- if (!file || !lineNumber || !columnNumber) {
717
- return null;
718
- }
719
- if (method.startsWith("async ")) {
720
- method = method.slice(6);
721
- }
722
- if (file.startsWith("file://")) {
723
- file = file.slice(7);
724
- }
725
- file = file.startsWith("node:") || file.startsWith("internal:") ? file : resolve$2(file);
726
- if (method) {
727
- method = method.replace(/__vite_ssr_import_\d+__\./g, "");
728
- }
729
- return {
730
- method,
731
- file,
732
- line: Number.parseInt(lineNumber),
733
- column: Number.parseInt(columnNumber)
734
- };
713
+ let line = raw.trim();
714
+ if (!CHROME_IE_STACK_REGEXP.test(line)) {
715
+ return null;
716
+ }
717
+ if (line.includes("(eval ")) {
718
+ line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
719
+ }
720
+ let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
721
+ const location = sanitizedLine.match(/ (\(.+\)$)/);
722
+ sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
723
+ const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine);
724
+ let method = location && sanitizedLine || "";
725
+ let file = url && ["eval", "<anonymous>"].includes(url) ? undefined : url;
726
+ if (!file || !lineNumber || !columnNumber) {
727
+ return null;
728
+ }
729
+ if (method.startsWith("async ")) {
730
+ method = method.slice(6);
731
+ }
732
+ if (file.startsWith("file://")) {
733
+ file = file.slice(7);
734
+ }
735
+ file = file.startsWith("node:") || file.startsWith("internal:") ? file : resolve$2(file);
736
+ if (method) {
737
+ method = method.replace(/__vite_ssr_import_\d+__\./g, "");
738
+ }
739
+ return {
740
+ method,
741
+ file,
742
+ line: Number.parseInt(lineNumber),
743
+ column: Number.parseInt(columnNumber)
744
+ };
735
745
  }
736
746
  function parseStacktrace(stack, options = {}) {
737
- const { ignoreStackEntries = stackIgnorePatterns } = options;
738
- const stacks = !CHROME_IE_STACK_REGEXP.test(stack) ? parseFFOrSafariStackTrace(stack) : parseV8Stacktrace(stack);
739
- return stacks.map((stack2) => {
740
- var _a;
741
- if (options.getUrlId) {
742
- stack2.file = options.getUrlId(stack2.file);
743
- }
744
- const map = (_a = options.getSourceMap) == null ? void 0 : _a.call(options, stack2.file);
745
- if (!map || typeof map !== "object" || !map.version) {
746
- return shouldFilter(ignoreStackEntries, stack2.file) ? null : stack2;
747
- }
748
- const traceMap = new TraceMap(map);
749
- const { line, column, source, name } = originalPositionFor(traceMap, stack2);
750
- let file = stack2.file;
751
- if (source) {
752
- const fileUrl = stack2.file.startsWith("file://") ? stack2.file : `file://${stack2.file}`;
753
- const sourceRootUrl = map.sourceRoot ? new URL(map.sourceRoot, fileUrl) : fileUrl;
754
- file = new URL(source, sourceRootUrl).pathname;
755
- }
756
- if (shouldFilter(ignoreStackEntries, file)) {
757
- return null;
758
- }
759
- if (line != null && column != null) {
760
- return {
761
- line,
762
- column,
763
- file,
764
- method: name || stack2.method
765
- };
766
- }
767
- return stack2;
768
- }).filter((s) => s != null);
747
+ const { ignoreStackEntries = stackIgnorePatterns } = options;
748
+ const stacks = !CHROME_IE_STACK_REGEXP.test(stack) ? parseFFOrSafariStackTrace(stack) : parseV8Stacktrace(stack);
749
+ return stacks.map((stack) => {
750
+ var _options$getSourceMap;
751
+ if (options.getUrlId) {
752
+ stack.file = options.getUrlId(stack.file);
753
+ }
754
+ const map = (_options$getSourceMap = options.getSourceMap) === null || _options$getSourceMap === void 0 ? void 0 : _options$getSourceMap.call(options, stack.file);
755
+ if (!map || typeof map !== "object" || !map.version) {
756
+ return shouldFilter(ignoreStackEntries, stack.file) ? null : stack;
757
+ }
758
+ const traceMap = new TraceMap(map);
759
+ const { line, column, source, name } = originalPositionFor(traceMap, stack);
760
+ let file = stack.file;
761
+ if (source) {
762
+ const fileUrl = stack.file.startsWith("file://") ? stack.file : `file://${stack.file}`;
763
+ const sourceRootUrl = map.sourceRoot ? new URL(map.sourceRoot, fileUrl) : fileUrl;
764
+ file = new URL(source, sourceRootUrl).pathname;
765
+ }
766
+ if (shouldFilter(ignoreStackEntries, file)) {
767
+ return null;
768
+ }
769
+ if (line != null && column != null) {
770
+ return {
771
+ line,
772
+ column,
773
+ file,
774
+ method: name || stack.method
775
+ };
776
+ }
777
+ return stack;
778
+ }).filter((s) => s != null);
769
779
  }
770
780
  function shouldFilter(ignoreStackEntries, file) {
771
- return ignoreStackEntries.some((p) => file.match(p));
781
+ return ignoreStackEntries.some((p) => file.match(p));
772
782
  }
773
783
  function parseFFOrSafariStackTrace(stack) {
774
- return stack.split("\n").map((line) => parseSingleFFOrSafariStack(line)).filter(notNullish);
784
+ return stack.split("\n").map((line) => parseSingleFFOrSafariStack(line)).filter(notNullish);
775
785
  }
776
786
  function parseV8Stacktrace(stack) {
777
- return stack.split("\n").map((line) => parseSingleV8Stack(line)).filter(notNullish);
787
+ return stack.split("\n").map((line) => parseSingleV8Stack(line)).filter(notNullish);
778
788
  }
779
789
  function parseErrorStacktrace(e, options = {}) {
780
- if (!e || isPrimitive(e)) {
781
- return [];
782
- }
783
- if (e.stacks) {
784
- return e.stacks;
785
- }
786
- const stackStr = e.stack || e.stackStr || "";
787
- let stackFrames = parseStacktrace(stackStr, options);
788
- if (options.frameFilter) {
789
- stackFrames = stackFrames.filter(
790
- (f) => options.frameFilter(e, f) !== false
791
- );
792
- }
793
- e.stacks = stackFrames;
794
- return stackFrames;
790
+ if (!e || isPrimitive(e)) {
791
+ return [];
792
+ }
793
+ if (e.stacks) {
794
+ return e.stacks;
795
+ }
796
+ const stackStr = e.stack || e.stackStr || "";
797
+ let stackFrames = parseStacktrace(stackStr, options);
798
+ if (!stackFrames.length) {
799
+ const e_ = e;
800
+ if (e_.fileName != null && e_.lineNumber != null && e_.columnNumber != null) {
801
+ stackFrames = parseStacktrace(`${e_.fileName}:${e_.lineNumber}:${e_.columnNumber}`, options);
802
+ }
803
+ if (e_.sourceURL != null && e_.line != null && e_._column != null) {
804
+ stackFrames = parseStacktrace(`${e_.sourceURL}:${e_.line}:${e_.column}`, options);
805
+ }
806
+ }
807
+ if (options.frameFilter) {
808
+ stackFrames = stackFrames.filter((f) => options.frameFilter(e, f) !== false);
809
+ }
810
+ e.stacks = stackFrames;
811
+ return stackFrames;
795
812
  }
796
813
 
797
814
  let getPromiseValue = () => 'Promise{…}';
@@ -828,14 +845,7 @@ catch (noNodeInspect) {
828
845
  nodeInspect = false;
829
846
  }
830
847
 
831
- const {
832
- AsymmetricMatcher: AsymmetricMatcher$1,
833
- DOMCollection: DOMCollection$1,
834
- DOMElement: DOMElement$1,
835
- Immutable: Immutable$1,
836
- ReactElement: ReactElement$1,
837
- ReactTestComponent: ReactTestComponent$1
838
- } = plugins;
848
+ const { AsymmetricMatcher: AsymmetricMatcher$1, DOMCollection: DOMCollection$1, DOMElement: DOMElement$1, Immutable: Immutable$1, ReactElement: ReactElement$1, ReactTestComponent: ReactTestComponent$1 } = plugins;
839
849
 
840
850
  function getDefaultExportFromCjs (x) {
841
851
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -1374,190 +1384,180 @@ p();
1374
1384
 
1375
1385
  const lineSplitRE = /\r?\n/;
1376
1386
  function positionToOffset(source, lineNumber, columnNumber) {
1377
- const lines = source.split(lineSplitRE);
1378
- const nl = /\r\n/.test(source) ? 2 : 1;
1379
- let start = 0;
1380
- if (lineNumber > lines.length) {
1381
- return source.length;
1382
- }
1383
- for (let i = 0; i < lineNumber - 1; i++) {
1384
- start += lines[i].length + nl;
1385
- }
1386
- return start + columnNumber;
1387
+ const lines = source.split(lineSplitRE);
1388
+ const nl = /\r\n/.test(source) ? 2 : 1;
1389
+ let start = 0;
1390
+ if (lineNumber > lines.length) {
1391
+ return source.length;
1392
+ }
1393
+ for (let i = 0; i < lineNumber - 1; i++) {
1394
+ start += lines[i].length + nl;
1395
+ }
1396
+ return start + columnNumber;
1387
1397
  }
1388
1398
  function offsetToLineNumber(source, offset) {
1389
- if (offset > source.length) {
1390
- throw new Error(
1391
- `offset is longer than source length! offset ${offset} > length ${source.length}`
1392
- );
1393
- }
1394
- const lines = source.split(lineSplitRE);
1395
- const nl = /\r\n/.test(source) ? 2 : 1;
1396
- let counted = 0;
1397
- let line = 0;
1398
- for (; line < lines.length; line++) {
1399
- const lineLength = lines[line].length + nl;
1400
- if (counted + lineLength >= offset) {
1401
- break;
1402
- }
1403
- counted += lineLength;
1404
- }
1405
- return line + 1;
1399
+ if (offset > source.length) {
1400
+ throw new Error(`offset is longer than source length! offset ${offset} > length ${source.length}`);
1401
+ }
1402
+ const lines = source.split(lineSplitRE);
1403
+ const nl = /\r\n/.test(source) ? 2 : 1;
1404
+ let counted = 0;
1405
+ let line = 0;
1406
+ for (; line < lines.length; line++) {
1407
+ const lineLength = lines[line].length + nl;
1408
+ if (counted + lineLength >= offset) {
1409
+ break;
1410
+ }
1411
+ counted += lineLength;
1412
+ }
1413
+ return line + 1;
1406
1414
  }
1407
1415
 
1408
1416
  async function saveInlineSnapshots(environment, snapshots) {
1409
- const MagicString = (await import('magic-string')).default;
1410
- const files = new Set(snapshots.map((i) => i.file));
1411
- await Promise.all(
1412
- Array.from(files).map(async (file) => {
1413
- const snaps = snapshots.filter((i) => i.file === file);
1414
- const code = await environment.readSnapshotFile(file);
1415
- const s = new MagicString(code);
1416
- for (const snap of snaps) {
1417
- const index = positionToOffset(code, snap.line, snap.column);
1418
- replaceInlineSnap(code, s, index, snap.snapshot);
1419
- }
1420
- const transformed = s.toString();
1421
- if (transformed !== code) {
1422
- await environment.saveSnapshotFile(file, transformed);
1423
- }
1424
- })
1425
- );
1417
+ const MagicString = (await import('magic-string')).default;
1418
+ const files = new Set(snapshots.map((i) => i.file));
1419
+ await Promise.all(Array.from(files).map(async (file) => {
1420
+ const snaps = snapshots.filter((i) => i.file === file);
1421
+ const code = await environment.readSnapshotFile(file);
1422
+ const s = new MagicString(code);
1423
+ for (const snap of snaps) {
1424
+ const index = positionToOffset(code, snap.line, snap.column);
1425
+ replaceInlineSnap(code, s, index, snap.snapshot);
1426
+ }
1427
+ const transformed = s.toString();
1428
+ if (transformed !== code) {
1429
+ await environment.saveSnapshotFile(file, transformed);
1430
+ }
1431
+ }));
1426
1432
  }
1427
1433
  const startObjectRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\s\S]*\*\/\s*|\/\/.*(?:[\n\r\u2028\u2029]\s*|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF]))*\{/;
1428
1434
  function replaceObjectSnap(code, s, index, newSnap) {
1429
- let _code = code.slice(index);
1430
- const startMatch = startObjectRegex.exec(_code);
1431
- if (!startMatch) {
1432
- return false;
1433
- }
1434
- _code = _code.slice(startMatch.index);
1435
- let callEnd = getCallLastIndex(_code);
1436
- if (callEnd === null) {
1437
- return false;
1438
- }
1439
- callEnd += index + startMatch.index;
1440
- const shapeStart = index + startMatch.index + startMatch[0].length;
1441
- const shapeEnd = getObjectShapeEndIndex(code, shapeStart);
1442
- const snap = `, ${prepareSnapString(newSnap, code, index)}`;
1443
- if (shapeEnd === callEnd) {
1444
- s.appendLeft(callEnd, snap);
1445
- } else {
1446
- s.overwrite(shapeEnd, callEnd, snap);
1447
- }
1448
- return true;
1435
+ let _code = code.slice(index);
1436
+ const startMatch = startObjectRegex.exec(_code);
1437
+ if (!startMatch) {
1438
+ return false;
1439
+ }
1440
+ _code = _code.slice(startMatch.index);
1441
+ let callEnd = getCallLastIndex(_code);
1442
+ if (callEnd === null) {
1443
+ return false;
1444
+ }
1445
+ callEnd += index + startMatch.index;
1446
+ const shapeStart = index + startMatch.index + startMatch[0].length;
1447
+ const shapeEnd = getObjectShapeEndIndex(code, shapeStart);
1448
+ const snap = `, ${prepareSnapString(newSnap, code, index)}`;
1449
+ if (shapeEnd === callEnd) {
1450
+ s.appendLeft(callEnd, snap);
1451
+ } else {
1452
+ s.overwrite(shapeEnd, callEnd, snap);
1453
+ }
1454
+ return true;
1449
1455
  }
1450
1456
  function getObjectShapeEndIndex(code, index) {
1451
- let startBraces = 1;
1452
- let endBraces = 0;
1453
- while (startBraces !== endBraces && index < code.length) {
1454
- const s = code[index++];
1455
- if (s === "{") {
1456
- startBraces++;
1457
- } else if (s === "}") {
1458
- endBraces++;
1459
- }
1460
- }
1461
- return index;
1457
+ let startBraces = 1;
1458
+ let endBraces = 0;
1459
+ while (startBraces !== endBraces && index < code.length) {
1460
+ const s = code[index++];
1461
+ if (s === "{") {
1462
+ startBraces++;
1463
+ } else if (s === "}") {
1464
+ endBraces++;
1465
+ }
1466
+ }
1467
+ return index;
1462
1468
  }
1463
1469
  function prepareSnapString(snap, source, index) {
1464
- const lineNumber = offsetToLineNumber(source, index);
1465
- const line = source.split(lineSplitRE)[lineNumber - 1];
1466
- const indent = line.match(/^\s*/)[0] || "";
1467
- const indentNext = indent.includes(" ") ? `${indent} ` : `${indent} `;
1468
- const lines = snap.trim().replace(/\\/g, "\\\\").split(/\n/g);
1469
- const isOneline = lines.length <= 1;
1470
- const quote = "`";
1471
- if (isOneline) {
1472
- return `${quote}${lines.join("\n").replace(/`/g, "\\`").replace(/\$\{/g, "\\${")}${quote}`;
1473
- }
1474
- return `${quote}
1475
- ${lines.map((i) => i ? indentNext + i : "").join("\n").replace(/`/g, "\\`").replace(/\$\{/g, "\\${")}
1476
- ${indent}${quote}`;
1470
+ const lineNumber = offsetToLineNumber(source, index);
1471
+ const line = source.split(lineSplitRE)[lineNumber - 1];
1472
+ const indent = line.match(/^\s*/)[0] || "";
1473
+ const indentNext = indent.includes(" ") ? `${indent}\t` : `${indent} `;
1474
+ const lines = snap.trim().replace(/\\/g, "\\\\").split(/\n/g);
1475
+ const isOneline = lines.length <= 1;
1476
+ const quote = "`";
1477
+ if (isOneline) {
1478
+ return `${quote}${lines.join("\n").replace(/`/g, "\\`").replace(/\$\{/g, "\\\${")}${quote}`;
1479
+ }
1480
+ return `${quote}\n${lines.map((i) => i ? indentNext + i : "").join("\n").replace(/`/g, "\\`").replace(/\$\{/g, "\\\${")}\n${indent}${quote}`;
1477
1481
  }
1478
1482
  const toMatchInlineName = "toMatchInlineSnapshot";
1479
1483
  const toThrowErrorMatchingInlineName = "toThrowErrorMatchingInlineSnapshot";
1480
1484
  function getCodeStartingAtIndex(code, index) {
1481
- const indexInline = index - toMatchInlineName.length;
1482
- if (code.slice(indexInline, index) === toMatchInlineName) {
1483
- return {
1484
- code: code.slice(indexInline),
1485
- index: indexInline
1486
- };
1487
- }
1488
- const indexThrowInline = index - toThrowErrorMatchingInlineName.length;
1489
- if (code.slice(index - indexThrowInline, index) === toThrowErrorMatchingInlineName) {
1490
- return {
1491
- code: code.slice(index - indexThrowInline),
1492
- index: index - indexThrowInline
1493
- };
1494
- }
1495
- return {
1496
- code: code.slice(index),
1497
- index
1498
- };
1485
+ const indexInline = index - toMatchInlineName.length;
1486
+ if (code.slice(indexInline, index) === toMatchInlineName) {
1487
+ return {
1488
+ code: code.slice(indexInline),
1489
+ index: indexInline
1490
+ };
1491
+ }
1492
+ const indexThrowInline = index - toThrowErrorMatchingInlineName.length;
1493
+ if (code.slice(index - indexThrowInline, index) === toThrowErrorMatchingInlineName) {
1494
+ return {
1495
+ code: code.slice(index - indexThrowInline),
1496
+ index: index - indexThrowInline
1497
+ };
1498
+ }
1499
+ return {
1500
+ code: code.slice(index),
1501
+ index
1502
+ };
1499
1503
  }
1500
1504
  const startRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\s\S]*\*\/\s*|\/\/.*(?:[\n\r\u2028\u2029]\s*|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF]))*[\w$]*(['"`)])/;
1501
1505
  function replaceInlineSnap(code, s, currentIndex, newSnap) {
1502
- const { code: codeStartingAtIndex, index } = getCodeStartingAtIndex(code, currentIndex);
1503
- const startMatch = startRegex.exec(codeStartingAtIndex);
1504
- const firstKeywordMatch = /toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot/.exec(
1505
- codeStartingAtIndex
1506
- );
1507
- if (!startMatch || startMatch.index !== (firstKeywordMatch == null ? void 0 : firstKeywordMatch.index)) {
1508
- return replaceObjectSnap(code, s, index, newSnap);
1509
- }
1510
- const quote = startMatch[1];
1511
- const startIndex = index + startMatch.index + startMatch[0].length;
1512
- const snapString = prepareSnapString(newSnap, code, index);
1513
- if (quote === ")") {
1514
- s.appendRight(startIndex - 1, snapString);
1515
- return true;
1516
- }
1517
- const quoteEndRE = new RegExp(`(?:^|[^\\\\])${quote}`);
1518
- const endMatch = quoteEndRE.exec(code.slice(startIndex));
1519
- if (!endMatch) {
1520
- return false;
1521
- }
1522
- const endIndex = startIndex + endMatch.index + endMatch[0].length;
1523
- s.overwrite(startIndex - 1, endIndex, snapString);
1524
- return true;
1506
+ const { code: codeStartingAtIndex, index } = getCodeStartingAtIndex(code, currentIndex);
1507
+ const startMatch = startRegex.exec(codeStartingAtIndex);
1508
+ const firstKeywordMatch = /toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot/.exec(codeStartingAtIndex);
1509
+ if (!startMatch || startMatch.index !== (firstKeywordMatch === null || firstKeywordMatch === void 0 ? void 0 : firstKeywordMatch.index)) {
1510
+ return replaceObjectSnap(code, s, index, newSnap);
1511
+ }
1512
+ const quote = startMatch[1];
1513
+ const startIndex = index + startMatch.index + startMatch[0].length;
1514
+ const snapString = prepareSnapString(newSnap, code, index);
1515
+ if (quote === ")") {
1516
+ s.appendRight(startIndex - 1, snapString);
1517
+ return true;
1518
+ }
1519
+ const quoteEndRE = new RegExp(`(?:^|[^\\\\])${quote}`);
1520
+ const endMatch = quoteEndRE.exec(code.slice(startIndex));
1521
+ if (!endMatch) {
1522
+ return false;
1523
+ }
1524
+ const endIndex = startIndex + endMatch.index + endMatch[0].length;
1525
+ s.overwrite(startIndex - 1, endIndex, snapString);
1526
+ return true;
1525
1527
  }
1526
1528
  const INDENTATION_REGEX = /^([^\S\n]*)\S/m;
1527
1529
  function stripSnapshotIndentation(inlineSnapshot) {
1528
- const match = inlineSnapshot.match(INDENTATION_REGEX);
1529
- if (!match || !match[1]) {
1530
- return inlineSnapshot;
1531
- }
1532
- const indentation = match[1];
1533
- const lines = inlineSnapshot.split(/\n/g);
1534
- if (lines.length <= 2) {
1535
- return inlineSnapshot;
1536
- }
1537
- if (lines[0].trim() !== "" || lines[lines.length - 1].trim() !== "") {
1538
- return inlineSnapshot;
1539
- }
1540
- for (let i = 1; i < lines.length - 1; i++) {
1541
- if (lines[i] !== "") {
1542
- if (lines[i].indexOf(indentation) !== 0) {
1543
- return inlineSnapshot;
1544
- }
1545
- lines[i] = lines[i].substring(indentation.length);
1546
- }
1547
- }
1548
- lines[lines.length - 1] = "";
1549
- inlineSnapshot = lines.join("\n");
1550
- return inlineSnapshot;
1530
+ const match = inlineSnapshot.match(INDENTATION_REGEX);
1531
+ if (!match || !match[1]) {
1532
+ return inlineSnapshot;
1533
+ }
1534
+ const indentation = match[1];
1535
+ const lines = inlineSnapshot.split(/\n/g);
1536
+ if (lines.length <= 2) {
1537
+ return inlineSnapshot;
1538
+ }
1539
+ if (lines[0].trim() !== "" || lines[lines.length - 1].trim() !== "") {
1540
+ return inlineSnapshot;
1541
+ }
1542
+ for (let i = 1; i < lines.length - 1; i++) {
1543
+ if (lines[i] !== "") {
1544
+ if (lines[i].indexOf(indentation) !== 0) {
1545
+ return inlineSnapshot;
1546
+ }
1547
+ lines[i] = lines[i].substring(indentation.length);
1548
+ }
1549
+ }
1550
+ lines[lines.length - 1] = "";
1551
+ inlineSnapshot = lines.join("\n");
1552
+ return inlineSnapshot;
1551
1553
  }
1552
1554
 
1553
1555
  async function saveRawSnapshots(environment, snapshots) {
1554
- await Promise.all(
1555
- snapshots.map(async (snap) => {
1556
- if (!snap.readonly) {
1557
- await environment.saveSnapshotFile(snap.file, snap.snapshot);
1558
- }
1559
- })
1560
- );
1556
+ await Promise.all(snapshots.map(async (snap) => {
1557
+ if (!snap.readonly) {
1558
+ await environment.saveSnapshotFile(snap.file, snap.snapshot);
1559
+ }
1560
+ }));
1561
1561
  }
1562
1562
 
1563
1563
  var naturalCompare$1 = {exports: {}};
@@ -1628,699 +1628,600 @@ var naturalCompareExports = requireNaturalCompare();
1628
1628
  var naturalCompare = /*@__PURE__*/getDefaultExportFromCjs(naturalCompareExports);
1629
1629
 
1630
1630
  const serialize$1 = (val, config, indentation, depth, refs, printer) => {
1631
- const name = val.getMockName();
1632
- const nameString = name === "vi.fn()" ? "" : ` ${name}`;
1633
- let callsString = "";
1634
- if (val.mock.calls.length !== 0) {
1635
- const indentationNext = indentation + config.indent;
1636
- callsString = ` {${config.spacingOuter}${indentationNext}"calls": ${printer(
1637
- val.mock.calls,
1638
- config,
1639
- indentationNext,
1640
- depth,
1641
- refs
1642
- )}${config.min ? ", " : ","}${config.spacingOuter}${indentationNext}"results": ${printer(
1643
- val.mock.results,
1644
- config,
1645
- indentationNext,
1646
- depth,
1647
- refs
1648
- )}${config.min ? "" : ","}${config.spacingOuter}${indentation}}`;
1649
- }
1650
- return `[MockFunction${nameString}]${callsString}`;
1631
+ const name = val.getMockName();
1632
+ const nameString = name === "vi.fn()" ? "" : ` ${name}`;
1633
+ let callsString = "";
1634
+ if (val.mock.calls.length !== 0) {
1635
+ const indentationNext = indentation + config.indent;
1636
+ callsString = ` {${config.spacingOuter}${indentationNext}"calls": ${printer(val.mock.calls, config, indentationNext, depth, refs)}${config.min ? ", " : ","}${config.spacingOuter}${indentationNext}"results": ${printer(val.mock.results, config, indentationNext, depth, refs)}${config.min ? "" : ","}${config.spacingOuter}${indentation}}`;
1637
+ }
1638
+ return `[MockFunction${nameString}]${callsString}`;
1651
1639
  };
1652
1640
  const test = (val) => val && !!val._isMockFunction;
1653
- const plugin = { serialize: serialize$1, test };
1641
+ const plugin = {
1642
+ serialize: serialize$1,
1643
+ test
1644
+ };
1654
1645
 
1655
- const {
1656
- DOMCollection,
1657
- DOMElement,
1658
- Immutable,
1659
- ReactElement,
1660
- ReactTestComponent,
1661
- AsymmetricMatcher
1662
- } = plugins;
1646
+ const { DOMCollection, DOMElement, Immutable, ReactElement, ReactTestComponent, AsymmetricMatcher } = plugins;
1663
1647
  let PLUGINS = [
1664
- ReactTestComponent,
1665
- ReactElement,
1666
- DOMElement,
1667
- DOMCollection,
1668
- Immutable,
1669
- AsymmetricMatcher,
1670
- plugin
1648
+ ReactTestComponent,
1649
+ ReactElement,
1650
+ DOMElement,
1651
+ DOMCollection,
1652
+ Immutable,
1653
+ AsymmetricMatcher,
1654
+ plugin
1671
1655
  ];
1672
1656
  function addSerializer(plugin) {
1673
- PLUGINS = [plugin].concat(PLUGINS);
1657
+ PLUGINS = [plugin].concat(PLUGINS);
1674
1658
  }
1675
1659
  function getSerializers() {
1676
- return PLUGINS;
1660
+ return PLUGINS;
1677
1661
  }
1678
1662
 
1679
1663
  function testNameToKey(testName, count) {
1680
- return `${testName} ${count}`;
1664
+ return `${testName} ${count}`;
1681
1665
  }
1682
1666
  function keyToTestName(key) {
1683
- if (!/ \d+$/.test(key)) {
1684
- throw new Error("Snapshot keys must end with a number.");
1685
- }
1686
- return key.replace(/ \d+$/, "");
1667
+ if (!/ \d+$/.test(key)) {
1668
+ throw new Error("Snapshot keys must end with a number.");
1669
+ }
1670
+ return key.replace(/ \d+$/, "");
1687
1671
  }
1688
1672
  function getSnapshotData(content, options) {
1689
- const update = options.updateSnapshot;
1690
- const data = /* @__PURE__ */ Object.create(null);
1691
- let snapshotContents = "";
1692
- let dirty = false;
1693
- if (content != null) {
1694
- try {
1695
- snapshotContents = content;
1696
- const populate = new Function("exports", snapshotContents);
1697
- populate(data);
1698
- } catch {
1699
- }
1700
- }
1701
- const isInvalid = snapshotContents;
1702
- if ((update === "all" || update === "new") && isInvalid) {
1703
- dirty = true;
1704
- }
1705
- return { data, dirty };
1673
+ const update = options.updateSnapshot;
1674
+ const data = Object.create(null);
1675
+ let snapshotContents = "";
1676
+ let dirty = false;
1677
+ if (content != null) {
1678
+ try {
1679
+ snapshotContents = content;
1680
+ const populate = new Function("exports", snapshotContents);
1681
+ populate(data);
1682
+ } catch {}
1683
+ }
1684
+ const isInvalid = snapshotContents;
1685
+ if ((update === "all" || update === "new") && isInvalid) {
1686
+ dirty = true;
1687
+ }
1688
+ return {
1689
+ data,
1690
+ dirty
1691
+ };
1706
1692
  }
1707
1693
  function addExtraLineBreaks(string) {
1708
- return string.includes("\n") ? `
1709
- ${string}
1710
- ` : string;
1694
+ return string.includes("\n") ? `\n${string}\n` : string;
1711
1695
  }
1712
1696
  function removeExtraLineBreaks(string) {
1713
- return string.length > 2 && string.startsWith("\n") && string.endsWith("\n") ? string.slice(1, -1) : string;
1697
+ return string.length > 2 && string.startsWith("\n") && string.endsWith("\n") ? string.slice(1, -1) : string;
1714
1698
  }
1715
1699
  const escapeRegex = true;
1716
1700
  const printFunctionName = false;
1717
1701
  function serialize(val, indent = 2, formatOverrides = {}) {
1718
- return normalizeNewlines(
1719
- format(val, {
1720
- escapeRegex,
1721
- indent,
1722
- plugins: getSerializers(),
1723
- printFunctionName,
1724
- ...formatOverrides
1725
- })
1726
- );
1702
+ return normalizeNewlines(format(val, {
1703
+ escapeRegex,
1704
+ indent,
1705
+ plugins: getSerializers(),
1706
+ printFunctionName,
1707
+ ...formatOverrides
1708
+ }));
1727
1709
  }
1728
1710
  function escapeBacktickString(str) {
1729
- return str.replace(/`|\\|\$\{/g, "\\$&");
1711
+ return str.replace(/`|\\|\$\{/g, "\\$&");
1730
1712
  }
1731
1713
  function printBacktickString(str) {
1732
- return `\`${escapeBacktickString(str)}\``;
1714
+ return `\`${escapeBacktickString(str)}\``;
1733
1715
  }
1734
1716
  function normalizeNewlines(string) {
1735
- return string.replace(/\r\n|\r/g, "\n");
1717
+ return string.replace(/\r\n|\r/g, "\n");
1736
1718
  }
1737
1719
  async function saveSnapshotFile(environment, snapshotData, snapshotPath) {
1738
- const snapshots = Object.keys(snapshotData).sort(naturalCompare).map(
1739
- (key) => `exports[${printBacktickString(key)}] = ${printBacktickString(
1740
- normalizeNewlines(snapshotData[key])
1741
- )};`
1742
- );
1743
- const content = `${environment.getHeader()}
1744
-
1745
- ${snapshots.join("\n\n")}
1746
- `;
1747
- const oldContent = await environment.readSnapshotFile(snapshotPath);
1748
- const skipWriting = oldContent != null && oldContent === content;
1749
- if (skipWriting) {
1750
- return;
1751
- }
1752
- await environment.saveSnapshotFile(snapshotPath, content);
1753
- }
1754
- function prepareExpected(expected) {
1755
- function findStartIndent() {
1756
- var _a, _b;
1757
- const matchObject = /^( +)\}\s+$/m.exec(expected || "");
1758
- const objectIndent = (_a = matchObject == null ? void 0 : matchObject[1]) == null ? void 0 : _a.length;
1759
- if (objectIndent) {
1760
- return objectIndent;
1761
- }
1762
- const matchText = /^\n( +)"/.exec(expected || "");
1763
- return ((_b = matchText == null ? void 0 : matchText[1]) == null ? void 0 : _b.length) || 0;
1764
- }
1765
- const startIndent = findStartIndent();
1766
- let expectedTrimmed = expected == null ? void 0 : expected.trim();
1767
- if (startIndent) {
1768
- expectedTrimmed = expectedTrimmed == null ? void 0 : expectedTrimmed.replace(new RegExp(`^${" ".repeat(startIndent)}`, "gm"), "").replace(/ +\}$/, "}");
1769
- }
1770
- return expectedTrimmed;
1720
+ const snapshots = Object.keys(snapshotData).sort(naturalCompare).map((key) => `exports[${printBacktickString(key)}] = ${printBacktickString(normalizeNewlines(snapshotData[key]))};`);
1721
+ const content = `${environment.getHeader()}\n\n${snapshots.join("\n\n")}\n`;
1722
+ const oldContent = await environment.readSnapshotFile(snapshotPath);
1723
+ const skipWriting = oldContent != null && oldContent === content;
1724
+ if (skipWriting) {
1725
+ return;
1726
+ }
1727
+ await environment.saveSnapshotFile(snapshotPath, content);
1771
1728
  }
1772
1729
  function deepMergeArray(target = [], source = []) {
1773
- const mergedOutput = Array.from(target);
1774
- source.forEach((sourceElement, index) => {
1775
- const targetElement = mergedOutput[index];
1776
- if (Array.isArray(target[index])) {
1777
- mergedOutput[index] = deepMergeArray(target[index], sourceElement);
1778
- } else if (isObject(targetElement)) {
1779
- mergedOutput[index] = deepMergeSnapshot(target[index], sourceElement);
1780
- } else {
1781
- mergedOutput[index] = sourceElement;
1782
- }
1783
- });
1784
- return mergedOutput;
1730
+ const mergedOutput = Array.from(target);
1731
+ source.forEach((sourceElement, index) => {
1732
+ const targetElement = mergedOutput[index];
1733
+ if (Array.isArray(target[index])) {
1734
+ mergedOutput[index] = deepMergeArray(target[index], sourceElement);
1735
+ } else if (isObject(targetElement)) {
1736
+ mergedOutput[index] = deepMergeSnapshot(target[index], sourceElement);
1737
+ } else {
1738
+ mergedOutput[index] = sourceElement;
1739
+ }
1740
+ });
1741
+ return mergedOutput;
1785
1742
  }
1743
+ /**
1744
+ * Deep merge, but considers asymmetric matchers. Unlike base util's deep merge,
1745
+ * will merge any object-like instance.
1746
+ * Compatible with Jest's snapshot matcher. Should not be used outside of snapshot.
1747
+ *
1748
+ * @example
1749
+ * ```ts
1750
+ * toMatchSnapshot({
1751
+ * name: expect.stringContaining('text')
1752
+ * })
1753
+ * ```
1754
+ */
1786
1755
  function deepMergeSnapshot(target, source) {
1787
- if (isObject(target) && isObject(source)) {
1788
- const mergedOutput = { ...target };
1789
- Object.keys(source).forEach((key) => {
1790
- if (isObject(source[key]) && !source[key].$$typeof) {
1791
- if (!(key in target)) {
1792
- Object.assign(mergedOutput, { [key]: source[key] });
1793
- } else {
1794
- mergedOutput[key] = deepMergeSnapshot(target[key], source[key]);
1795
- }
1796
- } else if (Array.isArray(source[key])) {
1797
- mergedOutput[key] = deepMergeArray(target[key], source[key]);
1798
- } else {
1799
- Object.assign(mergedOutput, { [key]: source[key] });
1800
- }
1801
- });
1802
- return mergedOutput;
1803
- } else if (Array.isArray(target) && Array.isArray(source)) {
1804
- return deepMergeArray(target, source);
1805
- }
1806
- return target;
1756
+ if (isObject(target) && isObject(source)) {
1757
+ const mergedOutput = { ...target };
1758
+ Object.keys(source).forEach((key) => {
1759
+ if (isObject(source[key]) && !source[key].$$typeof) {
1760
+ if (!(key in target)) {
1761
+ Object.assign(mergedOutput, { [key]: source[key] });
1762
+ } else {
1763
+ mergedOutput[key] = deepMergeSnapshot(target[key], source[key]);
1764
+ }
1765
+ } else if (Array.isArray(source[key])) {
1766
+ mergedOutput[key] = deepMergeArray(target[key], source[key]);
1767
+ } else {
1768
+ Object.assign(mergedOutput, { [key]: source[key] });
1769
+ }
1770
+ });
1771
+ return mergedOutput;
1772
+ } else if (Array.isArray(target) && Array.isArray(source)) {
1773
+ return deepMergeArray(target, source);
1774
+ }
1775
+ return target;
1807
1776
  }
1808
1777
  class DefaultMap extends Map {
1809
- constructor(defaultFn, entries) {
1810
- super(entries);
1811
- this.defaultFn = defaultFn;
1812
- }
1813
- get(key) {
1814
- if (!this.has(key)) {
1815
- this.set(key, this.defaultFn(key));
1816
- }
1817
- return super.get(key);
1818
- }
1778
+ constructor(defaultFn, entries) {
1779
+ super(entries);
1780
+ this.defaultFn = defaultFn;
1781
+ }
1782
+ get(key) {
1783
+ if (!this.has(key)) {
1784
+ this.set(key, this.defaultFn(key));
1785
+ }
1786
+ return super.get(key);
1787
+ }
1819
1788
  }
1820
1789
  class CounterMap extends DefaultMap {
1821
- constructor() {
1822
- super(() => 0);
1823
- }
1824
- // compat for jest-image-snapshot https://github.com/vitest-dev/vitest/issues/7322
1825
- // `valueOf` and `Snapshot.added` setter allows
1826
- // snapshotState.added = snapshotState.added + 1
1827
- // to function as
1828
- // snapshotState.added.total_ = snapshotState.added.total() + 1
1829
- _total;
1830
- valueOf() {
1831
- return this._total = this.total();
1832
- }
1833
- increment(key) {
1834
- if (typeof this._total !== "undefined") {
1835
- this._total++;
1836
- }
1837
- this.set(key, this.get(key) + 1);
1838
- }
1839
- total() {
1840
- if (typeof this._total !== "undefined") {
1841
- return this._total;
1842
- }
1843
- let total = 0;
1844
- for (const x of this.values()) {
1845
- total += x;
1846
- }
1847
- return total;
1848
- }
1790
+ constructor() {
1791
+ super(() => 0);
1792
+ }
1793
+ _total;
1794
+ valueOf() {
1795
+ return this._total = this.total();
1796
+ }
1797
+ increment(key) {
1798
+ if (typeof this._total !== "undefined") {
1799
+ this._total++;
1800
+ }
1801
+ this.set(key, this.get(key) + 1);
1802
+ }
1803
+ total() {
1804
+ if (typeof this._total !== "undefined") {
1805
+ return this._total;
1806
+ }
1807
+ let total = 0;
1808
+ for (const x of this.values()) {
1809
+ total += x;
1810
+ }
1811
+ return total;
1812
+ }
1849
1813
  }
1850
1814
 
1851
1815
  function isSameStackPosition(x, y) {
1852
- return x.file === y.file && x.column === y.column && x.line === y.line;
1816
+ return x.file === y.file && x.column === y.column && x.line === y.line;
1853
1817
  }
1854
1818
  class SnapshotState {
1855
- constructor(testFilePath, snapshotPath, snapshotContent, options) {
1856
- this.testFilePath = testFilePath;
1857
- this.snapshotPath = snapshotPath;
1858
- const { data, dirty } = getSnapshotData(snapshotContent, options);
1859
- this._fileExists = snapshotContent != null;
1860
- this._initialData = { ...data };
1861
- this._snapshotData = { ...data };
1862
- this._dirty = dirty;
1863
- this._inlineSnapshots = [];
1864
- this._inlineSnapshotStacks = [];
1865
- this._rawSnapshots = [];
1866
- this._uncheckedKeys = new Set(Object.keys(this._snapshotData));
1867
- this.expand = options.expand || false;
1868
- this._updateSnapshot = options.updateSnapshot;
1869
- this._snapshotFormat = {
1870
- printBasicPrototype: false,
1871
- escapeString: false,
1872
- ...options.snapshotFormat
1873
- };
1874
- this._environment = options.snapshotEnvironment;
1875
- }
1876
- _counters = new CounterMap();
1877
- _dirty;
1878
- _updateSnapshot;
1879
- _snapshotData;
1880
- _initialData;
1881
- _inlineSnapshots;
1882
- _inlineSnapshotStacks;
1883
- _testIdToKeys = new DefaultMap(() => []);
1884
- _rawSnapshots;
1885
- _uncheckedKeys;
1886
- _snapshotFormat;
1887
- _environment;
1888
- _fileExists;
1889
- expand;
1890
- // getter/setter for jest-image-snapshot compat
1891
- // https://github.com/vitest-dev/vitest/issues/7322
1892
- _added = new CounterMap();
1893
- _matched = new CounterMap();
1894
- _unmatched = new CounterMap();
1895
- _updated = new CounterMap();
1896
- get added() {
1897
- return this._added;
1898
- }
1899
- set added(value) {
1900
- this._added._total = value;
1901
- }
1902
- get matched() {
1903
- return this._matched;
1904
- }
1905
- set matched(value) {
1906
- this._matched._total = value;
1907
- }
1908
- get unmatched() {
1909
- return this._unmatched;
1910
- }
1911
- set unmatched(value) {
1912
- this._unmatched._total = value;
1913
- }
1914
- get updated() {
1915
- return this._updated;
1916
- }
1917
- set updated(value) {
1918
- this._updated._total = value;
1919
- }
1920
- static async create(testFilePath, options) {
1921
- const snapshotPath = await options.snapshotEnvironment.resolvePath(
1922
- testFilePath
1923
- );
1924
- const content = await options.snapshotEnvironment.readSnapshotFile(
1925
- snapshotPath
1926
- );
1927
- return new SnapshotState(testFilePath, snapshotPath, content, options);
1928
- }
1929
- get environment() {
1930
- return this._environment;
1931
- }
1932
- markSnapshotsAsCheckedForTest(testName) {
1933
- this._uncheckedKeys.forEach((uncheckedKey) => {
1934
- if (/ \d+$| > /.test(uncheckedKey.slice(testName.length))) {
1935
- this._uncheckedKeys.delete(uncheckedKey);
1936
- }
1937
- });
1938
- }
1939
- clearTest(testId) {
1940
- this._inlineSnapshots = this._inlineSnapshots.filter((s) => s.testId !== testId);
1941
- this._inlineSnapshotStacks = this._inlineSnapshotStacks.filter((s) => s.testId !== testId);
1942
- for (const key of this._testIdToKeys.get(testId)) {
1943
- const name = keyToTestName(key);
1944
- const count = this._counters.get(name);
1945
- if (count > 0) {
1946
- if (key in this._snapshotData || key in this._initialData) {
1947
- this._snapshotData[key] = this._initialData[key];
1948
- }
1949
- this._counters.set(name, count - 1);
1950
- }
1951
- }
1952
- this._testIdToKeys.delete(testId);
1953
- this.added.delete(testId);
1954
- this.updated.delete(testId);
1955
- this.matched.delete(testId);
1956
- this.unmatched.delete(testId);
1957
- }
1958
- _inferInlineSnapshotStack(stacks) {
1959
- const promiseIndex = stacks.findIndex(
1960
- (i) => i.method.match(/__VITEST_(RESOLVES|REJECTS)__/)
1961
- );
1962
- if (promiseIndex !== -1) {
1963
- return stacks[promiseIndex + 3];
1964
- }
1965
- const stackIndex = stacks.findIndex(
1966
- (i) => i.method.includes("__INLINE_SNAPSHOT__")
1967
- );
1968
- return stackIndex !== -1 ? stacks[stackIndex + 2] : null;
1969
- }
1970
- _addSnapshot(key, receivedSerialized, options) {
1971
- this._dirty = true;
1972
- if (options.stack) {
1973
- this._inlineSnapshots.push({
1974
- snapshot: receivedSerialized,
1975
- testId: options.testId,
1976
- ...options.stack
1977
- });
1978
- } else if (options.rawSnapshot) {
1979
- this._rawSnapshots.push({
1980
- ...options.rawSnapshot,
1981
- snapshot: receivedSerialized
1982
- });
1983
- } else {
1984
- this._snapshotData[key] = receivedSerialized;
1985
- }
1986
- }
1987
- async save() {
1988
- const hasExternalSnapshots = Object.keys(this._snapshotData).length;
1989
- const hasInlineSnapshots = this._inlineSnapshots.length;
1990
- const hasRawSnapshots = this._rawSnapshots.length;
1991
- const isEmpty = !hasExternalSnapshots && !hasInlineSnapshots && !hasRawSnapshots;
1992
- const status = {
1993
- deleted: false,
1994
- saved: false
1995
- };
1996
- if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) {
1997
- if (hasExternalSnapshots) {
1998
- await saveSnapshotFile(
1999
- this._environment,
2000
- this._snapshotData,
2001
- this.snapshotPath
2002
- );
2003
- this._fileExists = true;
2004
- }
2005
- if (hasInlineSnapshots) {
2006
- await saveInlineSnapshots(this._environment, this._inlineSnapshots);
2007
- }
2008
- if (hasRawSnapshots) {
2009
- await saveRawSnapshots(this._environment, this._rawSnapshots);
2010
- }
2011
- status.saved = true;
2012
- } else if (!hasExternalSnapshots && this._fileExists) {
2013
- if (this._updateSnapshot === "all") {
2014
- await this._environment.removeSnapshotFile(this.snapshotPath);
2015
- this._fileExists = false;
2016
- }
2017
- status.deleted = true;
2018
- }
2019
- return status;
2020
- }
2021
- getUncheckedCount() {
2022
- return this._uncheckedKeys.size || 0;
2023
- }
2024
- getUncheckedKeys() {
2025
- return Array.from(this._uncheckedKeys);
2026
- }
2027
- removeUncheckedKeys() {
2028
- if (this._updateSnapshot === "all" && this._uncheckedKeys.size) {
2029
- this._dirty = true;
2030
- this._uncheckedKeys.forEach((key) => delete this._snapshotData[key]);
2031
- this._uncheckedKeys.clear();
2032
- }
2033
- }
2034
- match({
2035
- testId,
2036
- testName,
2037
- received,
2038
- key,
2039
- inlineSnapshot,
2040
- isInline,
2041
- error,
2042
- rawSnapshot
2043
- }) {
2044
- var _a, _b;
2045
- this._counters.increment(testName);
2046
- const count = this._counters.get(testName);
2047
- if (!key) {
2048
- key = testNameToKey(testName, count);
2049
- }
2050
- this._testIdToKeys.get(testId).push(key);
2051
- if (!(isInline && this._snapshotData[key] !== void 0)) {
2052
- this._uncheckedKeys.delete(key);
2053
- }
2054
- let receivedSerialized = rawSnapshot && typeof received === "string" ? received : serialize(received, void 0, this._snapshotFormat);
2055
- if (!rawSnapshot) {
2056
- receivedSerialized = addExtraLineBreaks(receivedSerialized);
2057
- }
2058
- if (rawSnapshot) {
2059
- if (rawSnapshot.content && rawSnapshot.content.match(/\r\n/) && !receivedSerialized.match(/\r\n/)) {
2060
- rawSnapshot.content = normalizeNewlines(rawSnapshot.content);
2061
- }
2062
- }
2063
- const expected = isInline ? inlineSnapshot : rawSnapshot ? rawSnapshot.content : this._snapshotData[key];
2064
- const expectedTrimmed = rawSnapshot ? expected : prepareExpected(expected);
2065
- const pass = expectedTrimmed === (rawSnapshot ? receivedSerialized : prepareExpected(receivedSerialized));
2066
- const hasSnapshot = expected !== void 0;
2067
- const snapshotIsPersisted = isInline || this._fileExists || rawSnapshot && rawSnapshot.content != null;
2068
- if (pass && !isInline && !rawSnapshot) {
2069
- this._snapshotData[key] = receivedSerialized;
2070
- }
2071
- let stack;
2072
- if (isInline) {
2073
- const stacks = parseErrorStacktrace(
2074
- error || new Error("snapshot"),
2075
- { ignoreStackEntries: [] }
2076
- );
2077
- const _stack = this._inferInlineSnapshotStack(stacks);
2078
- if (!_stack) {
2079
- throw new Error(
2080
- `@vitest/snapshot: Couldn't infer stack frame for inline snapshot.
2081
- ${JSON.stringify(
2082
- stacks
2083
- )}`
2084
- );
2085
- }
2086
- stack = ((_b = (_a = this.environment).processStackTrace) == null ? void 0 : _b.call(_a, _stack)) || _stack;
2087
- stack.column--;
2088
- const snapshotsWithSameStack = this._inlineSnapshotStacks.filter((s) => isSameStackPosition(s, stack));
2089
- if (snapshotsWithSameStack.length > 0) {
2090
- this._inlineSnapshots = this._inlineSnapshots.filter((s) => !isSameStackPosition(s, stack));
2091
- const differentSnapshot = snapshotsWithSameStack.find((s) => s.snapshot !== receivedSerialized);
2092
- if (differentSnapshot) {
2093
- throw Object.assign(
2094
- new Error(
2095
- "toMatchInlineSnapshot with different snapshots cannot be called at the same location"
2096
- ),
2097
- {
2098
- actual: receivedSerialized,
2099
- expected: differentSnapshot.snapshot
2100
- }
2101
- );
2102
- }
2103
- }
2104
- this._inlineSnapshotStacks.push({ ...stack, testId, snapshot: receivedSerialized });
2105
- }
2106
- if (hasSnapshot && this._updateSnapshot === "all" || (!hasSnapshot || !snapshotIsPersisted) && (this._updateSnapshot === "new" || this._updateSnapshot === "all")) {
2107
- if (this._updateSnapshot === "all") {
2108
- if (!pass) {
2109
- if (hasSnapshot) {
2110
- this.updated.increment(testId);
2111
- } else {
2112
- this.added.increment(testId);
2113
- }
2114
- this._addSnapshot(key, receivedSerialized, {
2115
- stack,
2116
- testId,
2117
- rawSnapshot
2118
- });
2119
- } else {
2120
- this.matched.increment(testId);
2121
- }
2122
- } else {
2123
- this._addSnapshot(key, receivedSerialized, {
2124
- stack,
2125
- testId,
2126
- rawSnapshot
2127
- });
2128
- this.added.increment(testId);
2129
- }
2130
- return {
2131
- actual: "",
2132
- count,
2133
- expected: "",
2134
- key,
2135
- pass: true
2136
- };
2137
- } else {
2138
- if (!pass) {
2139
- this.unmatched.increment(testId);
2140
- return {
2141
- actual: rawSnapshot ? receivedSerialized : removeExtraLineBreaks(receivedSerialized),
2142
- count,
2143
- expected: expectedTrimmed !== void 0 ? rawSnapshot ? expectedTrimmed : removeExtraLineBreaks(expectedTrimmed) : void 0,
2144
- key,
2145
- pass: false
2146
- };
2147
- } else {
2148
- this.matched.increment(testId);
2149
- return {
2150
- actual: "",
2151
- count,
2152
- expected: "",
2153
- key,
2154
- pass: true
2155
- };
2156
- }
2157
- }
2158
- }
2159
- async pack() {
2160
- const snapshot = {
2161
- filepath: this.testFilePath,
2162
- added: 0,
2163
- fileDeleted: false,
2164
- matched: 0,
2165
- unchecked: 0,
2166
- uncheckedKeys: [],
2167
- unmatched: 0,
2168
- updated: 0
2169
- };
2170
- const uncheckedCount = this.getUncheckedCount();
2171
- const uncheckedKeys = this.getUncheckedKeys();
2172
- if (uncheckedCount) {
2173
- this.removeUncheckedKeys();
2174
- }
2175
- const status = await this.save();
2176
- snapshot.fileDeleted = status.deleted;
2177
- snapshot.added = this.added.total();
2178
- snapshot.matched = this.matched.total();
2179
- snapshot.unmatched = this.unmatched.total();
2180
- snapshot.updated = this.updated.total();
2181
- snapshot.unchecked = !status.deleted ? uncheckedCount : 0;
2182
- snapshot.uncheckedKeys = Array.from(uncheckedKeys);
2183
- return snapshot;
2184
- }
1819
+ _counters = new CounterMap();
1820
+ _dirty;
1821
+ _updateSnapshot;
1822
+ _snapshotData;
1823
+ _initialData;
1824
+ _inlineSnapshots;
1825
+ _inlineSnapshotStacks;
1826
+ _testIdToKeys = new DefaultMap(() => []);
1827
+ _rawSnapshots;
1828
+ _uncheckedKeys;
1829
+ _snapshotFormat;
1830
+ _environment;
1831
+ _fileExists;
1832
+ expand;
1833
+ _added = new CounterMap();
1834
+ _matched = new CounterMap();
1835
+ _unmatched = new CounterMap();
1836
+ _updated = new CounterMap();
1837
+ get added() {
1838
+ return this._added;
1839
+ }
1840
+ set added(value) {
1841
+ this._added._total = value;
1842
+ }
1843
+ get matched() {
1844
+ return this._matched;
1845
+ }
1846
+ set matched(value) {
1847
+ this._matched._total = value;
1848
+ }
1849
+ get unmatched() {
1850
+ return this._unmatched;
1851
+ }
1852
+ set unmatched(value) {
1853
+ this._unmatched._total = value;
1854
+ }
1855
+ get updated() {
1856
+ return this._updated;
1857
+ }
1858
+ set updated(value) {
1859
+ this._updated._total = value;
1860
+ }
1861
+ constructor(testFilePath, snapshotPath, snapshotContent, options) {
1862
+ this.testFilePath = testFilePath;
1863
+ this.snapshotPath = snapshotPath;
1864
+ const { data, dirty } = getSnapshotData(snapshotContent, options);
1865
+ this._fileExists = snapshotContent != null;
1866
+ this._initialData = { ...data };
1867
+ this._snapshotData = { ...data };
1868
+ this._dirty = dirty;
1869
+ this._inlineSnapshots = [];
1870
+ this._inlineSnapshotStacks = [];
1871
+ this._rawSnapshots = [];
1872
+ this._uncheckedKeys = new Set(Object.keys(this._snapshotData));
1873
+ this.expand = options.expand || false;
1874
+ this._updateSnapshot = options.updateSnapshot;
1875
+ this._snapshotFormat = {
1876
+ printBasicPrototype: false,
1877
+ escapeString: false,
1878
+ ...options.snapshotFormat
1879
+ };
1880
+ this._environment = options.snapshotEnvironment;
1881
+ }
1882
+ static async create(testFilePath, options) {
1883
+ const snapshotPath = await options.snapshotEnvironment.resolvePath(testFilePath);
1884
+ const content = await options.snapshotEnvironment.readSnapshotFile(snapshotPath);
1885
+ return new SnapshotState(testFilePath, snapshotPath, content, options);
1886
+ }
1887
+ get environment() {
1888
+ return this._environment;
1889
+ }
1890
+ markSnapshotsAsCheckedForTest(testName) {
1891
+ this._uncheckedKeys.forEach((uncheckedKey) => {
1892
+ if (/ \d+$| > /.test(uncheckedKey.slice(testName.length))) {
1893
+ this._uncheckedKeys.delete(uncheckedKey);
1894
+ }
1895
+ });
1896
+ }
1897
+ clearTest(testId) {
1898
+ this._inlineSnapshots = this._inlineSnapshots.filter((s) => s.testId !== testId);
1899
+ this._inlineSnapshotStacks = this._inlineSnapshotStacks.filter((s) => s.testId !== testId);
1900
+ for (const key of this._testIdToKeys.get(testId)) {
1901
+ const name = keyToTestName(key);
1902
+ const count = this._counters.get(name);
1903
+ if (count > 0) {
1904
+ if (key in this._snapshotData || key in this._initialData) {
1905
+ this._snapshotData[key] = this._initialData[key];
1906
+ }
1907
+ this._counters.set(name, count - 1);
1908
+ }
1909
+ }
1910
+ this._testIdToKeys.delete(testId);
1911
+ this.added.delete(testId);
1912
+ this.updated.delete(testId);
1913
+ this.matched.delete(testId);
1914
+ this.unmatched.delete(testId);
1915
+ }
1916
+ _inferInlineSnapshotStack(stacks) {
1917
+ const promiseIndex = stacks.findIndex((i) => i.method.match(/__VITEST_(RESOLVES|REJECTS)__/));
1918
+ if (promiseIndex !== -1) {
1919
+ return stacks[promiseIndex + 3];
1920
+ }
1921
+ const stackIndex = stacks.findIndex((i) => i.method.includes("__INLINE_SNAPSHOT__"));
1922
+ return stackIndex !== -1 ? stacks[stackIndex + 2] : null;
1923
+ }
1924
+ _addSnapshot(key, receivedSerialized, options) {
1925
+ this._dirty = true;
1926
+ if (options.stack) {
1927
+ this._inlineSnapshots.push({
1928
+ snapshot: receivedSerialized,
1929
+ testId: options.testId,
1930
+ ...options.stack
1931
+ });
1932
+ } else if (options.rawSnapshot) {
1933
+ this._rawSnapshots.push({
1934
+ ...options.rawSnapshot,
1935
+ snapshot: receivedSerialized
1936
+ });
1937
+ } else {
1938
+ this._snapshotData[key] = receivedSerialized;
1939
+ }
1940
+ }
1941
+ async save() {
1942
+ const hasExternalSnapshots = Object.keys(this._snapshotData).length;
1943
+ const hasInlineSnapshots = this._inlineSnapshots.length;
1944
+ const hasRawSnapshots = this._rawSnapshots.length;
1945
+ const isEmpty = !hasExternalSnapshots && !hasInlineSnapshots && !hasRawSnapshots;
1946
+ const status = {
1947
+ deleted: false,
1948
+ saved: false
1949
+ };
1950
+ if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) {
1951
+ if (hasExternalSnapshots) {
1952
+ await saveSnapshotFile(this._environment, this._snapshotData, this.snapshotPath);
1953
+ this._fileExists = true;
1954
+ }
1955
+ if (hasInlineSnapshots) {
1956
+ await saveInlineSnapshots(this._environment, this._inlineSnapshots);
1957
+ }
1958
+ if (hasRawSnapshots) {
1959
+ await saveRawSnapshots(this._environment, this._rawSnapshots);
1960
+ }
1961
+ status.saved = true;
1962
+ } else if (!hasExternalSnapshots && this._fileExists) {
1963
+ if (this._updateSnapshot === "all") {
1964
+ await this._environment.removeSnapshotFile(this.snapshotPath);
1965
+ this._fileExists = false;
1966
+ }
1967
+ status.deleted = true;
1968
+ }
1969
+ return status;
1970
+ }
1971
+ getUncheckedCount() {
1972
+ return this._uncheckedKeys.size || 0;
1973
+ }
1974
+ getUncheckedKeys() {
1975
+ return Array.from(this._uncheckedKeys);
1976
+ }
1977
+ removeUncheckedKeys() {
1978
+ if (this._updateSnapshot === "all" && this._uncheckedKeys.size) {
1979
+ this._dirty = true;
1980
+ this._uncheckedKeys.forEach((key) => delete this._snapshotData[key]);
1981
+ this._uncheckedKeys.clear();
1982
+ }
1983
+ }
1984
+ match({ testId, testName, received, key, inlineSnapshot, isInline, error, rawSnapshot }) {
1985
+ this._counters.increment(testName);
1986
+ const count = this._counters.get(testName);
1987
+ if (!key) {
1988
+ key = testNameToKey(testName, count);
1989
+ }
1990
+ this._testIdToKeys.get(testId).push(key);
1991
+ if (!(isInline && this._snapshotData[key] !== undefined)) {
1992
+ this._uncheckedKeys.delete(key);
1993
+ }
1994
+ let receivedSerialized = rawSnapshot && typeof received === "string" ? received : serialize(received, undefined, this._snapshotFormat);
1995
+ if (!rawSnapshot) {
1996
+ receivedSerialized = addExtraLineBreaks(receivedSerialized);
1997
+ }
1998
+ if (rawSnapshot) {
1999
+ if (rawSnapshot.content && rawSnapshot.content.match(/\r\n/) && !receivedSerialized.match(/\r\n/)) {
2000
+ rawSnapshot.content = normalizeNewlines(rawSnapshot.content);
2001
+ }
2002
+ }
2003
+ const expected = isInline ? inlineSnapshot : rawSnapshot ? rawSnapshot.content : this._snapshotData[key];
2004
+ const expectedTrimmed = rawSnapshot ? expected : expected === null || expected === void 0 ? void 0 : expected.trim();
2005
+ const pass = expectedTrimmed === (rawSnapshot ? receivedSerialized : receivedSerialized.trim());
2006
+ const hasSnapshot = expected !== undefined;
2007
+ const snapshotIsPersisted = isInline || this._fileExists || rawSnapshot && rawSnapshot.content != null;
2008
+ if (pass && !isInline && !rawSnapshot) {
2009
+ this._snapshotData[key] = receivedSerialized;
2010
+ }
2011
+ let stack;
2012
+ if (isInline) {
2013
+ var _this$environment$pro, _this$environment;
2014
+ const stacks = parseErrorStacktrace(error || new Error("snapshot"), { ignoreStackEntries: [] });
2015
+ const _stack = this._inferInlineSnapshotStack(stacks);
2016
+ if (!_stack) {
2017
+ throw new Error(`@vitest/snapshot: Couldn't infer stack frame for inline snapshot.\n${JSON.stringify(stacks)}`);
2018
+ }
2019
+ stack = ((_this$environment$pro = (_this$environment = this.environment).processStackTrace) === null || _this$environment$pro === void 0 ? void 0 : _this$environment$pro.call(_this$environment, _stack)) || _stack;
2020
+ stack.column--;
2021
+ const snapshotsWithSameStack = this._inlineSnapshotStacks.filter((s) => isSameStackPosition(s, stack));
2022
+ if (snapshotsWithSameStack.length > 0) {
2023
+ this._inlineSnapshots = this._inlineSnapshots.filter((s) => !isSameStackPosition(s, stack));
2024
+ const differentSnapshot = snapshotsWithSameStack.find((s) => s.snapshot !== receivedSerialized);
2025
+ if (differentSnapshot) {
2026
+ throw Object.assign(new Error("toMatchInlineSnapshot with different snapshots cannot be called at the same location"), {
2027
+ actual: receivedSerialized,
2028
+ expected: differentSnapshot.snapshot
2029
+ });
2030
+ }
2031
+ }
2032
+ this._inlineSnapshotStacks.push({
2033
+ ...stack,
2034
+ testId,
2035
+ snapshot: receivedSerialized
2036
+ });
2037
+ }
2038
+ if (hasSnapshot && this._updateSnapshot === "all" || (!hasSnapshot || !snapshotIsPersisted) && (this._updateSnapshot === "new" || this._updateSnapshot === "all")) {
2039
+ if (this._updateSnapshot === "all") {
2040
+ if (!pass) {
2041
+ if (hasSnapshot) {
2042
+ this.updated.increment(testId);
2043
+ } else {
2044
+ this.added.increment(testId);
2045
+ }
2046
+ this._addSnapshot(key, receivedSerialized, {
2047
+ stack,
2048
+ testId,
2049
+ rawSnapshot
2050
+ });
2051
+ } else {
2052
+ this.matched.increment(testId);
2053
+ }
2054
+ } else {
2055
+ this._addSnapshot(key, receivedSerialized, {
2056
+ stack,
2057
+ testId,
2058
+ rawSnapshot
2059
+ });
2060
+ this.added.increment(testId);
2061
+ }
2062
+ return {
2063
+ actual: "",
2064
+ count,
2065
+ expected: "",
2066
+ key,
2067
+ pass: true
2068
+ };
2069
+ } else {
2070
+ if (!pass) {
2071
+ this.unmatched.increment(testId);
2072
+ return {
2073
+ actual: rawSnapshot ? receivedSerialized : removeExtraLineBreaks(receivedSerialized),
2074
+ count,
2075
+ expected: expectedTrimmed !== undefined ? rawSnapshot ? expectedTrimmed : removeExtraLineBreaks(expectedTrimmed) : undefined,
2076
+ key,
2077
+ pass: false
2078
+ };
2079
+ } else {
2080
+ this.matched.increment(testId);
2081
+ return {
2082
+ actual: "",
2083
+ count,
2084
+ expected: "",
2085
+ key,
2086
+ pass: true
2087
+ };
2088
+ }
2089
+ }
2090
+ }
2091
+ async pack() {
2092
+ const snapshot = {
2093
+ filepath: this.testFilePath,
2094
+ added: 0,
2095
+ fileDeleted: false,
2096
+ matched: 0,
2097
+ unchecked: 0,
2098
+ uncheckedKeys: [],
2099
+ unmatched: 0,
2100
+ updated: 0
2101
+ };
2102
+ const uncheckedCount = this.getUncheckedCount();
2103
+ const uncheckedKeys = this.getUncheckedKeys();
2104
+ if (uncheckedCount) {
2105
+ this.removeUncheckedKeys();
2106
+ }
2107
+ const status = await this.save();
2108
+ snapshot.fileDeleted = status.deleted;
2109
+ snapshot.added = this.added.total();
2110
+ snapshot.matched = this.matched.total();
2111
+ snapshot.unmatched = this.unmatched.total();
2112
+ snapshot.updated = this.updated.total();
2113
+ snapshot.unchecked = !status.deleted ? uncheckedCount : 0;
2114
+ snapshot.uncheckedKeys = Array.from(uncheckedKeys);
2115
+ return snapshot;
2116
+ }
2185
2117
  }
2186
2118
 
2187
2119
  function createMismatchError(message, expand, actual, expected) {
2188
- const error = new Error(message);
2189
- Object.defineProperty(error, "actual", {
2190
- value: actual,
2191
- enumerable: true,
2192
- configurable: true,
2193
- writable: true
2194
- });
2195
- Object.defineProperty(error, "expected", {
2196
- value: expected,
2197
- enumerable: true,
2198
- configurable: true,
2199
- writable: true
2200
- });
2201
- Object.defineProperty(error, "diffOptions", { value: { expand } });
2202
- return error;
2120
+ const error = new Error(message);
2121
+ Object.defineProperty(error, "actual", {
2122
+ value: actual,
2123
+ enumerable: true,
2124
+ configurable: true,
2125
+ writable: true
2126
+ });
2127
+ Object.defineProperty(error, "expected", {
2128
+ value: expected,
2129
+ enumerable: true,
2130
+ configurable: true,
2131
+ writable: true
2132
+ });
2133
+ Object.defineProperty(error, "diffOptions", { value: { expand } });
2134
+ return error;
2203
2135
  }
2204
2136
  class SnapshotClient {
2205
- constructor(options = {}) {
2206
- this.options = options;
2207
- }
2208
- snapshotStateMap = /* @__PURE__ */ new Map();
2209
- async setup(filepath, options) {
2210
- if (this.snapshotStateMap.has(filepath)) {
2211
- return;
2212
- }
2213
- this.snapshotStateMap.set(
2214
- filepath,
2215
- await SnapshotState.create(filepath, options)
2216
- );
2217
- }
2218
- async finish(filepath) {
2219
- const state = this.getSnapshotState(filepath);
2220
- const result = await state.pack();
2221
- this.snapshotStateMap.delete(filepath);
2222
- return result;
2223
- }
2224
- skipTest(filepath, testName) {
2225
- const state = this.getSnapshotState(filepath);
2226
- state.markSnapshotsAsCheckedForTest(testName);
2227
- }
2228
- clearTest(filepath, testId) {
2229
- const state = this.getSnapshotState(filepath);
2230
- state.clearTest(testId);
2231
- }
2232
- getSnapshotState(filepath) {
2233
- const state = this.snapshotStateMap.get(filepath);
2234
- if (!state) {
2235
- throw new Error(
2236
- `The snapshot state for '${filepath}' is not found. Did you call 'SnapshotClient.setup()'?`
2237
- );
2238
- }
2239
- return state;
2240
- }
2241
- assert(options) {
2242
- var _a, _b;
2243
- const {
2244
- filepath,
2245
- name,
2246
- testId = name,
2247
- message,
2248
- isInline = false,
2249
- properties,
2250
- inlineSnapshot,
2251
- error,
2252
- errorMessage,
2253
- rawSnapshot
2254
- } = options;
2255
- let { received } = options;
2256
- if (!filepath) {
2257
- throw new Error("Snapshot cannot be used outside of test");
2258
- }
2259
- const snapshotState = this.getSnapshotState(filepath);
2260
- if (typeof properties === "object") {
2261
- if (typeof received !== "object" || !received) {
2262
- throw new Error(
2263
- "Received value must be an object when the matcher has properties"
2264
- );
2265
- }
2266
- try {
2267
- const pass2 = ((_b = (_a = this.options).isEqual) == null ? void 0 : _b.call(_a, received, properties)) ?? false;
2268
- if (!pass2) {
2269
- throw createMismatchError(
2270
- "Snapshot properties mismatched",
2271
- snapshotState.expand,
2272
- received,
2273
- properties
2274
- );
2275
- } else {
2276
- received = deepMergeSnapshot(received, properties);
2277
- }
2278
- } catch (err) {
2279
- err.message = errorMessage || "Snapshot mismatched";
2280
- throw err;
2281
- }
2282
- }
2283
- const testName = [name, ...message ? [message] : []].join(" > ");
2284
- const { actual, expected, key, pass } = snapshotState.match({
2285
- testId,
2286
- testName,
2287
- received,
2288
- isInline,
2289
- error,
2290
- inlineSnapshot,
2291
- rawSnapshot
2292
- });
2293
- if (!pass) {
2294
- throw createMismatchError(
2295
- `Snapshot \`${key || "unknown"}\` mismatched`,
2296
- snapshotState.expand,
2297
- rawSnapshot ? actual : actual == null ? void 0 : actual.trim(),
2298
- rawSnapshot ? expected : expected == null ? void 0 : expected.trim()
2299
- );
2300
- }
2301
- }
2302
- async assertRaw(options) {
2303
- if (!options.rawSnapshot) {
2304
- throw new Error("Raw snapshot is required");
2305
- }
2306
- const { filepath, rawSnapshot } = options;
2307
- if (rawSnapshot.content == null) {
2308
- if (!filepath) {
2309
- throw new Error("Snapshot cannot be used outside of test");
2310
- }
2311
- const snapshotState = this.getSnapshotState(filepath);
2312
- options.filepath || (options.filepath = filepath);
2313
- rawSnapshot.file = await snapshotState.environment.resolveRawPath(
2314
- filepath,
2315
- rawSnapshot.file
2316
- );
2317
- rawSnapshot.content = await snapshotState.environment.readSnapshotFile(rawSnapshot.file) ?? void 0;
2318
- }
2319
- return this.assert(options);
2320
- }
2321
- clear() {
2322
- this.snapshotStateMap.clear();
2323
- }
2137
+ snapshotStateMap = new Map();
2138
+ constructor(options = {}) {
2139
+ this.options = options;
2140
+ }
2141
+ async setup(filepath, options) {
2142
+ if (this.snapshotStateMap.has(filepath)) {
2143
+ return;
2144
+ }
2145
+ this.snapshotStateMap.set(filepath, await SnapshotState.create(filepath, options));
2146
+ }
2147
+ async finish(filepath) {
2148
+ const state = this.getSnapshotState(filepath);
2149
+ const result = await state.pack();
2150
+ this.snapshotStateMap.delete(filepath);
2151
+ return result;
2152
+ }
2153
+ skipTest(filepath, testName) {
2154
+ const state = this.getSnapshotState(filepath);
2155
+ state.markSnapshotsAsCheckedForTest(testName);
2156
+ }
2157
+ clearTest(filepath, testId) {
2158
+ const state = this.getSnapshotState(filepath);
2159
+ state.clearTest(testId);
2160
+ }
2161
+ getSnapshotState(filepath) {
2162
+ const state = this.snapshotStateMap.get(filepath);
2163
+ if (!state) {
2164
+ throw new Error(`The snapshot state for '${filepath}' is not found. Did you call 'SnapshotClient.setup()'?`);
2165
+ }
2166
+ return state;
2167
+ }
2168
+ assert(options) {
2169
+ const { filepath, name, testId = name, message, isInline = false, properties, inlineSnapshot, error, errorMessage, rawSnapshot } = options;
2170
+ let { received } = options;
2171
+ if (!filepath) {
2172
+ throw new Error("Snapshot cannot be used outside of test");
2173
+ }
2174
+ const snapshotState = this.getSnapshotState(filepath);
2175
+ if (typeof properties === "object") {
2176
+ if (typeof received !== "object" || !received) {
2177
+ throw new Error("Received value must be an object when the matcher has properties");
2178
+ }
2179
+ try {
2180
+ var _this$options$isEqual, _this$options;
2181
+ const pass = ((_this$options$isEqual = (_this$options = this.options).isEqual) === null || _this$options$isEqual === void 0 ? void 0 : _this$options$isEqual.call(_this$options, received, properties)) ?? false;
2182
+ if (!pass) {
2183
+ throw createMismatchError("Snapshot properties mismatched", snapshotState.expand, received, properties);
2184
+ } else {
2185
+ received = deepMergeSnapshot(received, properties);
2186
+ }
2187
+ } catch (err) {
2188
+ err.message = errorMessage || "Snapshot mismatched";
2189
+ throw err;
2190
+ }
2191
+ }
2192
+ const testName = [name, ...message ? [message] : []].join(" > ");
2193
+ const { actual, expected, key, pass } = snapshotState.match({
2194
+ testId,
2195
+ testName,
2196
+ received,
2197
+ isInline,
2198
+ error,
2199
+ inlineSnapshot,
2200
+ rawSnapshot
2201
+ });
2202
+ if (!pass) {
2203
+ throw createMismatchError(`Snapshot \`${key || "unknown"}\` mismatched`, snapshotState.expand, rawSnapshot ? actual : actual === null || actual === void 0 ? void 0 : actual.trim(), rawSnapshot ? expected : expected === null || expected === void 0 ? void 0 : expected.trim());
2204
+ }
2205
+ }
2206
+ async assertRaw(options) {
2207
+ if (!options.rawSnapshot) {
2208
+ throw new Error("Raw snapshot is required");
2209
+ }
2210
+ const { filepath, rawSnapshot } = options;
2211
+ if (rawSnapshot.content == null) {
2212
+ if (!filepath) {
2213
+ throw new Error("Snapshot cannot be used outside of test");
2214
+ }
2215
+ const snapshotState = this.getSnapshotState(filepath);
2216
+ options.filepath || (options.filepath = filepath);
2217
+ rawSnapshot.file = await snapshotState.environment.resolveRawPath(filepath, rawSnapshot.file);
2218
+ rawSnapshot.content = await snapshotState.environment.readSnapshotFile(rawSnapshot.file) ?? undefined;
2219
+ }
2220
+ return this.assert(options);
2221
+ }
2222
+ clear() {
2223
+ this.snapshotStateMap.clear();
2224
+ }
2324
2225
  }
2325
2226
 
2326
2227
  export { SnapshotClient, SnapshotState, addSerializer, getSerializers, stripSnapshotIndentation };