vitest 2.1.5 → 2.2.0-beta.2

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.
Files changed (45) hide show
  1. package/LICENSE.md +0 -75
  2. package/dist/browser.d.ts +11 -11
  3. package/dist/browser.js +1 -1
  4. package/dist/chunks/{RandomSequencer.CMRlh2v4.js → RandomSequencer.BPedXEug.js} +1 -0
  5. package/dist/chunks/{base.BZZh4cSm.js → base.BS0HhLXd.js} +1 -1
  6. package/dist/chunks/{benchmark.geERunq4.d.ts → benchmark.CFFwLv-O.d.ts} +2 -2
  7. package/dist/chunks/{cac.DWAW3Uh5.js → cac.Cs06pOqp.js} +56 -7
  8. package/dist/chunks/{cli-api.BtqJwSCh.js → cli-api.CB-jIbYQ.js} +585 -407
  9. package/dist/chunks/{config.Cy0C388Z.d.ts → config.CPguQ7J1.d.ts} +2 -1
  10. package/dist/chunks/{environment.LoooBwUu.d.ts → environment.CT0jpO-1.d.ts} +2 -1
  11. package/dist/chunks/{globals.D8ZVAdXd.js → globals.BCGEw6ON.js} +2 -2
  12. package/dist/chunks/{index.nEwtF0bu.js → index.BjjsHdBb.js} +1 -1
  13. package/dist/chunks/{index.ckWaX2gY.js → index.DD5eTY2y.js} +2 -8
  14. package/dist/chunks/{index.DsZFoqi9.js → index.bzFpKeaq.js} +601 -807
  15. package/dist/chunks/{reporters.D7Jzd9GS.d.ts → reporters.F9D2idOT.d.ts} +1429 -1286
  16. package/dist/chunks/{resolveConfig.RxKrDli4.js → resolveConfig.CLnvCvEs.js} +11 -9
  17. package/dist/chunks/{runBaseTests.3qpJUEJM.js → runBaseTests.B7hcVT-s.js} +4 -4
  18. package/dist/chunks/{setup-common.Dj6BZI3u.js → setup-common.BfGt8K-K.js} +4 -1
  19. package/dist/chunks/{suite.B2jumIFP.d.ts → suite.BJU7kdY9.d.ts} +4 -4
  20. package/dist/chunks/{utils.DNoFbBUZ.js → utils.DJONn5B5.js} +15 -21
  21. package/dist/chunks/{vi.DgezovHB.js → vi.BlPttogV.js} +6 -1
  22. package/dist/chunks/{vite.C-N5BBZe.d.ts → vite.DonA4fvH.d.ts} +1 -1
  23. package/dist/chunks/{worker.tN5KGIih.d.ts → worker.9VY11NZs.d.ts} +2 -2
  24. package/dist/chunks/{worker.B9FxPCaC.d.ts → worker.Qz1UB4Fv.d.ts} +1 -1
  25. package/dist/cli.js +1 -1
  26. package/dist/config.d.ts +13 -11
  27. package/dist/coverage.d.ts +9 -112
  28. package/dist/coverage.js +2 -2
  29. package/dist/environments.d.ts +2 -2
  30. package/dist/execute.d.ts +4 -3
  31. package/dist/index.d.ts +14 -13
  32. package/dist/index.js +2 -2
  33. package/dist/node.d.ts +26 -15
  34. package/dist/node.js +9 -9
  35. package/dist/reporters.d.ts +9 -8
  36. package/dist/reporters.js +4 -5
  37. package/dist/runners.d.ts +5 -3
  38. package/dist/runners.js +4 -1
  39. package/dist/suite.d.ts +2 -2
  40. package/dist/workers/forks.js +1 -1
  41. package/dist/workers/runVmTests.js +4 -4
  42. package/dist/workers/threads.js +1 -1
  43. package/dist/workers.d.ts +5 -4
  44. package/dist/workers.js +1 -1
  45. package/package.json +13 -12
@@ -3,85 +3,22 @@ import { getTests, getTestName, hasFailed, getFullName, getSuites, getTasks } fr
3
3
  import * as pathe from 'pathe';
4
4
  import { extname, relative, normalize, resolve, dirname } from 'pathe';
5
5
  import c from 'tinyrainbow';
6
- import { d as divider, F as F_POINTER, w as withLabel, f as formatProjectName, a as formatTimeString, g as getStateSymbol, t as taskFail, b as F_RIGHT, c as F_CHECK, r as renderSnapshotSummary, e as getStateString, h as countTestErrors, i as getCols, j as getHookStateSymbol } from './utils.DNoFbBUZ.js';
6
+ import { d as divider, F as F_POINTER, w as withLabel, f as formatProjectName, a as formatTimeString, g as getStateSymbol, t as taskFail, b as F_RIGHT, c as F_CHECK, r as renderSnapshotSummary, p as padSummaryTitle, e as getStateString$1, h as formatTime, i as countTestErrors, j as F_TREE_NODE_END, k as F_TREE_NODE_MIDDLE, l as getCols } from './utils.DJONn5B5.js';
7
7
  import { stripVTControlCharacters } from 'node:util';
8
8
  import { highlight, isPrimitive, inspect, positionToOffset, lineSplitRE, toArray, notNullish } from '@vitest/utils';
9
- import { performance } from 'node:perf_hooks';
9
+ import { performance as performance$1 } from 'node:perf_hooks';
10
10
  import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
11
- import { a as TypeCheckError, R as RandomSequencer, g as getOutputFile, b as isNode, c as isDeno } from './RandomSequencer.CMRlh2v4.js';
11
+ import { a as TypeCheckError, R as RandomSequencer, g as getOutputFile, b as isNode, c as isDeno } from './RandomSequencer.BPedXEug.js';
12
12
  import { isCI } from 'std-env';
13
13
  import { mkdir, writeFile, readdir, stat, readFile } from 'node:fs/promises';
14
+ import restoreCursor from 'restore-cursor';
14
15
  import { Writable } from 'node:stream';
15
16
  import { Console } from 'node:console';
16
17
  import process$1 from 'node:process';
17
- import { g as getDefaultExportFromCjs, c as commonjsGlobal } from './_commonjsHelpers.BFTU3MAI.js';
18
- import require$$0 from 'assert';
19
- import require$$0$1 from 'events';
18
+ import { g as getDefaultExportFromCjs } from './_commonjsHelpers.BFTU3MAI.js';
20
19
  import { createRequire } from 'node:module';
21
20
  import { hostname } from 'node:os';
22
21
 
23
- class TestProject {
24
- /**
25
- * The global vitest instance.
26
- * @experimental The public Vitest API is experimental and does not follow semver.
27
- */
28
- vitest;
29
- /**
30
- * The workspace project this test project is associated with.
31
- * @experimental The public Vitest API is experimental and does not follow semver.
32
- */
33
- workspaceProject;
34
- /**
35
- * Vite's dev server instance. Every workspace project has its own server.
36
- */
37
- vite;
38
- /**
39
- * Resolved project configuration.
40
- */
41
- config;
42
- /**
43
- * Resolved global configuration. If there are no workspace projects, this will be the same as `config`.
44
- */
45
- globalConfig;
46
- /**
47
- * The name of the project or an empty string if not set.
48
- */
49
- name;
50
- constructor(workspaceProject) {
51
- this.workspaceProject = workspaceProject;
52
- this.vitest = workspaceProject.ctx;
53
- this.vite = workspaceProject.server;
54
- this.globalConfig = workspaceProject.ctx.config;
55
- this.config = workspaceProject.config;
56
- this.name = workspaceProject.getName();
57
- }
58
- /**
59
- * Serialized project configuration. This is the config that tests receive.
60
- */
61
- get serializedConfig() {
62
- return this.workspaceProject.getSerializableConfig();
63
- }
64
- /**
65
- * Custom context provided to the project.
66
- */
67
- context() {
68
- return this.workspaceProject.getProvidedContext();
69
- }
70
- /**
71
- * Provide a custom serializable context to the project. This context will be available for tests once they run.
72
- */
73
- provide(key, value) {
74
- this.workspaceProject.provide(key, value);
75
- }
76
- toJSON() {
77
- return {
78
- name: this.name,
79
- serializedConfig: this.serializedConfig,
80
- context: this.context()
81
- };
82
- }
83
- }
84
-
85
22
  class ReportedTaskImplementation {
86
23
  /**
87
24
  * Task instance.
@@ -104,7 +41,7 @@ class ReportedTaskImplementation {
104
41
  location;
105
42
  constructor(task, project) {
106
43
  this.task = task;
107
- this.project = project.testProject || (project.testProject = new TestProject(project));
44
+ this.project = project;
108
45
  this.id = task.id;
109
46
  this.location = task.location;
110
47
  }
@@ -170,9 +107,22 @@ class TestCase extends ReportedTaskImplementation {
170
107
  return void 0;
171
108
  }
172
109
  const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
110
+ if (state === "skipped") {
111
+ return {
112
+ state,
113
+ note: result.note,
114
+ errors: void 0
115
+ };
116
+ }
117
+ if (state === "passed") {
118
+ return {
119
+ state,
120
+ errors: result.errors
121
+ };
122
+ }
173
123
  return {
174
124
  state,
175
- errors: result.errors
125
+ errors: result.errors || []
176
126
  };
177
127
  }
178
128
  /**
@@ -402,10 +352,10 @@ function getTestState(test) {
402
352
  return result ? result.state : "running";
403
353
  }
404
354
  function storeTask(project, runnerTask, reportedTask) {
405
- project.ctx.state.reportedTasksMap.set(runnerTask, reportedTask);
355
+ project.vitest.state.reportedTasksMap.set(runnerTask, reportedTask);
406
356
  }
407
357
  function getReportedTask(project, runnerTask) {
408
- const reportedTask = project.ctx.state.getReportedEntity(runnerTask);
358
+ const reportedTask = project.vitest.state.getReportedEntity(runnerTask);
409
359
  if (!reportedTask) {
410
360
  throw new Error(
411
361
  `Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`
@@ -521,7 +471,7 @@ const stringify = (value, replacer, space) => {
521
471
  }
522
472
  };
523
473
 
524
- const ESC$1 = '\u001B[';
474
+ const ESC$2 = '\u001B[';
525
475
  const OSC = '\u001B]';
526
476
  const BEL = '\u0007';
527
477
  const SEP = ';';
@@ -535,10 +485,10 @@ ansiEscapes.cursorTo = (x, y) => {
535
485
  }
536
486
 
537
487
  if (typeof y !== 'number') {
538
- return ESC$1 + (x + 1) + 'G';
488
+ return ESC$2 + (x + 1) + 'G';
539
489
  }
540
490
 
541
- return ESC$1 + (y + 1) + ';' + (x + 1) + 'H';
491
+ return ESC$2 + (y + 1) + ';' + (x + 1) + 'H';
542
492
  };
543
493
 
544
494
  ansiEscapes.cursorMove = (x, y) => {
@@ -549,33 +499,33 @@ ansiEscapes.cursorMove = (x, y) => {
549
499
  let returnValue = '';
550
500
 
551
501
  if (x < 0) {
552
- returnValue += ESC$1 + (-x) + 'D';
502
+ returnValue += ESC$2 + (-x) + 'D';
553
503
  } else if (x > 0) {
554
- returnValue += ESC$1 + x + 'C';
504
+ returnValue += ESC$2 + x + 'C';
555
505
  }
556
506
 
557
507
  if (y < 0) {
558
- returnValue += ESC$1 + (-y) + 'A';
508
+ returnValue += ESC$2 + (-y) + 'A';
559
509
  } else if (y > 0) {
560
- returnValue += ESC$1 + y + 'B';
510
+ returnValue += ESC$2 + y + 'B';
561
511
  }
562
512
 
563
513
  return returnValue;
564
514
  };
565
515
 
566
- ansiEscapes.cursorUp = (count = 1) => ESC$1 + count + 'A';
567
- ansiEscapes.cursorDown = (count = 1) => ESC$1 + count + 'B';
568
- ansiEscapes.cursorForward = (count = 1) => ESC$1 + count + 'C';
569
- ansiEscapes.cursorBackward = (count = 1) => ESC$1 + count + 'D';
516
+ ansiEscapes.cursorUp = (count = 1) => ESC$2 + count + 'A';
517
+ ansiEscapes.cursorDown = (count = 1) => ESC$2 + count + 'B';
518
+ ansiEscapes.cursorForward = (count = 1) => ESC$2 + count + 'C';
519
+ ansiEscapes.cursorBackward = (count = 1) => ESC$2 + count + 'D';
570
520
 
571
- ansiEscapes.cursorLeft = ESC$1 + 'G';
572
- ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC$1 + 's';
573
- ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC$1 + 'u';
574
- ansiEscapes.cursorGetPosition = ESC$1 + '6n';
575
- ansiEscapes.cursorNextLine = ESC$1 + 'E';
576
- ansiEscapes.cursorPrevLine = ESC$1 + 'F';
577
- ansiEscapes.cursorHide = ESC$1 + '?25l';
578
- ansiEscapes.cursorShow = ESC$1 + '?25h';
521
+ ansiEscapes.cursorLeft = ESC$2 + 'G';
522
+ ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC$2 + 's';
523
+ ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC$2 + 'u';
524
+ ansiEscapes.cursorGetPosition = ESC$2 + '6n';
525
+ ansiEscapes.cursorNextLine = ESC$2 + 'E';
526
+ ansiEscapes.cursorPrevLine = ESC$2 + 'F';
527
+ ansiEscapes.cursorHide = ESC$2 + '?25l';
528
+ ansiEscapes.cursorShow = ESC$2 + '?25h';
579
529
 
580
530
  ansiEscapes.eraseLines = count => {
581
531
  let clear = '';
@@ -591,24 +541,24 @@ ansiEscapes.eraseLines = count => {
591
541
  return clear;
592
542
  };
593
543
 
594
- ansiEscapes.eraseEndLine = ESC$1 + 'K';
595
- ansiEscapes.eraseStartLine = ESC$1 + '1K';
596
- ansiEscapes.eraseLine = ESC$1 + '2K';
597
- ansiEscapes.eraseDown = ESC$1 + 'J';
598
- ansiEscapes.eraseUp = ESC$1 + '1J';
599
- ansiEscapes.eraseScreen = ESC$1 + '2J';
600
- ansiEscapes.scrollUp = ESC$1 + 'S';
601
- ansiEscapes.scrollDown = ESC$1 + 'T';
544
+ ansiEscapes.eraseEndLine = ESC$2 + 'K';
545
+ ansiEscapes.eraseStartLine = ESC$2 + '1K';
546
+ ansiEscapes.eraseLine = ESC$2 + '2K';
547
+ ansiEscapes.eraseDown = ESC$2 + 'J';
548
+ ansiEscapes.eraseUp = ESC$2 + '1J';
549
+ ansiEscapes.eraseScreen = ESC$2 + '2J';
550
+ ansiEscapes.scrollUp = ESC$2 + 'S';
551
+ ansiEscapes.scrollDown = ESC$2 + 'T';
602
552
 
603
553
  ansiEscapes.clearScreen = '\u001Bc';
604
554
 
605
555
  ansiEscapes.clearTerminal = process.platform === 'win32' ?
606
- `${ansiEscapes.eraseScreen}${ESC$1}0f` :
556
+ `${ansiEscapes.eraseScreen}${ESC$2}0f` :
607
557
  // 1. Erases the screen (Only done in case `2` is not supported)
608
558
  // 2. Erases the whole screen including scrollback buffer
609
559
  // 3. Moves cursor to the top-left position
610
560
  // More info: https://www.real-world-systems.com/docs/ANSIcode.html
611
- `${ansiEscapes.eraseScreen}${ESC$1}3J${ESC$1}H`;
561
+ `${ansiEscapes.eraseScreen}${ESC$2}3J${ESC$2}H`;
612
562
 
613
563
  ansiEscapes.beep = BEL;
614
564
 
@@ -676,370 +626,6 @@ ansiEscapes.iTerm = {
676
626
  }
677
627
  };
678
628
 
679
- var onetime$1 = {exports: {}};
680
-
681
- var mimicFn = {exports: {}};
682
-
683
- var hasRequiredMimicFn;
684
-
685
- function requireMimicFn () {
686
- if (hasRequiredMimicFn) return mimicFn.exports;
687
- hasRequiredMimicFn = 1;
688
-
689
- const mimicFn$1 = (to, from) => {
690
- for (const prop of Reflect.ownKeys(from)) {
691
- Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop));
692
- }
693
-
694
- return to;
695
- };
696
-
697
- mimicFn.exports = mimicFn$1;
698
- // TODO: Remove this for the next major release
699
- mimicFn.exports.default = mimicFn$1;
700
- return mimicFn.exports;
701
- }
702
-
703
- var hasRequiredOnetime;
704
-
705
- function requireOnetime () {
706
- if (hasRequiredOnetime) return onetime$1.exports;
707
- hasRequiredOnetime = 1;
708
- const mimicFn = requireMimicFn();
709
-
710
- const calledFunctions = new WeakMap();
711
-
712
- const onetime = (function_, options = {}) => {
713
- if (typeof function_ !== 'function') {
714
- throw new TypeError('Expected a function');
715
- }
716
-
717
- let returnValue;
718
- let callCount = 0;
719
- const functionName = function_.displayName || function_.name || '<anonymous>';
720
-
721
- const onetime = function (...arguments_) {
722
- calledFunctions.set(onetime, ++callCount);
723
-
724
- if (callCount === 1) {
725
- returnValue = function_.apply(this, arguments_);
726
- function_ = null;
727
- } else if (options.throw === true) {
728
- throw new Error(`Function \`${functionName}\` can only be called once`);
729
- }
730
-
731
- return returnValue;
732
- };
733
-
734
- mimicFn(onetime, function_);
735
- calledFunctions.set(onetime, callCount);
736
-
737
- return onetime;
738
- };
739
-
740
- onetime$1.exports = onetime;
741
- // TODO: Remove this for the next major release
742
- onetime$1.exports.default = onetime;
743
-
744
- onetime$1.exports.callCount = function_ => {
745
- if (!calledFunctions.has(function_)) {
746
- throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`);
747
- }
748
-
749
- return calledFunctions.get(function_);
750
- };
751
- return onetime$1.exports;
752
- }
753
-
754
- var onetimeExports = requireOnetime();
755
- var onetime = /*@__PURE__*/getDefaultExportFromCjs(onetimeExports);
756
-
757
- var signalExit$1 = {exports: {}};
758
-
759
- var signals = {exports: {}};
760
-
761
- var hasRequiredSignals;
762
-
763
- function requireSignals () {
764
- if (hasRequiredSignals) return signals.exports;
765
- hasRequiredSignals = 1;
766
- (function (module) {
767
- // This is not the set of all possible signals.
768
- //
769
- // It IS, however, the set of all signals that trigger
770
- // an exit on either Linux or BSD systems. Linux is a
771
- // superset of the signal names supported on BSD, and
772
- // the unknown signals just fail to register, so we can
773
- // catch that easily enough.
774
- //
775
- // Don't bother with SIGKILL. It's uncatchable, which
776
- // means that we can't fire any callbacks anyway.
777
- //
778
- // If a user does happen to register a handler on a non-
779
- // fatal signal like SIGWINCH or something, and then
780
- // exit, it'll end up firing `process.emit('exit')`, so
781
- // the handler will be fired anyway.
782
- //
783
- // SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
784
- // artificially, inherently leave the process in a
785
- // state from which it is not safe to try and enter JS
786
- // listeners.
787
- module.exports = [
788
- 'SIGABRT',
789
- 'SIGALRM',
790
- 'SIGHUP',
791
- 'SIGINT',
792
- 'SIGTERM'
793
- ];
794
-
795
- if (process.platform !== 'win32') {
796
- module.exports.push(
797
- 'SIGVTALRM',
798
- 'SIGXCPU',
799
- 'SIGXFSZ',
800
- 'SIGUSR2',
801
- 'SIGTRAP',
802
- 'SIGSYS',
803
- 'SIGQUIT',
804
- 'SIGIOT'
805
- // should detect profiler and enable/disable accordingly.
806
- // see #21
807
- // 'SIGPROF'
808
- );
809
- }
810
-
811
- if (process.platform === 'linux') {
812
- module.exports.push(
813
- 'SIGIO',
814
- 'SIGPOLL',
815
- 'SIGPWR',
816
- 'SIGSTKFLT',
817
- 'SIGUNUSED'
818
- );
819
- }
820
- } (signals));
821
- return signals.exports;
822
- }
823
-
824
- var hasRequiredSignalExit;
825
-
826
- function requireSignalExit () {
827
- if (hasRequiredSignalExit) return signalExit$1.exports;
828
- hasRequiredSignalExit = 1;
829
- // Note: since nyc uses this module to output coverage, any lines
830
- // that are in the direct sync flow of nyc's outputCoverage are
831
- // ignored, since we can never get coverage for them.
832
- // grab a reference to node's real process object right away
833
- var process = commonjsGlobal.process;
834
-
835
- const processOk = function (process) {
836
- return process &&
837
- typeof process === 'object' &&
838
- typeof process.removeListener === 'function' &&
839
- typeof process.emit === 'function' &&
840
- typeof process.reallyExit === 'function' &&
841
- typeof process.listeners === 'function' &&
842
- typeof process.kill === 'function' &&
843
- typeof process.pid === 'number' &&
844
- typeof process.on === 'function'
845
- };
846
-
847
- // some kind of non-node environment, just no-op
848
- /* istanbul ignore if */
849
- if (!processOk(process)) {
850
- signalExit$1.exports = function () {
851
- return function () {}
852
- };
853
- } else {
854
- var assert = require$$0;
855
- var signals = requireSignals();
856
- var isWin = /^win/i.test(process.platform);
857
-
858
- var EE = require$$0$1;
859
- /* istanbul ignore if */
860
- if (typeof EE !== 'function') {
861
- EE = EE.EventEmitter;
862
- }
863
-
864
- var emitter;
865
- if (process.__signal_exit_emitter__) {
866
- emitter = process.__signal_exit_emitter__;
867
- } else {
868
- emitter = process.__signal_exit_emitter__ = new EE();
869
- emitter.count = 0;
870
- emitter.emitted = {};
871
- }
872
-
873
- // Because this emitter is a global, we have to check to see if a
874
- // previous version of this library failed to enable infinite listeners.
875
- // I know what you're about to say. But literally everything about
876
- // signal-exit is a compromise with evil. Get used to it.
877
- if (!emitter.infinite) {
878
- emitter.setMaxListeners(Infinity);
879
- emitter.infinite = true;
880
- }
881
-
882
- signalExit$1.exports = function (cb, opts) {
883
- /* istanbul ignore if */
884
- if (!processOk(commonjsGlobal.process)) {
885
- return function () {}
886
- }
887
- assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler');
888
-
889
- if (loaded === false) {
890
- load();
891
- }
892
-
893
- var ev = 'exit';
894
- if (opts && opts.alwaysLast) {
895
- ev = 'afterexit';
896
- }
897
-
898
- var remove = function () {
899
- emitter.removeListener(ev, cb);
900
- if (emitter.listeners('exit').length === 0 &&
901
- emitter.listeners('afterexit').length === 0) {
902
- unload();
903
- }
904
- };
905
- emitter.on(ev, cb);
906
-
907
- return remove
908
- };
909
-
910
- var unload = function unload () {
911
- if (!loaded || !processOk(commonjsGlobal.process)) {
912
- return
913
- }
914
- loaded = false;
915
-
916
- signals.forEach(function (sig) {
917
- try {
918
- process.removeListener(sig, sigListeners[sig]);
919
- } catch (er) {}
920
- });
921
- process.emit = originalProcessEmit;
922
- process.reallyExit = originalProcessReallyExit;
923
- emitter.count -= 1;
924
- };
925
- signalExit$1.exports.unload = unload;
926
-
927
- var emit = function emit (event, code, signal) {
928
- /* istanbul ignore if */
929
- if (emitter.emitted[event]) {
930
- return
931
- }
932
- emitter.emitted[event] = true;
933
- emitter.emit(event, code, signal);
934
- };
935
-
936
- // { <signal>: <listener fn>, ... }
937
- var sigListeners = {};
938
- signals.forEach(function (sig) {
939
- sigListeners[sig] = function listener () {
940
- /* istanbul ignore if */
941
- if (!processOk(commonjsGlobal.process)) {
942
- return
943
- }
944
- // If there are no other listeners, an exit is coming!
945
- // Simplest way: remove us and then re-send the signal.
946
- // We know that this will kill the process, so we can
947
- // safely emit now.
948
- var listeners = process.listeners(sig);
949
- if (listeners.length === emitter.count) {
950
- unload();
951
- emit('exit', null, sig);
952
- /* istanbul ignore next */
953
- emit('afterexit', null, sig);
954
- /* istanbul ignore next */
955
- if (isWin && sig === 'SIGHUP') {
956
- // "SIGHUP" throws an `ENOSYS` error on Windows,
957
- // so use a supported signal instead
958
- sig = 'SIGINT';
959
- }
960
- /* istanbul ignore next */
961
- process.kill(process.pid, sig);
962
- }
963
- };
964
- });
965
-
966
- signalExit$1.exports.signals = function () {
967
- return signals
968
- };
969
-
970
- var loaded = false;
971
-
972
- var load = function load () {
973
- if (loaded || !processOk(commonjsGlobal.process)) {
974
- return
975
- }
976
- loaded = true;
977
-
978
- // This is the number of onSignalExit's that are in play.
979
- // It's important so that we can count the correct number of
980
- // listeners on signals, and don't wait for the other one to
981
- // handle it instead of us.
982
- emitter.count += 1;
983
-
984
- signals = signals.filter(function (sig) {
985
- try {
986
- process.on(sig, sigListeners[sig]);
987
- return true
988
- } catch (er) {
989
- return false
990
- }
991
- });
992
-
993
- process.emit = processEmit;
994
- process.reallyExit = processReallyExit;
995
- };
996
- signalExit$1.exports.load = load;
997
-
998
- var originalProcessReallyExit = process.reallyExit;
999
- var processReallyExit = function processReallyExit (code) {
1000
- /* istanbul ignore if */
1001
- if (!processOk(commonjsGlobal.process)) {
1002
- return
1003
- }
1004
- process.exitCode = code || /* istanbul ignore next */ 0;
1005
- emit('exit', process.exitCode, null);
1006
- /* istanbul ignore next */
1007
- emit('afterexit', process.exitCode, null);
1008
- /* istanbul ignore next */
1009
- originalProcessReallyExit.call(process, process.exitCode);
1010
- };
1011
-
1012
- var originalProcessEmit = process.emit;
1013
- var processEmit = function processEmit (ev, arg) {
1014
- if (ev === 'exit' && processOk(commonjsGlobal.process)) {
1015
- /* istanbul ignore else */
1016
- if (arg !== undefined) {
1017
- process.exitCode = arg;
1018
- }
1019
- var ret = originalProcessEmit.apply(this, arguments);
1020
- /* istanbul ignore next */
1021
- emit('exit', process.exitCode, null);
1022
- /* istanbul ignore next */
1023
- emit('afterexit', process.exitCode, null);
1024
- /* istanbul ignore next */
1025
- return ret
1026
- } else {
1027
- return originalProcessEmit.apply(this, arguments)
1028
- }
1029
- };
1030
- }
1031
- return signalExit$1.exports;
1032
- }
1033
-
1034
- var signalExitExports = requireSignalExit();
1035
- var signalExit = /*@__PURE__*/getDefaultExportFromCjs(signalExitExports);
1036
-
1037
- const restoreCursor = onetime(() => {
1038
- signalExit(() => {
1039
- process$1.stderr.write('\u001B[?25h');
1040
- }, {alwaysLast: true});
1041
- });
1042
-
1043
629
  let isHidden = false;
1044
630
 
1045
631
  const cliCursor = {};
@@ -2403,8 +1989,10 @@ function isWide(x) {
2403
1989
  || x === 0x25FE
2404
1990
  || x === 0x2614
2405
1991
  || x === 0x2615
1992
+ || x >= 0x2630 && x <= 0x2637
2406
1993
  || x >= 0x2648 && x <= 0x2653
2407
1994
  || x === 0x267F
1995
+ || x >= 0x268A && x <= 0x268F
2408
1996
  || x === 0x2693
2409
1997
  || x === 0x26A1
2410
1998
  || x === 0x26AA
@@ -2445,11 +2033,10 @@ function isWide(x) {
2445
2033
  || x >= 0x3099 && x <= 0x30FF
2446
2034
  || x >= 0x3105 && x <= 0x312F
2447
2035
  || x >= 0x3131 && x <= 0x318E
2448
- || x >= 0x3190 && x <= 0x31E3
2036
+ || x >= 0x3190 && x <= 0x31E5
2449
2037
  || x >= 0x31EF && x <= 0x321E
2450
2038
  || x >= 0x3220 && x <= 0x3247
2451
- || x >= 0x3250 && x <= 0x4DBF
2452
- || x >= 0x4E00 && x <= 0xA48C
2039
+ || x >= 0x3250 && x <= 0xA48C
2453
2040
  || x >= 0xA490 && x <= 0xA4C6
2454
2041
  || x >= 0xA960 && x <= 0xA97C
2455
2042
  || x >= 0xAC00 && x <= 0xD7A3
@@ -2463,7 +2050,7 @@ function isWide(x) {
2463
2050
  || x === 0x16FF1
2464
2051
  || x >= 0x17000 && x <= 0x187F7
2465
2052
  || x >= 0x18800 && x <= 0x18CD5
2466
- || x >= 0x18D00 && x <= 0x18D08
2053
+ || x >= 0x18CFF && x <= 0x18D08
2467
2054
  || x >= 0x1AFF0 && x <= 0x1AFF3
2468
2055
  || x >= 0x1AFF5 && x <= 0x1AFFB
2469
2056
  || x === 0x1AFFD
@@ -2474,6 +2061,8 @@ function isWide(x) {
2474
2061
  || x === 0x1B155
2475
2062
  || x >= 0x1B164 && x <= 0x1B167
2476
2063
  || x >= 0x1B170 && x <= 0x1B2FB
2064
+ || x >= 0x1D300 && x <= 0x1D356
2065
+ || x >= 0x1D360 && x <= 0x1D376
2477
2066
  || x === 0x1F004
2478
2067
  || x === 0x1F0CF
2479
2068
  || x === 0x1F18E
@@ -2517,11 +2106,10 @@ function isWide(x) {
2517
2106
  || x >= 0x1F93C && x <= 0x1F945
2518
2107
  || x >= 0x1F947 && x <= 0x1F9FF
2519
2108
  || x >= 0x1FA70 && x <= 0x1FA7C
2520
- || x >= 0x1FA80 && x <= 0x1FA88
2521
- || x >= 0x1FA90 && x <= 0x1FABD
2522
- || x >= 0x1FABF && x <= 0x1FAC5
2523
- || x >= 0x1FACE && x <= 0x1FADB
2524
- || x >= 0x1FAE0 && x <= 0x1FAE8
2109
+ || x >= 0x1FA80 && x <= 0x1FA89
2110
+ || x >= 0x1FA8F && x <= 0x1FAC6
2111
+ || x >= 0x1FACE && x <= 0x1FADC
2112
+ || x >= 0x1FADF && x <= 0x1FAE9
2525
2113
  || x >= 0x1FAF0 && x <= 0x1FAF8
2526
2114
  || x >= 0x20000 && x <= 0x2FFFD
2527
2115
  || x >= 0x30000 && x <= 0x3FFFD;
@@ -3011,10 +2599,10 @@ function lineNo(no = "") {
3011
2599
  }
3012
2600
 
3013
2601
  const PAD = " ";
3014
- const ESC = "\x1B[";
3015
- const ERASE_DOWN = `${ESC}J`;
3016
- const ERASE_SCROLLBACK = `${ESC}3J`;
3017
- const CURSOR_TO_START = `${ESC}1;1H`;
2602
+ const ESC$1 = "\x1B[";
2603
+ const ERASE_DOWN = `${ESC$1}J`;
2604
+ const ERASE_SCROLLBACK = `${ESC$1}3J`;
2605
+ const CURSOR_TO_START = `${ESC$1}1;1H`;
3018
2606
  const CLEAR_SCREEN = "\x1Bc";
3019
2607
  class Logger {
3020
2608
  constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
@@ -3073,7 +2661,7 @@ class Logger {
3073
2661
  }
3074
2662
  printError(err, options = {}) {
3075
2663
  const { fullStack = false, type } = options;
3076
- const project = options.project ?? this.ctx.getCoreWorkspaceProject() ?? this.ctx.projects[0];
2664
+ const project = options.project ?? this.ctx.coreWorkspaceProject ?? this.ctx.projects[0];
3077
2665
  return printError(err, project, {
3078
2666
  type,
3079
2667
  showCodeFrame: options.showCodeFrame ?? true,
@@ -3122,8 +2710,7 @@ class Logger {
3122
2710
  }
3123
2711
  this.ctx.projects.forEach((project) => {
3124
2712
  const config2 = project.config;
3125
- const name = project.getName();
3126
- const output = project.isCore() || !name ? "" : `[${name}]`;
2713
+ const output = project.isRootProject() || !project.name ? "" : `[${project.name}]`;
3127
2714
  if (output) {
3128
2715
  this.console.error(c.bgCyan(`${output} Config`));
3129
2716
  }
@@ -3199,8 +2786,7 @@ Vitest is running in standalone mode. Edit a test file to rerun tests.`));
3199
2786
  if (!origin) {
3200
2787
  return;
3201
2788
  }
3202
- const name = project.getName();
3203
- const output = project.isCore() ? "" : formatProjectName(name);
2789
+ const output = project.isRootProject() ? "" : formatProjectName(project.name);
3204
2790
  const provider = project.browser.provider.name;
3205
2791
  const providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
3206
2792
  this.log(
@@ -3281,7 +2867,7 @@ class BlobReporter {
3281
2867
  (project) => {
3282
2868
  return [
3283
2869
  project.getName(),
3284
- [...project.server.moduleGraph.idToModuleMap.entries()].map((mod) => {
2870
+ [...project.vite.moduleGraph.idToModuleMap.entries()].map((mod) => {
3285
2871
  if (!mod[1].file) {
3286
2872
  return null;
3287
2873
  }
@@ -3357,10 +2943,10 @@ ${blobs.map((b) => `- "${b.file}" uses v${b.version}`).join("\n")}`
3357
2943
  return;
3358
2944
  }
3359
2945
  moduleIds.forEach(([moduleId, file, url]) => {
3360
- const moduleNode = project.server.moduleGraph.createFileOnlyEntry(file);
2946
+ const moduleNode = project.vite.moduleGraph.createFileOnlyEntry(file);
3361
2947
  moduleNode.url = url;
3362
2948
  moduleNode.id = moduleId;
3363
- project.server.moduleGraph.idToModuleMap.set(moduleId, moduleNode);
2949
+ project.vite.moduleGraph.idToModuleMap.set(moduleId, moduleNode);
3364
2950
  });
3365
2951
  });
3366
2952
  });
@@ -3387,7 +2973,6 @@ function hasFailedSnapshot(suite) {
3387
2973
  }
3388
2974
 
3389
2975
  const BADGE_PADDING = " ";
3390
- const LAST_RUN_LOG_TIMEOUT = 1500;
3391
2976
  class BaseReporter {
3392
2977
  start = 0;
3393
2978
  end = 0;
@@ -3395,19 +2980,17 @@ class BaseReporter {
3395
2980
  failedUnwatchedFiles = [];
3396
2981
  isTTY;
3397
2982
  ctx = void 0;
2983
+ renderSucceed = false;
3398
2984
  verbose = false;
3399
2985
  _filesInWatchMode = /* @__PURE__ */ new Map();
3400
2986
  _timeStart = formatTimeString(/* @__PURE__ */ new Date());
3401
- _lastRunTimeout = 0;
3402
- _lastRunTimer;
3403
- _lastRunCount = 0;
3404
2987
  constructor(options = {}) {
3405
2988
  this.isTTY = options.isTTY ?? ((isNode || isDeno) && process.stdout?.isTTY && !isCI);
3406
2989
  }
3407
2990
  onInit(ctx) {
3408
2991
  this.ctx = ctx;
3409
2992
  this.ctx.logger.printBanner();
3410
- this.start = performance.now();
2993
+ this.start = performance$1.now();
3411
2994
  }
3412
2995
  log(...messages) {
3413
2996
  this.ctx.logger.log(...messages);
@@ -3419,13 +3002,10 @@ class BaseReporter {
3419
3002
  return relative(this.ctx.config.root, path);
3420
3003
  }
3421
3004
  onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
3422
- this.end = performance.now();
3005
+ this.end = performance$1.now();
3423
3006
  this.reportSummary(files, errors);
3424
3007
  }
3425
3008
  onTaskUpdate(packs) {
3426
- if (this.isTTY) {
3427
- return;
3428
- }
3429
3009
  for (const pack of packs) {
3430
3010
  const task = this.ctx.state.idMap.get(pack[0]);
3431
3011
  if (task) {
@@ -3459,6 +3039,7 @@ class BaseReporter {
3459
3039
  title += ` ${formatProjectName(task.projectName, "")}`;
3460
3040
  }
3461
3041
  this.log(` ${title} ${task.name} ${suffix}`);
3042
+ const anyFailed = tests.some((test) => test.result?.state === "fail");
3462
3043
  for (const test of tests) {
3463
3044
  const duration = test.result?.duration;
3464
3045
  if (test.result?.state === "fail") {
@@ -3471,6 +3052,10 @@ class BaseReporter {
3471
3052
  this.log(
3472
3053
  ` ${c.yellow(c.dim(F_CHECK))} ${getTestName(test, c.dim(" > "))} ${c.yellow(Math.round(duration) + c.dim("ms"))}`
3473
3054
  );
3055
+ } else if (test.result?.state === "skip" && test.result.note) {
3056
+ this.log(` ${getStateSymbol(test)} ${getTestName(test)}${c.dim(c.gray(` [${test.result.note}]`))}`);
3057
+ } else if (this.renderSucceed || anyFailed) {
3058
+ this.log(` ${c.green(c.dim(F_CHECK))} ${getTestName(test, c.dim(" > "))}`);
3474
3059
  }
3475
3060
  }
3476
3061
  }
@@ -3482,7 +3067,6 @@ class BaseReporter {
3482
3067
  return color(` ${Math.round(task.result.duration)}${c.dim("ms")}`);
3483
3068
  }
3484
3069
  onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
3485
- this.resetLastRunLog();
3486
3070
  const failed = errors.length > 0 || hasFailed(files);
3487
3071
  if (failed) {
3488
3072
  this.log(withLabel("red", "FAIL", "Tests failed. Watching for file changes..."));
@@ -3498,34 +3082,8 @@ class BaseReporter {
3498
3082
  hints.push(c.dim("press ") + c.bold("q") + c.dim(" to quit"));
3499
3083
  }
3500
3084
  this.log(BADGE_PADDING + hints.join(c.dim(", ")));
3501
- if (this._lastRunCount) {
3502
- const LAST_RUN_TEXT = `rerun x${this._lastRunCount}`;
3503
- const LAST_RUN_TEXTS = [
3504
- c.blue(LAST_RUN_TEXT),
3505
- c.gray(LAST_RUN_TEXT),
3506
- c.dim(c.gray(LAST_RUN_TEXT))
3507
- ];
3508
- this.ctx.logger.logUpdate(BADGE_PADDING + LAST_RUN_TEXTS[0]);
3509
- this._lastRunTimeout = 0;
3510
- this._lastRunTimer = setInterval(() => {
3511
- this._lastRunTimeout += 1;
3512
- if (this._lastRunTimeout >= LAST_RUN_TEXTS.length) {
3513
- this.resetLastRunLog();
3514
- } else {
3515
- this.ctx.logger.logUpdate(
3516
- BADGE_PADDING + LAST_RUN_TEXTS[this._lastRunTimeout]
3517
- );
3518
- }
3519
- }, LAST_RUN_LOG_TIMEOUT / LAST_RUN_TEXTS.length);
3520
- }
3521
- }
3522
- resetLastRunLog() {
3523
- clearInterval(this._lastRunTimer);
3524
- this._lastRunTimer = void 0;
3525
- this.ctx.logger.logUpdate.clear();
3526
3085
  }
3527
3086
  onWatcherRerun(files, trigger) {
3528
- this.resetLastRunLog();
3529
3087
  this.watchFilters = files;
3530
3088
  this.failedUnwatchedFiles = this.ctx.state.getFiles().filter(
3531
3089
  (file) => !files.includes(file.filepath) && hasFailed(file)
@@ -3535,9 +3093,7 @@ class BaseReporter {
3535
3093
  this._filesInWatchMode.set(filepath, ++reruns);
3536
3094
  });
3537
3095
  let banner = trigger ? c.dim(`${this.relative(trigger)} `) : "";
3538
- if (files.length > 1 || !files.length) {
3539
- this._lastRunCount = 0;
3540
- } else if (files.length === 1) {
3096
+ if (files.length === 1) {
3541
3097
  const rerun = this._filesInWatchMode.get(files[0]) ?? 1;
3542
3098
  banner += c.blue(`x${rerun} `);
3543
3099
  }
@@ -3553,13 +3109,11 @@ class BaseReporter {
3553
3109
  this.log(BADGE_PADDING + c.dim(" Test name pattern: ") + c.blue(String(this.ctx.configOverride.testNamePattern)));
3554
3110
  }
3555
3111
  this.log("");
3556
- if (!this.isTTY) {
3557
- for (const task of this.failedUnwatchedFiles) {
3558
- this.printTask(task);
3559
- }
3112
+ for (const task of this.failedUnwatchedFiles) {
3113
+ this.printTask(task);
3560
3114
  }
3561
3115
  this._timeStart = formatTimeString(/* @__PURE__ */ new Date());
3562
- this.start = performance.now();
3116
+ this.start = performance$1.now();
3563
3117
  }
3564
3118
  onUserConsoleLog(log) {
3565
3119
  if (!this.shouldLog(log)) {
@@ -3580,7 +3134,7 @@ class BaseReporter {
3580
3134
  if (log.browser) {
3581
3135
  write("\n");
3582
3136
  }
3583
- const project = log.taskId ? this.ctx.getProjectByTaskId(log.taskId) : this.ctx.getCoreWorkspaceProject();
3137
+ const project = log.taskId ? this.ctx.getProjectByTaskId(log.taskId) : this.ctx.getRootTestProject();
3584
3138
  const stack = log.browser ? project.browser?.parseStacktrace(log.origin) || [] : parseStacktrace(log.origin);
3585
3139
  const highlight = task && stack.find((i) => i.file === task.file.filepath);
3586
3140
  for (const frame of stack) {
@@ -3624,6 +3178,7 @@ class BaseReporter {
3624
3178
  }
3625
3179
  }
3626
3180
  reportTestSummary(files, errors) {
3181
+ this.log();
3627
3182
  const affectedFiles = [
3628
3183
  ...this.failedUnwatchedFiles,
3629
3184
  ...files
@@ -3635,32 +3190,32 @@ class BaseReporter {
3635
3190
  );
3636
3191
  for (const [index, snapshot] of snapshotOutput.entries()) {
3637
3192
  const title = index === 0 ? "Snapshots" : "";
3638
- this.log(`${padTitle(title)} ${snapshot}`);
3193
+ this.log(`${padSummaryTitle(title)} ${snapshot}`);
3639
3194
  }
3640
3195
  if (snapshotOutput.length > 1) {
3641
3196
  this.log();
3642
3197
  }
3643
- this.log(padTitle("Test Files"), getStateString(affectedFiles));
3644
- this.log(padTitle("Tests"), getStateString(tests));
3198
+ this.log(padSummaryTitle("Test Files"), getStateString$1(affectedFiles));
3199
+ this.log(padSummaryTitle("Tests"), getStateString$1(tests));
3645
3200
  if (this.ctx.projects.some((c2) => c2.config.typecheck.enabled)) {
3646
3201
  const failed = tests.filter((t) => t.meta?.typecheck && t.result?.errors?.length);
3647
3202
  this.log(
3648
- padTitle("Type Errors"),
3203
+ padSummaryTitle("Type Errors"),
3649
3204
  failed.length ? c.bold(c.red(`${failed.length} failed`)) : c.dim("no errors")
3650
3205
  );
3651
3206
  }
3652
3207
  if (errors.length) {
3653
3208
  this.log(
3654
- padTitle("Errors"),
3209
+ padSummaryTitle("Errors"),
3655
3210
  c.bold(c.red(`${errors.length} error${errors.length > 1 ? "s" : ""}`))
3656
3211
  );
3657
3212
  }
3658
- this.log(padTitle("Start at"), this._timeStart);
3213
+ this.log(padSummaryTitle("Start at"), this._timeStart);
3659
3214
  const collectTime = sum(files, (file) => file.collectDuration);
3660
3215
  const testsTime = sum(files, (file) => file.result?.duration);
3661
3216
  const setupTime = sum(files, (file) => file.setupDuration);
3662
3217
  if (this.watchFilters) {
3663
- this.log(padTitle("Duration"), time(collectTime + testsTime + setupTime));
3218
+ this.log(padSummaryTitle("Duration"), formatTime(collectTime + testsTime + setupTime));
3664
3219
  } else {
3665
3220
  const executionTime = this.end - this.start;
3666
3221
  const environmentTime = sum(files, (file) => file.environmentLoad);
@@ -3668,15 +3223,15 @@ class BaseReporter {
3668
3223
  const transformTime = sum(this.ctx.projects, (project) => project.vitenode.getTotalDuration());
3669
3224
  const typecheck = sum(this.ctx.projects, (project) => project.typechecker?.getResult().time);
3670
3225
  const timers = [
3671
- `transform ${time(transformTime)}`,
3672
- `setup ${time(setupTime)}`,
3673
- `collect ${time(collectTime)}`,
3674
- `tests ${time(testsTime)}`,
3675
- `environment ${time(environmentTime)}`,
3676
- `prepare ${time(prepareTime)}`,
3677
- typecheck && `typecheck ${time(typecheck)}`
3226
+ `transform ${formatTime(transformTime)}`,
3227
+ `setup ${formatTime(setupTime)}`,
3228
+ `collect ${formatTime(collectTime)}`,
3229
+ `tests ${formatTime(testsTime)}`,
3230
+ `environment ${formatTime(environmentTime)}`,
3231
+ `prepare ${formatTime(prepareTime)}`,
3232
+ typecheck && `typecheck ${formatTime(typecheck)}`
3678
3233
  ].filter(Boolean).join(", ");
3679
- this.log(padTitle("Duration"), time(executionTime) + c.dim(` (${timers})`));
3234
+ this.log(padSummaryTitle("Duration"), formatTime(executionTime) + c.dim(` (${timers})`));
3680
3235
  }
3681
3236
  this.log();
3682
3237
  }
@@ -3771,15 +3326,6 @@ class BaseReporter {
3771
3326
  function errorBanner(message) {
3772
3327
  return c.red(divider(c.bold(c.inverse(` ${message} `))));
3773
3328
  }
3774
- function padTitle(str) {
3775
- return c.dim(`${str.padStart(11)} `);
3776
- }
3777
- function time(time2) {
3778
- if (time2 > 1e3) {
3779
- return `${(time2 / 1e3).toFixed(2)}s`;
3780
- }
3781
- return `${Math.round(time2)}ms`;
3782
- }
3783
3329
  function sum(items, cb) {
3784
3330
  return items.reduce((total, next) => {
3785
3331
  return total + Math.max(cb(next) || 0, 0);
@@ -3791,288 +3337,521 @@ class BasicReporter extends BaseReporter {
3791
3337
  super();
3792
3338
  this.isTTY = false;
3793
3339
  }
3340
+ onInit(ctx) {
3341
+ super.onInit(ctx);
3342
+ ctx.logger.log(c.inverse(c.bold(c.yellow(" DEPRECATED "))), c.yellow(
3343
+ `'basic' reporter is deprecated and will be removed in Vitest v3.
3344
+ Remove 'basic' from 'reporters' option. To match 'basic' reporter 100%, use configuration:
3345
+ ${JSON.stringify({ test: { reporters: [["default", { summary: false }]] } }, null, 2)}`
3346
+ ));
3347
+ }
3794
3348
  reportSummary(files, errors) {
3795
3349
  this.ctx.logger.log();
3796
3350
  return super.reportSummary(files, errors);
3797
3351
  }
3798
3352
  }
3799
3353
 
3800
- const outputMap$1 = /* @__PURE__ */ new WeakMap();
3801
- function formatFilepath$1(path) {
3802
- const lastSlash = Math.max(path.lastIndexOf("/") + 1, 0);
3803
- const basename = path.slice(lastSlash);
3804
- let firstDot = basename.indexOf(".");
3805
- if (firstDot < 0) {
3806
- firstDot = basename.length;
3354
+ const DEFAULT_RENDER_INTERVAL = 16;
3355
+ const ESC = "\x1B[";
3356
+ const CLEAR_LINE = `${ESC}K`;
3357
+ const MOVE_CURSOR_ONE_ROW_UP = `${ESC}1A`;
3358
+ const HIDE_CURSOR = `${ESC}?25l`;
3359
+ const SHOW_CURSOR = `${ESC}?25h`;
3360
+ const SYNC_START = `${ESC}?2026h`;
3361
+ const SYNC_END = `${ESC}?2026l`;
3362
+ class WindowRenderer {
3363
+ options;
3364
+ streams;
3365
+ buffer = [];
3366
+ renderInterval = void 0;
3367
+ windowHeight = 0;
3368
+ finished = false;
3369
+ cleanups = [];
3370
+ constructor(options) {
3371
+ this.options = {
3372
+ interval: DEFAULT_RENDER_INTERVAL,
3373
+ ...options
3374
+ };
3375
+ this.streams = {
3376
+ output: options.logger.outputStream.write.bind(options.logger.outputStream),
3377
+ error: options.logger.errorStream.write.bind(options.logger.errorStream)
3378
+ };
3379
+ this.cleanups.push(
3380
+ this.interceptStream(process.stdout, "output"),
3381
+ this.interceptStream(process.stderr, "error")
3382
+ );
3383
+ restoreCursor();
3384
+ this.write(HIDE_CURSOR, "output");
3385
+ this.start();
3807
3386
  }
3808
- firstDot += lastSlash;
3809
- return c.dim(path.slice(0, lastSlash)) + path.slice(lastSlash, firstDot) + c.dim(path.slice(firstDot));
3810
- }
3811
- function formatNumber$1(number) {
3812
- const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
3813
- return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
3814
- }
3815
- function renderHookState(task, hookName, level = 0) {
3816
- const state = task.result?.hooks?.[hookName];
3817
- if (state && state === "run") {
3818
- return `${" ".repeat(level)} ${getHookStateSymbol(task, hookName)} ${c.dim(
3819
- `[ ${hookName} ]`
3820
- )}`;
3821
- }
3822
- return "";
3823
- }
3824
- function renderBenchmarkItems$1(result) {
3825
- return [
3826
- result.name,
3827
- formatNumber$1(result.hz || 0),
3828
- formatNumber$1(result.p99 || 0),
3829
- `\xB1${result.rme.toFixed(2)}%`,
3830
- result.samples.length.toString()
3831
- ];
3832
- }
3833
- function renderBenchmark$1(task, tasks) {
3834
- const result = task.result?.benchmark;
3835
- if (!result) {
3836
- return task.name;
3837
- }
3838
- const benches = tasks.map((i) => i.meta?.benchmark ? i.result?.benchmark : void 0).filter(notNullish);
3839
- const allItems = benches.map(renderBenchmarkItems$1);
3840
- const items = renderBenchmarkItems$1(result);
3841
- const padded = items.map((i, idx) => {
3842
- const width = Math.max(...allItems.map((i2) => i2[idx].length));
3843
- return idx ? i.padStart(width, " ") : i.padEnd(width, " ");
3844
- });
3845
- return [
3846
- padded[0],
3847
- // name
3848
- c.dim(" "),
3849
- c.blue(padded[1]),
3850
- c.dim(" ops/sec "),
3851
- c.cyan(padded[3]),
3852
- c.dim(` (${padded[4]} samples)`),
3853
- result.rank === 1 ? c.bold(c.green(" fastest")) : result.rank === benches.length && benches.length > 2 ? c.bold(c.gray(" slowest")) : ""
3854
- ].join("");
3855
- }
3856
- function renderTree$1(tasks, options, level = 0, maxRows) {
3857
- const output = [];
3858
- let currentRowCount = 0;
3859
- for (const task of [...tasks].reverse()) {
3860
- const taskOutput = [];
3861
- let suffix = "";
3862
- let prefix = ` ${getStateSymbol(task)} `;
3863
- if (level === 0 && task.type === "suite" && "projectName" in task) {
3864
- prefix += formatProjectName(task.projectName);
3865
- }
3866
- if (level === 0 && task.type === "suite" && task.meta.typecheck) {
3867
- prefix += c.bgBlue(c.bold(" TS "));
3868
- prefix += " ";
3387
+ start() {
3388
+ this.finished = false;
3389
+ this.renderInterval = setInterval(() => this.flushBuffer(), this.options.interval);
3390
+ }
3391
+ stop() {
3392
+ this.write(SHOW_CURSOR, "output");
3393
+ this.cleanups.splice(0).map((fn) => fn());
3394
+ clearInterval(this.renderInterval);
3395
+ }
3396
+ /**
3397
+ * Write all buffered output and stop buffering.
3398
+ * All intercepted writes are forwarded to actual write after this.
3399
+ */
3400
+ finish() {
3401
+ this.finished = true;
3402
+ this.flushBuffer();
3403
+ clearInterval(this.renderInterval);
3404
+ }
3405
+ flushBuffer() {
3406
+ if (this.buffer.length === 0) {
3407
+ return this.render();
3408
+ }
3409
+ let current;
3410
+ for (const next of this.buffer.splice(0)) {
3411
+ if (!current) {
3412
+ current = next;
3413
+ continue;
3414
+ }
3415
+ if (current.type !== next.type) {
3416
+ this.render(current.message, current.type);
3417
+ current = next;
3418
+ continue;
3419
+ }
3420
+ current.message += next.message;
3869
3421
  }
3870
- if (task.type === "test" && task.result?.retryCount && task.result.retryCount > 0) {
3871
- suffix += c.yellow(` (retry x${task.result.retryCount})`);
3422
+ if (current) {
3423
+ this.render(current?.message, current?.type);
3872
3424
  }
3873
- if (task.type === "suite") {
3874
- const tests = getTests(task);
3875
- suffix += c.dim(` (${tests.length})`);
3425
+ }
3426
+ render(message, type = "output") {
3427
+ if (this.finished) {
3428
+ this.clearWindow();
3429
+ return this.write(message || "", type);
3876
3430
  }
3877
- if (task.mode === "skip" || task.mode === "todo") {
3878
- suffix += ` ${c.dim(c.gray("[skipped]"))}`;
3431
+ const windowContent = this.options.getWindow();
3432
+ const rowCount = getRenderedRowCount(windowContent, this.options.logger.outputStream);
3433
+ let padding = this.windowHeight - rowCount;
3434
+ if (padding > 0 && message) {
3435
+ padding -= getRenderedRowCount([message], this.options.logger.outputStream);
3879
3436
  }
3880
- if (task.type === "test" && task.result?.repeatCount && task.result.repeatCount > 0) {
3881
- suffix += c.yellow(` (repeat x${task.result.repeatCount})`);
3437
+ this.write(SYNC_START);
3438
+ this.clearWindow();
3439
+ if (message) {
3440
+ this.write(message, type);
3882
3441
  }
3883
- if (task.result?.duration != null) {
3884
- if (task.result.duration > options.slowTestThreshold) {
3885
- suffix += c.yellow(
3886
- ` ${Math.round(task.result.duration)}${c.dim("ms")}`
3887
- );
3888
- }
3442
+ if (padding > 0) {
3443
+ this.write("\n".repeat(padding));
3889
3444
  }
3890
- if (options.showHeap && task.result?.heap != null) {
3891
- suffix += c.magenta(
3892
- ` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`
3893
- );
3445
+ this.write(windowContent.join("\n"));
3446
+ this.write(SYNC_END);
3447
+ this.windowHeight = rowCount + Math.max(0, padding);
3448
+ }
3449
+ clearWindow() {
3450
+ if (this.windowHeight === 0) {
3451
+ return;
3894
3452
  }
3895
- let name = task.name;
3896
- if (level === 0) {
3897
- name = formatFilepath$1(name);
3453
+ this.write(CLEAR_LINE);
3454
+ for (let i = 1; i < this.windowHeight; i++) {
3455
+ this.write(`${MOVE_CURSOR_ONE_ROW_UP}${CLEAR_LINE}`);
3898
3456
  }
3899
- const padding = " ".repeat(level);
3900
- const body = task.meta?.benchmark ? renderBenchmark$1(task, tasks) : name;
3901
- taskOutput.push(padding + prefix + body + suffix);
3902
- if (task.result?.state !== "pass" && outputMap$1.get(task) != null) {
3903
- let data = outputMap$1.get(task);
3904
- if (typeof data === "string") {
3905
- data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
3906
- if (data === "") {
3907
- data = void 0;
3457
+ this.windowHeight = 0;
3458
+ }
3459
+ interceptStream(stream, type) {
3460
+ const original = stream.write;
3461
+ stream.write = (chunk, _, callback) => {
3462
+ if (chunk) {
3463
+ if (this.finished) {
3464
+ this.write(chunk.toString(), type);
3465
+ } else {
3466
+ this.buffer.push({ type, message: chunk.toString() });
3908
3467
  }
3909
3468
  }
3910
- if (data != null) {
3911
- const out = `${" ".repeat(level)}${F_RIGHT} ${data}`;
3912
- taskOutput.push(` ${c.gray(cliTruncate(out, getCols(-3)))}`);
3913
- }
3914
- }
3915
- taskOutput.push(renderHookState(task, "beforeAll", level + 1));
3916
- taskOutput.push(renderHookState(task, "beforeEach", level + 1));
3917
- if (task.type === "suite" && task.tasks.length > 0) {
3918
- if (task.result?.state === "fail" || task.result?.state === "run" || options.renderSucceed) {
3919
- if (options.logger.ctx.config.hideSkippedTests) {
3920
- const filteredTasks = task.tasks.filter(
3921
- (t) => t.mode !== "skip" && t.mode !== "todo"
3922
- );
3923
- taskOutput.push(
3924
- renderTree$1(filteredTasks, options, level + 1, maxRows)
3925
- );
3469
+ callback?.();
3470
+ };
3471
+ return function restore() {
3472
+ stream.write = original;
3473
+ };
3474
+ }
3475
+ write(message, type = "output") {
3476
+ this.streams[type](message);
3477
+ }
3478
+ }
3479
+ function getRenderedRowCount(rows, stream) {
3480
+ let count = 0;
3481
+ const columns = "columns" in stream ? stream.columns : 80;
3482
+ for (const row of rows) {
3483
+ const text = stripVTControlCharacters(row);
3484
+ count += Math.max(1, Math.ceil(text.length / columns));
3485
+ }
3486
+ return count;
3487
+ }
3488
+
3489
+ class TaskParser {
3490
+ ctx;
3491
+ onInit(ctx) {
3492
+ this.ctx = ctx;
3493
+ }
3494
+ onHookStart(_options) {
3495
+ }
3496
+ onHookEnd(_options) {
3497
+ }
3498
+ onTestStart(_test) {
3499
+ }
3500
+ onTestFinished(_test) {
3501
+ }
3502
+ onTestFilePrepare(_file) {
3503
+ }
3504
+ onTestFileFinished(_file) {
3505
+ }
3506
+ onTaskUpdate(packs) {
3507
+ const startingTestFiles = [];
3508
+ const finishedTestFiles = [];
3509
+ const startingTests = [];
3510
+ const finishedTests = [];
3511
+ const startingHooks = [];
3512
+ const endingHooks = [];
3513
+ for (const pack of packs) {
3514
+ const task = this.ctx.state.idMap.get(pack[0]);
3515
+ if (task?.type === "suite" && "filepath" in task && task.result?.state) {
3516
+ if (task?.result?.state === "run") {
3517
+ startingTestFiles.push(task);
3926
3518
  } else {
3927
- taskOutput.push(renderTree$1(task.tasks, options, level + 1, maxRows));
3519
+ for (const test of getTests(task)) {
3520
+ if (!test.result || test.result?.state === "skip") {
3521
+ finishedTests.push(test);
3522
+ }
3523
+ }
3524
+ finishedTestFiles.push(task.file);
3525
+ }
3526
+ }
3527
+ if (task?.type === "test" || task?.type === "custom") {
3528
+ if (task.result?.state === "run") {
3529
+ startingTests.push(task);
3530
+ } else if (task.result?.hooks?.afterEach !== "run") {
3531
+ finishedTests.push(task);
3532
+ }
3533
+ }
3534
+ if (task?.result?.hooks) {
3535
+ for (const [hook, state] of Object.entries(task.result.hooks)) {
3536
+ if (state === "run") {
3537
+ startingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type });
3538
+ } else {
3539
+ endingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type });
3540
+ }
3928
3541
  }
3929
3542
  }
3930
3543
  }
3931
- taskOutput.push(renderHookState(task, "afterAll", level + 1));
3932
- taskOutput.push(renderHookState(task, "afterEach", level + 1));
3933
- const rows = taskOutput.filter(Boolean);
3934
- output.push(rows.join("\n"));
3935
- currentRowCount += rows.length;
3936
- if (maxRows && currentRowCount >= maxRows) {
3937
- break;
3938
- }
3544
+ endingHooks.forEach((hook) => this.onHookEnd(hook));
3545
+ finishedTests.forEach((test) => this.onTestFinished(test));
3546
+ finishedTestFiles.forEach((file) => this.onTestFileFinished(file));
3547
+ startingTestFiles.forEach((file) => this.onTestFilePrepare(file));
3548
+ startingTests.forEach((test) => this.onTestStart(test));
3549
+ startingHooks.forEach(
3550
+ (hook) => this.onHookStart(hook)
3551
+ );
3939
3552
  }
3940
- return output.reverse().join("\n");
3941
3553
  }
3942
- function createListRenderer(_tasks, options) {
3943
- let tasks = _tasks;
3944
- let timer;
3945
- const log = options.logger.logUpdate;
3946
- function update() {
3947
- if (options.logger.ctx.config.hideSkippedTests) {
3948
- const filteredTasks = tasks.filter(
3949
- (t) => t.mode !== "skip" && t.mode !== "todo"
3950
- );
3951
- log(
3952
- renderTree$1(
3953
- filteredTasks,
3954
- options,
3955
- 0,
3956
- // log-update already limits the amount of printed rows to fit the current terminal
3957
- // but we can optimize performance by doing it ourselves
3958
- process.stdout.rows
3959
- )
3960
- );
3961
- } else {
3962
- log(
3963
- renderTree$1(
3964
- tasks,
3965
- options,
3966
- 0,
3967
- // log-update already limits the amount of printed rows to fit the current terminal
3968
- // but we can optimize performance by doing it ourselves
3969
- process.stdout.rows
3970
- )
3971
- );
3554
+
3555
+ const DURATION_UPDATE_INTERVAL_MS = 100;
3556
+ const FINISHED_TEST_CLEANUP_TIME_MS = 1e3;
3557
+ class SummaryReporter extends TaskParser {
3558
+ options;
3559
+ renderer;
3560
+ suites = emptyCounters();
3561
+ tests = emptyCounters();
3562
+ maxParallelTests = 0;
3563
+ /** Currently running tests, may include finished tests too */
3564
+ runningTests = /* @__PURE__ */ new Map();
3565
+ /** ID of finished `this.runningTests` that are currently being shown */
3566
+ finishedTests = /* @__PURE__ */ new Map();
3567
+ /** IDs of all finished tests */
3568
+ allFinishedTests = /* @__PURE__ */ new Set();
3569
+ startTime = "";
3570
+ currentTime = 0;
3571
+ duration = 0;
3572
+ durationInterval = void 0;
3573
+ onInit(ctx, options = {}) {
3574
+ this.ctx = ctx;
3575
+ this.options = {
3576
+ verbose: false,
3577
+ ...options
3578
+ };
3579
+ this.renderer = new WindowRenderer({
3580
+ logger: ctx.logger,
3581
+ getWindow: () => this.createSummary()
3582
+ });
3583
+ this.startTimers();
3584
+ this.ctx.onClose(() => {
3585
+ clearInterval(this.durationInterval);
3586
+ this.renderer.stop();
3587
+ });
3588
+ }
3589
+ onPathsCollected(paths) {
3590
+ this.suites.total = (paths || []).length;
3591
+ }
3592
+ onWatcherRerun() {
3593
+ this.runningTests.clear();
3594
+ this.finishedTests.clear();
3595
+ this.allFinishedTests.clear();
3596
+ this.suites = emptyCounters();
3597
+ this.tests = emptyCounters();
3598
+ this.startTimers();
3599
+ this.renderer.start();
3600
+ }
3601
+ onFinished() {
3602
+ this.runningTests.clear();
3603
+ this.finishedTests.clear();
3604
+ this.allFinishedTests.clear();
3605
+ this.renderer.finish();
3606
+ clearInterval(this.durationInterval);
3607
+ }
3608
+ onTestFilePrepare(file) {
3609
+ if (this.allFinishedTests.has(file.id) || this.runningTests.has(file.id)) {
3610
+ return;
3972
3611
  }
3612
+ const total = getTests(file).length;
3613
+ this.tests.total += total;
3614
+ if (this.finishedTests.size) {
3615
+ const finished = this.finishedTests.keys().next().value;
3616
+ this.removeTestFile(finished);
3617
+ }
3618
+ this.runningTests.set(file.id, {
3619
+ total,
3620
+ completed: 0,
3621
+ filename: file.name,
3622
+ projectName: file.projectName,
3623
+ tests: /* @__PURE__ */ new Map()
3624
+ });
3625
+ this.maxParallelTests = Math.max(this.maxParallelTests, this.runningTests.size);
3973
3626
  }
3974
- return {
3975
- start() {
3976
- if (timer) {
3977
- return this;
3627
+ onHookStart(options) {
3628
+ const stats = this.getHookStats(options);
3629
+ if (!stats) {
3630
+ return;
3631
+ }
3632
+ const hook = {
3633
+ name: options.name,
3634
+ visible: false,
3635
+ startTime: performance.now(),
3636
+ onFinish: () => {
3978
3637
  }
3979
- timer = setInterval(update, 16);
3980
- return this;
3981
- },
3982
- update(_tasks2) {
3983
- tasks = _tasks2;
3984
- return this;
3985
- },
3986
- stop() {
3987
- if (timer) {
3988
- clearInterval(timer);
3989
- timer = void 0;
3638
+ };
3639
+ stats.hook?.onFinish?.();
3640
+ stats.hook = hook;
3641
+ const timeout = setTimeout(() => {
3642
+ hook.visible = true;
3643
+ }, this.ctx.config.slowTestThreshold).unref();
3644
+ hook.onFinish = () => clearTimeout(timeout);
3645
+ }
3646
+ onHookEnd(options) {
3647
+ const stats = this.getHookStats(options);
3648
+ if (stats?.hook?.name !== options.name) {
3649
+ return;
3650
+ }
3651
+ stats.hook.onFinish();
3652
+ stats.hook.visible = false;
3653
+ }
3654
+ onTestStart(test) {
3655
+ if (!this.options.verbose) {
3656
+ return;
3657
+ }
3658
+ const stats = this.getTestStats(test);
3659
+ if (!stats || stats.tests.has(test.id)) {
3660
+ return;
3661
+ }
3662
+ const slowTest = {
3663
+ name: test.name,
3664
+ visible: false,
3665
+ startTime: performance.now(),
3666
+ onFinish: () => {
3990
3667
  }
3991
- log.clear();
3992
- if (options.logger.ctx.config.hideSkippedTests) {
3993
- const filteredTasks = tasks.filter(
3994
- (t) => t.mode !== "skip" && t.mode !== "todo"
3668
+ };
3669
+ const timeout = setTimeout(() => {
3670
+ slowTest.visible = true;
3671
+ }, this.ctx.config.slowTestThreshold).unref();
3672
+ slowTest.onFinish = () => {
3673
+ slowTest.hook?.onFinish();
3674
+ clearTimeout(timeout);
3675
+ };
3676
+ stats.tests.set(test.id, slowTest);
3677
+ }
3678
+ onTestFinished(test) {
3679
+ const stats = this.getTestStats(test);
3680
+ if (!stats) {
3681
+ return;
3682
+ }
3683
+ stats.tests.get(test.id)?.onFinish();
3684
+ stats.tests.delete(test.id);
3685
+ stats.completed++;
3686
+ const result = test.result;
3687
+ if (result?.state === "pass") {
3688
+ this.tests.passed++;
3689
+ } else if (result?.state === "fail") {
3690
+ this.tests.failed++;
3691
+ } else if (!result?.state || result?.state === "skip" || result?.state === "todo") {
3692
+ this.tests.skipped++;
3693
+ }
3694
+ }
3695
+ onTestFileFinished(file) {
3696
+ if (this.allFinishedTests.has(file.id)) {
3697
+ return;
3698
+ }
3699
+ this.allFinishedTests.add(file.id);
3700
+ this.suites.completed++;
3701
+ if (file.result?.state === "pass") {
3702
+ this.suites.passed++;
3703
+ } else if (file.result?.state === "fail") {
3704
+ this.suites.failed++;
3705
+ } else if (file.result?.state === "skip") {
3706
+ this.suites.skipped++;
3707
+ } else if (file.result?.state === "todo") {
3708
+ this.suites.todo++;
3709
+ }
3710
+ const left = this.suites.total - this.suites.completed;
3711
+ if (left > this.maxParallelTests) {
3712
+ this.finishedTests.set(file.id, setTimeout(() => {
3713
+ this.removeTestFile(file.id);
3714
+ }, FINISHED_TEST_CLEANUP_TIME_MS).unref());
3715
+ } else {
3716
+ this.removeTestFile(file.id);
3717
+ }
3718
+ }
3719
+ getTestStats(test) {
3720
+ const file = test.file;
3721
+ let stats = this.runningTests.get(file.id);
3722
+ if (!stats) {
3723
+ this.onTestFilePrepare(test.file);
3724
+ stats = this.runningTests.get(file.id);
3725
+ if (!stats) {
3726
+ return;
3727
+ }
3728
+ }
3729
+ return stats;
3730
+ }
3731
+ getHookStats({ file, id, type }) {
3732
+ if (!this.options.verbose) {
3733
+ return;
3734
+ }
3735
+ const stats = this.runningTests.get(file.id);
3736
+ if (!stats) {
3737
+ return;
3738
+ }
3739
+ return type === "suite" ? stats : stats?.tests.get(id);
3740
+ }
3741
+ createSummary() {
3742
+ const summary = [""];
3743
+ for (const testFile of Array.from(this.runningTests.values()).sort(sortRunningTests)) {
3744
+ summary.push(
3745
+ c.bold(c.yellow(` ${F_POINTER} `)) + formatProjectName(testFile.projectName) + testFile.filename + c.dim(` ${testFile.completed}/${testFile.total}`)
3746
+ );
3747
+ const slowTasks = [
3748
+ testFile.hook,
3749
+ ...Array.from(testFile.tests.values())
3750
+ ].filter((t) => t != null && t.visible);
3751
+ for (const [index, task] of slowTasks.entries()) {
3752
+ const elapsed = this.currentTime - task.startTime;
3753
+ const icon = index === slowTasks.length - 1 ? F_TREE_NODE_END : F_TREE_NODE_MIDDLE;
3754
+ summary.push(
3755
+ c.bold(c.yellow(` ${icon} `)) + task.name + c.bold(c.yellow(` ${formatTime(Math.max(0, elapsed))}`))
3995
3756
  );
3996
- options.logger.log(renderTree$1(filteredTasks, options));
3997
- } else {
3998
- options.logger.log(renderTree$1(tasks, options));
3757
+ if (task.hook?.visible) {
3758
+ summary.push(c.bold(c.yellow(` ${F_TREE_NODE_END} `)) + task.hook.name);
3759
+ }
3999
3760
  }
4000
- return this;
4001
- },
4002
- clear() {
4003
- log.clear();
4004
3761
  }
4005
- };
3762
+ if (this.runningTests.size > 0) {
3763
+ summary.push("");
3764
+ }
3765
+ summary.push(padSummaryTitle("Test Files") + getStateString(this.suites));
3766
+ summary.push(padSummaryTitle("Tests") + getStateString(this.tests));
3767
+ summary.push(padSummaryTitle("Start at") + this.startTime);
3768
+ summary.push(padSummaryTitle("Duration") + formatTime(this.duration));
3769
+ summary.push("");
3770
+ return summary;
3771
+ }
3772
+ startTimers() {
3773
+ const start = performance.now();
3774
+ this.startTime = formatTimeString(/* @__PURE__ */ new Date());
3775
+ this.durationInterval = setInterval(() => {
3776
+ this.currentTime = performance.now();
3777
+ this.duration = this.currentTime - start;
3778
+ }, DURATION_UPDATE_INTERVAL_MS).unref();
3779
+ }
3780
+ removeTestFile(id) {
3781
+ if (!id) {
3782
+ return;
3783
+ }
3784
+ const testFile = this.runningTests.get(id);
3785
+ testFile?.hook?.onFinish();
3786
+ testFile?.tests?.forEach((test) => test.onFinish());
3787
+ this.runningTests.delete(id);
3788
+ clearTimeout(this.finishedTests.get(id));
3789
+ this.finishedTests.delete(id);
3790
+ }
3791
+ }
3792
+ function emptyCounters() {
3793
+ return { completed: 0, passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 };
3794
+ }
3795
+ function getStateString(entry) {
3796
+ return [
3797
+ entry.failed ? c.bold(c.red(`${entry.failed} failed`)) : null,
3798
+ c.bold(c.green(`${entry.passed} passed`)),
3799
+ entry.skipped ? c.yellow(`${entry.skipped} skipped`) : null,
3800
+ entry.todo ? c.gray(`${entry.todo} todo`) : null
3801
+ ].filter(Boolean).join(c.dim(" | ")) + c.gray(` (${entry.total})`);
3802
+ }
3803
+ function sortRunningTests(a, b) {
3804
+ if ((a.projectName || "") > (b.projectName || "")) {
3805
+ return 1;
3806
+ }
3807
+ if ((a.projectName || "") < (b.projectName || "")) {
3808
+ return -1;
3809
+ }
3810
+ return a.filename.localeCompare(b.filename);
4006
3811
  }
4007
3812
 
4008
3813
  class DefaultReporter extends BaseReporter {
4009
- renderer;
4010
- rendererOptions = {};
4011
- renderSucceedDefault;
4012
- onPathsCollected(paths = []) {
4013
- if (this.isTTY) {
4014
- if (this.renderSucceedDefault === void 0) {
4015
- this.renderSucceedDefault = !!this.rendererOptions.renderSucceed;
4016
- }
4017
- if (this.renderSucceedDefault !== true) {
4018
- this.rendererOptions.renderSucceed = paths.length <= 1;
4019
- }
3814
+ options;
3815
+ summary;
3816
+ constructor(options = {}) {
3817
+ super(options);
3818
+ this.options = {
3819
+ summary: true,
3820
+ ...options
3821
+ };
3822
+ if (!this.isTTY) {
3823
+ this.options.summary = false;
3824
+ }
3825
+ if (this.options.summary) {
3826
+ this.summary = new SummaryReporter();
4020
3827
  }
4021
3828
  }
4022
- async onTestRemoved(trigger) {
4023
- this.stopListRender();
4024
- this.ctx.logger.clearScreen(
4025
- c.yellow("Test removed...") + (trigger ? c.dim(` [ ${this.relative(trigger)} ]
4026
- `) : ""),
4027
- true
4028
- );
4029
- const files = this.ctx.state.getFiles(this.watchFilters);
4030
- createListRenderer(files, this.rendererOptions).stop();
4031
- this.ctx.logger.log();
4032
- super.reportSummary(files, this.ctx.state.getUnhandledErrors());
4033
- super.onWatcherStart();
3829
+ onInit(ctx) {
3830
+ super.onInit(ctx);
3831
+ this.summary?.onInit(ctx, { verbose: this.verbose });
4034
3832
  }
4035
- onCollected() {
3833
+ onPathsCollected(paths = []) {
4036
3834
  if (this.isTTY) {
4037
- this.rendererOptions.logger = this.ctx.logger;
4038
- this.rendererOptions.showHeap = this.ctx.config.logHeapUsage;
4039
- this.rendererOptions.slowTestThreshold = this.ctx.config.slowTestThreshold;
4040
- this.rendererOptions.mode = this.ctx.config.mode;
4041
- const files = this.ctx.state.getFiles(this.watchFilters);
4042
- if (!this.renderer) {
4043
- this.renderer = createListRenderer(files, this.rendererOptions).start();
4044
- } else {
4045
- this.renderer.update(files);
3835
+ if (this.renderSucceed === void 0) {
3836
+ this.renderSucceed = !!this.renderSucceed;
3837
+ }
3838
+ if (this.renderSucceed !== true) {
3839
+ this.renderSucceed = paths.length <= 1;
4046
3840
  }
4047
3841
  }
3842
+ this.summary?.onPathsCollected(paths);
4048
3843
  }
4049
- onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
4050
- this.renderer?.update([
4051
- ...this.failedUnwatchedFiles,
4052
- ...files
4053
- ]);
4054
- this.stopListRender();
4055
- this.ctx.logger.log();
4056
- super.onFinished(files, errors);
4057
- }
4058
- async onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
4059
- this.stopListRender();
4060
- await super.onWatcherStart(files, errors);
4061
- }
4062
- stopListRender() {
4063
- this.renderer?.stop();
4064
- this.renderer = void 0;
3844
+ onTaskUpdate(packs) {
3845
+ this.summary?.onTaskUpdate(packs);
3846
+ super.onTaskUpdate(packs);
4065
3847
  }
4066
- async onWatcherRerun(files, trigger) {
4067
- this.stopListRender();
4068
- await super.onWatcherRerun(files, trigger);
3848
+ onWatcherRerun(files, trigger) {
3849
+ this.summary?.onWatcherRerun();
3850
+ super.onWatcherRerun(files, trigger);
4069
3851
  }
4070
- onUserConsoleLog(log) {
4071
- if (!this.shouldLog(log)) {
4072
- return;
4073
- }
4074
- this.renderer?.clear();
4075
- super.onUserConsoleLog(log);
3852
+ onFinished(files, errors) {
3853
+ this.summary?.onFinished();
3854
+ super.onFinished(files, errors);
4076
3855
  }
4077
3856
  }
4078
3857
 
@@ -4172,6 +3951,8 @@ function createDotRenderer(_tasks, options) {
4172
3951
 
4173
3952
  class DotReporter extends BaseReporter {
4174
3953
  renderer;
3954
+ onTaskUpdate() {
3955
+ }
4175
3956
  onCollected() {
4176
3957
  if (this.isTTY) {
4177
3958
  const files = this.ctx.state.getFiles(this.watchFilters);
@@ -4217,7 +3998,7 @@ class GithubActionsReporter {
4217
3998
  const projectErrors = new Array();
4218
3999
  for (const error of errors) {
4219
4000
  projectErrors.push({
4220
- project: this.ctx.getCoreWorkspaceProject(),
4001
+ project: this.ctx.getRootTestProject(),
4221
4002
  title: "Unhandled error",
4222
4003
  error
4223
4004
  });
@@ -4311,7 +4092,7 @@ class JsonReporter {
4311
4092
  this.ctx = ctx;
4312
4093
  this.start = Date.now();
4313
4094
  }
4314
- async logTasks(files) {
4095
+ async logTasks(files, coverageMap) {
4315
4096
  const suites = getSuites(files);
4316
4097
  const numTotalTestSuites = suites.length;
4317
4098
  const tests = getTests(files);
@@ -4394,12 +4175,13 @@ class JsonReporter {
4394
4175
  snapshot: this.ctx.snapshot.summary,
4395
4176
  startTime: this.start,
4396
4177
  success,
4397
- testResults
4178
+ testResults,
4179
+ coverageMap
4398
4180
  };
4399
4181
  await this.writeReport(JSON.stringify(result));
4400
4182
  }
4401
- async onFinished(files = this.ctx.state.getFiles()) {
4402
- await this.logTasks(files);
4183
+ async onFinished(files = this.ctx.state.getFiles(), _errors = [], coverageMap) {
4184
+ await this.logTasks(files, coverageMap);
4403
4185
  }
4404
4186
  /**
4405
4187
  * Writes the report to an output file if specified in the config,
@@ -4554,10 +4336,22 @@ class JUnitReporter {
4554
4336
  }
4555
4337
  async writeTasks(tasks, filename) {
4556
4338
  for (const task of tasks) {
4339
+ let classname = filename;
4340
+ const templateVars = {
4341
+ filename: task.file.name,
4342
+ filepath: task.file.filepath
4343
+ };
4344
+ if (typeof this.options.classnameTemplate === "function") {
4345
+ classname = this.options.classnameTemplate(templateVars);
4346
+ } else if (typeof this.options.classnameTemplate === "string") {
4347
+ classname = this.options.classnameTemplate.replace(/\{filename\}/g, templateVars.filename).replace(/\{filepath\}/g, templateVars.filepath);
4348
+ } else if (typeof this.options.classname === "string") {
4349
+ classname = this.options.classname;
4350
+ }
4557
4351
  await this.writeElement(
4558
4352
  "testcase",
4559
4353
  {
4560
- classname: this.options.classname ?? filename,
4354
+ classname,
4561
4355
  file: this.options.addFileAttribute ? filename : void 0,
4562
4356
  name: task.name,
4563
4357
  time: getDuration(task)
@@ -4803,13 +4597,10 @@ class TapFlatReporter extends TapReporter {
4803
4597
 
4804
4598
  class VerboseReporter extends DefaultReporter {
4805
4599
  verbose = true;
4806
- constructor() {
4807
- super();
4808
- this.rendererOptions.renderSucceed = true;
4809
- }
4600
+ renderSucceed = true;
4810
4601
  onTaskUpdate(packs) {
4811
4602
  if (this.isTTY) {
4812
- return;
4603
+ return super.onTaskUpdate(packs);
4813
4604
  }
4814
4605
  for (const pack of packs) {
4815
4606
  const task = this.ctx.state.idMap.get(pack[0]);
@@ -4829,6 +4620,9 @@ class VerboseReporter extends DefaultReporter {
4829
4620
  ` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`
4830
4621
  );
4831
4622
  }
4623
+ if (task.result?.note) {
4624
+ title += c.dim(c.gray(` [${task.result.note}]`));
4625
+ }
4832
4626
  this.ctx.logger.log(title);
4833
4627
  if (task.result.state === "fail") {
4834
4628
  task.result.errors?.forEach((error) => {
@@ -5230,4 +5024,4 @@ const ReportersMap = {
5230
5024
  "github-actions": GithubActionsReporter
5231
5025
  };
5232
5026
 
5233
- export { BasicReporter as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, Logger as L, ReportersMap as R, TapFlatReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapReporter as c, TestFile as d, TestCase as e, TestModule as f, TestSuite as g, BenchmarkReportsMap as h, TestProject as i, generateCodeFrame as j, BlobReporter as k, parse as p, readBlobs as r, stringify as s };
5027
+ export { BasicReporter as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, Logger as L, ReportersMap as R, TapFlatReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapReporter as c, TestFile as d, TestCase as e, TestModule as f, TestSuite as g, BenchmarkReportsMap as h, generateCodeFrame as i, BlobReporter as j, parse as p, readBlobs as r, stringify as s };