vitest 2.2.0-beta.1 → 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.
@@ -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
  }
@@ -415,10 +352,10 @@ function getTestState(test) {
415
352
  return result ? result.state : "running";
416
353
  }
417
354
  function storeTask(project, runnerTask, reportedTask) {
418
- project.ctx.state.reportedTasksMap.set(runnerTask, reportedTask);
355
+ project.vitest.state.reportedTasksMap.set(runnerTask, reportedTask);
419
356
  }
420
357
  function getReportedTask(project, runnerTask) {
421
- const reportedTask = project.ctx.state.getReportedEntity(runnerTask);
358
+ const reportedTask = project.vitest.state.getReportedEntity(runnerTask);
422
359
  if (!reportedTask) {
423
360
  throw new Error(
424
361
  `Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`
@@ -534,7 +471,7 @@ const stringify = (value, replacer, space) => {
534
471
  }
535
472
  };
536
473
 
537
- const ESC$1 = '\u001B[';
474
+ const ESC$2 = '\u001B[';
538
475
  const OSC = '\u001B]';
539
476
  const BEL = '\u0007';
540
477
  const SEP = ';';
@@ -548,10 +485,10 @@ ansiEscapes.cursorTo = (x, y) => {
548
485
  }
549
486
 
550
487
  if (typeof y !== 'number') {
551
- return ESC$1 + (x + 1) + 'G';
488
+ return ESC$2 + (x + 1) + 'G';
552
489
  }
553
490
 
554
- return ESC$1 + (y + 1) + ';' + (x + 1) + 'H';
491
+ return ESC$2 + (y + 1) + ';' + (x + 1) + 'H';
555
492
  };
556
493
 
557
494
  ansiEscapes.cursorMove = (x, y) => {
@@ -562,33 +499,33 @@ ansiEscapes.cursorMove = (x, y) => {
562
499
  let returnValue = '';
563
500
 
564
501
  if (x < 0) {
565
- returnValue += ESC$1 + (-x) + 'D';
502
+ returnValue += ESC$2 + (-x) + 'D';
566
503
  } else if (x > 0) {
567
- returnValue += ESC$1 + x + 'C';
504
+ returnValue += ESC$2 + x + 'C';
568
505
  }
569
506
 
570
507
  if (y < 0) {
571
- returnValue += ESC$1 + (-y) + 'A';
508
+ returnValue += ESC$2 + (-y) + 'A';
572
509
  } else if (y > 0) {
573
- returnValue += ESC$1 + y + 'B';
510
+ returnValue += ESC$2 + y + 'B';
574
511
  }
575
512
 
576
513
  return returnValue;
577
514
  };
578
515
 
579
- ansiEscapes.cursorUp = (count = 1) => ESC$1 + count + 'A';
580
- ansiEscapes.cursorDown = (count = 1) => ESC$1 + count + 'B';
581
- ansiEscapes.cursorForward = (count = 1) => ESC$1 + count + 'C';
582
- 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';
583
520
 
584
- ansiEscapes.cursorLeft = ESC$1 + 'G';
585
- ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC$1 + 's';
586
- ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC$1 + 'u';
587
- ansiEscapes.cursorGetPosition = ESC$1 + '6n';
588
- ansiEscapes.cursorNextLine = ESC$1 + 'E';
589
- ansiEscapes.cursorPrevLine = ESC$1 + 'F';
590
- ansiEscapes.cursorHide = ESC$1 + '?25l';
591
- 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';
592
529
 
593
530
  ansiEscapes.eraseLines = count => {
594
531
  let clear = '';
@@ -604,24 +541,24 @@ ansiEscapes.eraseLines = count => {
604
541
  return clear;
605
542
  };
606
543
 
607
- ansiEscapes.eraseEndLine = ESC$1 + 'K';
608
- ansiEscapes.eraseStartLine = ESC$1 + '1K';
609
- ansiEscapes.eraseLine = ESC$1 + '2K';
610
- ansiEscapes.eraseDown = ESC$1 + 'J';
611
- ansiEscapes.eraseUp = ESC$1 + '1J';
612
- ansiEscapes.eraseScreen = ESC$1 + '2J';
613
- ansiEscapes.scrollUp = ESC$1 + 'S';
614
- 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';
615
552
 
616
553
  ansiEscapes.clearScreen = '\u001Bc';
617
554
 
618
555
  ansiEscapes.clearTerminal = process.platform === 'win32' ?
619
- `${ansiEscapes.eraseScreen}${ESC$1}0f` :
556
+ `${ansiEscapes.eraseScreen}${ESC$2}0f` :
620
557
  // 1. Erases the screen (Only done in case `2` is not supported)
621
558
  // 2. Erases the whole screen including scrollback buffer
622
559
  // 3. Moves cursor to the top-left position
623
560
  // More info: https://www.real-world-systems.com/docs/ANSIcode.html
624
- `${ansiEscapes.eraseScreen}${ESC$1}3J${ESC$1}H`;
561
+ `${ansiEscapes.eraseScreen}${ESC$2}3J${ESC$2}H`;
625
562
 
626
563
  ansiEscapes.beep = BEL;
627
564
 
@@ -689,370 +626,6 @@ ansiEscapes.iTerm = {
689
626
  }
690
627
  };
691
628
 
692
- var onetime$1 = {exports: {}};
693
-
694
- var mimicFn = {exports: {}};
695
-
696
- var hasRequiredMimicFn;
697
-
698
- function requireMimicFn () {
699
- if (hasRequiredMimicFn) return mimicFn.exports;
700
- hasRequiredMimicFn = 1;
701
-
702
- const mimicFn$1 = (to, from) => {
703
- for (const prop of Reflect.ownKeys(from)) {
704
- Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop));
705
- }
706
-
707
- return to;
708
- };
709
-
710
- mimicFn.exports = mimicFn$1;
711
- // TODO: Remove this for the next major release
712
- mimicFn.exports.default = mimicFn$1;
713
- return mimicFn.exports;
714
- }
715
-
716
- var hasRequiredOnetime;
717
-
718
- function requireOnetime () {
719
- if (hasRequiredOnetime) return onetime$1.exports;
720
- hasRequiredOnetime = 1;
721
- const mimicFn = requireMimicFn();
722
-
723
- const calledFunctions = new WeakMap();
724
-
725
- const onetime = (function_, options = {}) => {
726
- if (typeof function_ !== 'function') {
727
- throw new TypeError('Expected a function');
728
- }
729
-
730
- let returnValue;
731
- let callCount = 0;
732
- const functionName = function_.displayName || function_.name || '<anonymous>';
733
-
734
- const onetime = function (...arguments_) {
735
- calledFunctions.set(onetime, ++callCount);
736
-
737
- if (callCount === 1) {
738
- returnValue = function_.apply(this, arguments_);
739
- function_ = null;
740
- } else if (options.throw === true) {
741
- throw new Error(`Function \`${functionName}\` can only be called once`);
742
- }
743
-
744
- return returnValue;
745
- };
746
-
747
- mimicFn(onetime, function_);
748
- calledFunctions.set(onetime, callCount);
749
-
750
- return onetime;
751
- };
752
-
753
- onetime$1.exports = onetime;
754
- // TODO: Remove this for the next major release
755
- onetime$1.exports.default = onetime;
756
-
757
- onetime$1.exports.callCount = function_ => {
758
- if (!calledFunctions.has(function_)) {
759
- throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`);
760
- }
761
-
762
- return calledFunctions.get(function_);
763
- };
764
- return onetime$1.exports;
765
- }
766
-
767
- var onetimeExports = requireOnetime();
768
- var onetime = /*@__PURE__*/getDefaultExportFromCjs(onetimeExports);
769
-
770
- var signalExit$1 = {exports: {}};
771
-
772
- var signals = {exports: {}};
773
-
774
- var hasRequiredSignals;
775
-
776
- function requireSignals () {
777
- if (hasRequiredSignals) return signals.exports;
778
- hasRequiredSignals = 1;
779
- (function (module) {
780
- // This is not the set of all possible signals.
781
- //
782
- // It IS, however, the set of all signals that trigger
783
- // an exit on either Linux or BSD systems. Linux is a
784
- // superset of the signal names supported on BSD, and
785
- // the unknown signals just fail to register, so we can
786
- // catch that easily enough.
787
- //
788
- // Don't bother with SIGKILL. It's uncatchable, which
789
- // means that we can't fire any callbacks anyway.
790
- //
791
- // If a user does happen to register a handler on a non-
792
- // fatal signal like SIGWINCH or something, and then
793
- // exit, it'll end up firing `process.emit('exit')`, so
794
- // the handler will be fired anyway.
795
- //
796
- // SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
797
- // artificially, inherently leave the process in a
798
- // state from which it is not safe to try and enter JS
799
- // listeners.
800
- module.exports = [
801
- 'SIGABRT',
802
- 'SIGALRM',
803
- 'SIGHUP',
804
- 'SIGINT',
805
- 'SIGTERM'
806
- ];
807
-
808
- if (process.platform !== 'win32') {
809
- module.exports.push(
810
- 'SIGVTALRM',
811
- 'SIGXCPU',
812
- 'SIGXFSZ',
813
- 'SIGUSR2',
814
- 'SIGTRAP',
815
- 'SIGSYS',
816
- 'SIGQUIT',
817
- 'SIGIOT'
818
- // should detect profiler and enable/disable accordingly.
819
- // see #21
820
- // 'SIGPROF'
821
- );
822
- }
823
-
824
- if (process.platform === 'linux') {
825
- module.exports.push(
826
- 'SIGIO',
827
- 'SIGPOLL',
828
- 'SIGPWR',
829
- 'SIGSTKFLT',
830
- 'SIGUNUSED'
831
- );
832
- }
833
- } (signals));
834
- return signals.exports;
835
- }
836
-
837
- var hasRequiredSignalExit;
838
-
839
- function requireSignalExit () {
840
- if (hasRequiredSignalExit) return signalExit$1.exports;
841
- hasRequiredSignalExit = 1;
842
- // Note: since nyc uses this module to output coverage, any lines
843
- // that are in the direct sync flow of nyc's outputCoverage are
844
- // ignored, since we can never get coverage for them.
845
- // grab a reference to node's real process object right away
846
- var process = commonjsGlobal.process;
847
-
848
- const processOk = function (process) {
849
- return process &&
850
- typeof process === 'object' &&
851
- typeof process.removeListener === 'function' &&
852
- typeof process.emit === 'function' &&
853
- typeof process.reallyExit === 'function' &&
854
- typeof process.listeners === 'function' &&
855
- typeof process.kill === 'function' &&
856
- typeof process.pid === 'number' &&
857
- typeof process.on === 'function'
858
- };
859
-
860
- // some kind of non-node environment, just no-op
861
- /* istanbul ignore if */
862
- if (!processOk(process)) {
863
- signalExit$1.exports = function () {
864
- return function () {}
865
- };
866
- } else {
867
- var assert = require$$0;
868
- var signals = requireSignals();
869
- var isWin = /^win/i.test(process.platform);
870
-
871
- var EE = require$$0$1;
872
- /* istanbul ignore if */
873
- if (typeof EE !== 'function') {
874
- EE = EE.EventEmitter;
875
- }
876
-
877
- var emitter;
878
- if (process.__signal_exit_emitter__) {
879
- emitter = process.__signal_exit_emitter__;
880
- } else {
881
- emitter = process.__signal_exit_emitter__ = new EE();
882
- emitter.count = 0;
883
- emitter.emitted = {};
884
- }
885
-
886
- // Because this emitter is a global, we have to check to see if a
887
- // previous version of this library failed to enable infinite listeners.
888
- // I know what you're about to say. But literally everything about
889
- // signal-exit is a compromise with evil. Get used to it.
890
- if (!emitter.infinite) {
891
- emitter.setMaxListeners(Infinity);
892
- emitter.infinite = true;
893
- }
894
-
895
- signalExit$1.exports = function (cb, opts) {
896
- /* istanbul ignore if */
897
- if (!processOk(commonjsGlobal.process)) {
898
- return function () {}
899
- }
900
- assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler');
901
-
902
- if (loaded === false) {
903
- load();
904
- }
905
-
906
- var ev = 'exit';
907
- if (opts && opts.alwaysLast) {
908
- ev = 'afterexit';
909
- }
910
-
911
- var remove = function () {
912
- emitter.removeListener(ev, cb);
913
- if (emitter.listeners('exit').length === 0 &&
914
- emitter.listeners('afterexit').length === 0) {
915
- unload();
916
- }
917
- };
918
- emitter.on(ev, cb);
919
-
920
- return remove
921
- };
922
-
923
- var unload = function unload () {
924
- if (!loaded || !processOk(commonjsGlobal.process)) {
925
- return
926
- }
927
- loaded = false;
928
-
929
- signals.forEach(function (sig) {
930
- try {
931
- process.removeListener(sig, sigListeners[sig]);
932
- } catch (er) {}
933
- });
934
- process.emit = originalProcessEmit;
935
- process.reallyExit = originalProcessReallyExit;
936
- emitter.count -= 1;
937
- };
938
- signalExit$1.exports.unload = unload;
939
-
940
- var emit = function emit (event, code, signal) {
941
- /* istanbul ignore if */
942
- if (emitter.emitted[event]) {
943
- return
944
- }
945
- emitter.emitted[event] = true;
946
- emitter.emit(event, code, signal);
947
- };
948
-
949
- // { <signal>: <listener fn>, ... }
950
- var sigListeners = {};
951
- signals.forEach(function (sig) {
952
- sigListeners[sig] = function listener () {
953
- /* istanbul ignore if */
954
- if (!processOk(commonjsGlobal.process)) {
955
- return
956
- }
957
- // If there are no other listeners, an exit is coming!
958
- // Simplest way: remove us and then re-send the signal.
959
- // We know that this will kill the process, so we can
960
- // safely emit now.
961
- var listeners = process.listeners(sig);
962
- if (listeners.length === emitter.count) {
963
- unload();
964
- emit('exit', null, sig);
965
- /* istanbul ignore next */
966
- emit('afterexit', null, sig);
967
- /* istanbul ignore next */
968
- if (isWin && sig === 'SIGHUP') {
969
- // "SIGHUP" throws an `ENOSYS` error on Windows,
970
- // so use a supported signal instead
971
- sig = 'SIGINT';
972
- }
973
- /* istanbul ignore next */
974
- process.kill(process.pid, sig);
975
- }
976
- };
977
- });
978
-
979
- signalExit$1.exports.signals = function () {
980
- return signals
981
- };
982
-
983
- var loaded = false;
984
-
985
- var load = function load () {
986
- if (loaded || !processOk(commonjsGlobal.process)) {
987
- return
988
- }
989
- loaded = true;
990
-
991
- // This is the number of onSignalExit's that are in play.
992
- // It's important so that we can count the correct number of
993
- // listeners on signals, and don't wait for the other one to
994
- // handle it instead of us.
995
- emitter.count += 1;
996
-
997
- signals = signals.filter(function (sig) {
998
- try {
999
- process.on(sig, sigListeners[sig]);
1000
- return true
1001
- } catch (er) {
1002
- return false
1003
- }
1004
- });
1005
-
1006
- process.emit = processEmit;
1007
- process.reallyExit = processReallyExit;
1008
- };
1009
- signalExit$1.exports.load = load;
1010
-
1011
- var originalProcessReallyExit = process.reallyExit;
1012
- var processReallyExit = function processReallyExit (code) {
1013
- /* istanbul ignore if */
1014
- if (!processOk(commonjsGlobal.process)) {
1015
- return
1016
- }
1017
- process.exitCode = code || /* istanbul ignore next */ 0;
1018
- emit('exit', process.exitCode, null);
1019
- /* istanbul ignore next */
1020
- emit('afterexit', process.exitCode, null);
1021
- /* istanbul ignore next */
1022
- originalProcessReallyExit.call(process, process.exitCode);
1023
- };
1024
-
1025
- var originalProcessEmit = process.emit;
1026
- var processEmit = function processEmit (ev, arg) {
1027
- if (ev === 'exit' && processOk(commonjsGlobal.process)) {
1028
- /* istanbul ignore else */
1029
- if (arg !== undefined) {
1030
- process.exitCode = arg;
1031
- }
1032
- var ret = originalProcessEmit.apply(this, arguments);
1033
- /* istanbul ignore next */
1034
- emit('exit', process.exitCode, null);
1035
- /* istanbul ignore next */
1036
- emit('afterexit', process.exitCode, null);
1037
- /* istanbul ignore next */
1038
- return ret
1039
- } else {
1040
- return originalProcessEmit.apply(this, arguments)
1041
- }
1042
- };
1043
- }
1044
- return signalExit$1.exports;
1045
- }
1046
-
1047
- var signalExitExports = requireSignalExit();
1048
- var signalExit = /*@__PURE__*/getDefaultExportFromCjs(signalExitExports);
1049
-
1050
- const restoreCursor = onetime(() => {
1051
- signalExit(() => {
1052
- process$1.stderr.write('\u001B[?25h');
1053
- }, {alwaysLast: true});
1054
- });
1055
-
1056
629
  let isHidden = false;
1057
630
 
1058
631
  const cliCursor = {};
@@ -3026,10 +2599,10 @@ function lineNo(no = "") {
3026
2599
  }
3027
2600
 
3028
2601
  const PAD = " ";
3029
- const ESC = "\x1B[";
3030
- const ERASE_DOWN = `${ESC}J`;
3031
- const ERASE_SCROLLBACK = `${ESC}3J`;
3032
- 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`;
3033
2606
  const CLEAR_SCREEN = "\x1Bc";
3034
2607
  class Logger {
3035
2608
  constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
@@ -3088,7 +2661,7 @@ class Logger {
3088
2661
  }
3089
2662
  printError(err, options = {}) {
3090
2663
  const { fullStack = false, type } = options;
3091
- const project = options.project ?? this.ctx.getCoreWorkspaceProject() ?? this.ctx.projects[0];
2664
+ const project = options.project ?? this.ctx.coreWorkspaceProject ?? this.ctx.projects[0];
3092
2665
  return printError(err, project, {
3093
2666
  type,
3094
2667
  showCodeFrame: options.showCodeFrame ?? true,
@@ -3137,8 +2710,7 @@ class Logger {
3137
2710
  }
3138
2711
  this.ctx.projects.forEach((project) => {
3139
2712
  const config2 = project.config;
3140
- const name = project.getName();
3141
- const output = project.isCore() || !name ? "" : `[${name}]`;
2713
+ const output = project.isRootProject() || !project.name ? "" : `[${project.name}]`;
3142
2714
  if (output) {
3143
2715
  this.console.error(c.bgCyan(`${output} Config`));
3144
2716
  }
@@ -3214,8 +2786,7 @@ Vitest is running in standalone mode. Edit a test file to rerun tests.`));
3214
2786
  if (!origin) {
3215
2787
  return;
3216
2788
  }
3217
- const name = project.getName();
3218
- const output = project.isCore() ? "" : formatProjectName(name);
2789
+ const output = project.isRootProject() ? "" : formatProjectName(project.name);
3219
2790
  const provider = project.browser.provider.name;
3220
2791
  const providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
3221
2792
  this.log(
@@ -3296,7 +2867,7 @@ class BlobReporter {
3296
2867
  (project) => {
3297
2868
  return [
3298
2869
  project.getName(),
3299
- [...project.server.moduleGraph.idToModuleMap.entries()].map((mod) => {
2870
+ [...project.vite.moduleGraph.idToModuleMap.entries()].map((mod) => {
3300
2871
  if (!mod[1].file) {
3301
2872
  return null;
3302
2873
  }
@@ -3372,10 +2943,10 @@ ${blobs.map((b) => `- "${b.file}" uses v${b.version}`).join("\n")}`
3372
2943
  return;
3373
2944
  }
3374
2945
  moduleIds.forEach(([moduleId, file, url]) => {
3375
- const moduleNode = project.server.moduleGraph.createFileOnlyEntry(file);
2946
+ const moduleNode = project.vite.moduleGraph.createFileOnlyEntry(file);
3376
2947
  moduleNode.url = url;
3377
2948
  moduleNode.id = moduleId;
3378
- project.server.moduleGraph.idToModuleMap.set(moduleId, moduleNode);
2949
+ project.vite.moduleGraph.idToModuleMap.set(moduleId, moduleNode);
3379
2950
  });
3380
2951
  });
3381
2952
  });
@@ -3402,7 +2973,6 @@ function hasFailedSnapshot(suite) {
3402
2973
  }
3403
2974
 
3404
2975
  const BADGE_PADDING = " ";
3405
- const LAST_RUN_LOG_TIMEOUT = 1500;
3406
2976
  class BaseReporter {
3407
2977
  start = 0;
3408
2978
  end = 0;
@@ -3410,19 +2980,17 @@ class BaseReporter {
3410
2980
  failedUnwatchedFiles = [];
3411
2981
  isTTY;
3412
2982
  ctx = void 0;
2983
+ renderSucceed = false;
3413
2984
  verbose = false;
3414
2985
  _filesInWatchMode = /* @__PURE__ */ new Map();
3415
2986
  _timeStart = formatTimeString(/* @__PURE__ */ new Date());
3416
- _lastRunTimeout = 0;
3417
- _lastRunTimer;
3418
- _lastRunCount = 0;
3419
2987
  constructor(options = {}) {
3420
2988
  this.isTTY = options.isTTY ?? ((isNode || isDeno) && process.stdout?.isTTY && !isCI);
3421
2989
  }
3422
2990
  onInit(ctx) {
3423
2991
  this.ctx = ctx;
3424
2992
  this.ctx.logger.printBanner();
3425
- this.start = performance.now();
2993
+ this.start = performance$1.now();
3426
2994
  }
3427
2995
  log(...messages) {
3428
2996
  this.ctx.logger.log(...messages);
@@ -3434,13 +3002,10 @@ class BaseReporter {
3434
3002
  return relative(this.ctx.config.root, path);
3435
3003
  }
3436
3004
  onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
3437
- this.end = performance.now();
3005
+ this.end = performance$1.now();
3438
3006
  this.reportSummary(files, errors);
3439
3007
  }
3440
3008
  onTaskUpdate(packs) {
3441
- if (this.isTTY) {
3442
- return;
3443
- }
3444
3009
  for (const pack of packs) {
3445
3010
  const task = this.ctx.state.idMap.get(pack[0]);
3446
3011
  if (task) {
@@ -3474,6 +3039,7 @@ class BaseReporter {
3474
3039
  title += ` ${formatProjectName(task.projectName, "")}`;
3475
3040
  }
3476
3041
  this.log(` ${title} ${task.name} ${suffix}`);
3042
+ const anyFailed = tests.some((test) => test.result?.state === "fail");
3477
3043
  for (const test of tests) {
3478
3044
  const duration = test.result?.duration;
3479
3045
  if (test.result?.state === "fail") {
@@ -3486,6 +3052,10 @@ class BaseReporter {
3486
3052
  this.log(
3487
3053
  ` ${c.yellow(c.dim(F_CHECK))} ${getTestName(test, c.dim(" > "))} ${c.yellow(Math.round(duration) + c.dim("ms"))}`
3488
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(" > "))}`);
3489
3059
  }
3490
3060
  }
3491
3061
  }
@@ -3497,7 +3067,6 @@ class BaseReporter {
3497
3067
  return color(` ${Math.round(task.result.duration)}${c.dim("ms")}`);
3498
3068
  }
3499
3069
  onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
3500
- this.resetLastRunLog();
3501
3070
  const failed = errors.length > 0 || hasFailed(files);
3502
3071
  if (failed) {
3503
3072
  this.log(withLabel("red", "FAIL", "Tests failed. Watching for file changes..."));
@@ -3513,34 +3082,8 @@ class BaseReporter {
3513
3082
  hints.push(c.dim("press ") + c.bold("q") + c.dim(" to quit"));
3514
3083
  }
3515
3084
  this.log(BADGE_PADDING + hints.join(c.dim(", ")));
3516
- if (this._lastRunCount) {
3517
- const LAST_RUN_TEXT = `rerun x${this._lastRunCount}`;
3518
- const LAST_RUN_TEXTS = [
3519
- c.blue(LAST_RUN_TEXT),
3520
- c.gray(LAST_RUN_TEXT),
3521
- c.dim(c.gray(LAST_RUN_TEXT))
3522
- ];
3523
- this.ctx.logger.logUpdate(BADGE_PADDING + LAST_RUN_TEXTS[0]);
3524
- this._lastRunTimeout = 0;
3525
- this._lastRunTimer = setInterval(() => {
3526
- this._lastRunTimeout += 1;
3527
- if (this._lastRunTimeout >= LAST_RUN_TEXTS.length) {
3528
- this.resetLastRunLog();
3529
- } else {
3530
- this.ctx.logger.logUpdate(
3531
- BADGE_PADDING + LAST_RUN_TEXTS[this._lastRunTimeout]
3532
- );
3533
- }
3534
- }, LAST_RUN_LOG_TIMEOUT / LAST_RUN_TEXTS.length);
3535
- }
3536
- }
3537
- resetLastRunLog() {
3538
- clearInterval(this._lastRunTimer);
3539
- this._lastRunTimer = void 0;
3540
- this.ctx.logger.logUpdate.clear();
3541
3085
  }
3542
3086
  onWatcherRerun(files, trigger) {
3543
- this.resetLastRunLog();
3544
3087
  this.watchFilters = files;
3545
3088
  this.failedUnwatchedFiles = this.ctx.state.getFiles().filter(
3546
3089
  (file) => !files.includes(file.filepath) && hasFailed(file)
@@ -3550,9 +3093,7 @@ class BaseReporter {
3550
3093
  this._filesInWatchMode.set(filepath, ++reruns);
3551
3094
  });
3552
3095
  let banner = trigger ? c.dim(`${this.relative(trigger)} `) : "";
3553
- if (files.length > 1 || !files.length) {
3554
- this._lastRunCount = 0;
3555
- } else if (files.length === 1) {
3096
+ if (files.length === 1) {
3556
3097
  const rerun = this._filesInWatchMode.get(files[0]) ?? 1;
3557
3098
  banner += c.blue(`x${rerun} `);
3558
3099
  }
@@ -3568,13 +3109,11 @@ class BaseReporter {
3568
3109
  this.log(BADGE_PADDING + c.dim(" Test name pattern: ") + c.blue(String(this.ctx.configOverride.testNamePattern)));
3569
3110
  }
3570
3111
  this.log("");
3571
- if (!this.isTTY) {
3572
- for (const task of this.failedUnwatchedFiles) {
3573
- this.printTask(task);
3574
- }
3112
+ for (const task of this.failedUnwatchedFiles) {
3113
+ this.printTask(task);
3575
3114
  }
3576
3115
  this._timeStart = formatTimeString(/* @__PURE__ */ new Date());
3577
- this.start = performance.now();
3116
+ this.start = performance$1.now();
3578
3117
  }
3579
3118
  onUserConsoleLog(log) {
3580
3119
  if (!this.shouldLog(log)) {
@@ -3595,7 +3134,7 @@ class BaseReporter {
3595
3134
  if (log.browser) {
3596
3135
  write("\n");
3597
3136
  }
3598
- 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();
3599
3138
  const stack = log.browser ? project.browser?.parseStacktrace(log.origin) || [] : parseStacktrace(log.origin);
3600
3139
  const highlight = task && stack.find((i) => i.file === task.file.filepath);
3601
3140
  for (const frame of stack) {
@@ -3639,6 +3178,7 @@ class BaseReporter {
3639
3178
  }
3640
3179
  }
3641
3180
  reportTestSummary(files, errors) {
3181
+ this.log();
3642
3182
  const affectedFiles = [
3643
3183
  ...this.failedUnwatchedFiles,
3644
3184
  ...files
@@ -3650,32 +3190,32 @@ class BaseReporter {
3650
3190
  );
3651
3191
  for (const [index, snapshot] of snapshotOutput.entries()) {
3652
3192
  const title = index === 0 ? "Snapshots" : "";
3653
- this.log(`${padTitle(title)} ${snapshot}`);
3193
+ this.log(`${padSummaryTitle(title)} ${snapshot}`);
3654
3194
  }
3655
3195
  if (snapshotOutput.length > 1) {
3656
3196
  this.log();
3657
3197
  }
3658
- this.log(padTitle("Test Files"), getStateString(affectedFiles));
3659
- this.log(padTitle("Tests"), getStateString(tests));
3198
+ this.log(padSummaryTitle("Test Files"), getStateString$1(affectedFiles));
3199
+ this.log(padSummaryTitle("Tests"), getStateString$1(tests));
3660
3200
  if (this.ctx.projects.some((c2) => c2.config.typecheck.enabled)) {
3661
3201
  const failed = tests.filter((t) => t.meta?.typecheck && t.result?.errors?.length);
3662
3202
  this.log(
3663
- padTitle("Type Errors"),
3203
+ padSummaryTitle("Type Errors"),
3664
3204
  failed.length ? c.bold(c.red(`${failed.length} failed`)) : c.dim("no errors")
3665
3205
  );
3666
3206
  }
3667
3207
  if (errors.length) {
3668
3208
  this.log(
3669
- padTitle("Errors"),
3209
+ padSummaryTitle("Errors"),
3670
3210
  c.bold(c.red(`${errors.length} error${errors.length > 1 ? "s" : ""}`))
3671
3211
  );
3672
3212
  }
3673
- this.log(padTitle("Start at"), this._timeStart);
3213
+ this.log(padSummaryTitle("Start at"), this._timeStart);
3674
3214
  const collectTime = sum(files, (file) => file.collectDuration);
3675
3215
  const testsTime = sum(files, (file) => file.result?.duration);
3676
3216
  const setupTime = sum(files, (file) => file.setupDuration);
3677
3217
  if (this.watchFilters) {
3678
- this.log(padTitle("Duration"), time(collectTime + testsTime + setupTime));
3218
+ this.log(padSummaryTitle("Duration"), formatTime(collectTime + testsTime + setupTime));
3679
3219
  } else {
3680
3220
  const executionTime = this.end - this.start;
3681
3221
  const environmentTime = sum(files, (file) => file.environmentLoad);
@@ -3683,15 +3223,15 @@ class BaseReporter {
3683
3223
  const transformTime = sum(this.ctx.projects, (project) => project.vitenode.getTotalDuration());
3684
3224
  const typecheck = sum(this.ctx.projects, (project) => project.typechecker?.getResult().time);
3685
3225
  const timers = [
3686
- `transform ${time(transformTime)}`,
3687
- `setup ${time(setupTime)}`,
3688
- `collect ${time(collectTime)}`,
3689
- `tests ${time(testsTime)}`,
3690
- `environment ${time(environmentTime)}`,
3691
- `prepare ${time(prepareTime)}`,
3692
- 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)}`
3693
3233
  ].filter(Boolean).join(", ");
3694
- this.log(padTitle("Duration"), time(executionTime) + c.dim(` (${timers})`));
3234
+ this.log(padSummaryTitle("Duration"), formatTime(executionTime) + c.dim(` (${timers})`));
3695
3235
  }
3696
3236
  this.log();
3697
3237
  }
@@ -3786,15 +3326,6 @@ class BaseReporter {
3786
3326
  function errorBanner(message) {
3787
3327
  return c.red(divider(c.bold(c.inverse(` ${message} `))));
3788
3328
  }
3789
- function padTitle(str) {
3790
- return c.dim(`${str.padStart(11)} `);
3791
- }
3792
- function time(time2) {
3793
- if (time2 > 1e3) {
3794
- return `${(time2 / 1e3).toFixed(2)}s`;
3795
- }
3796
- return `${Math.round(time2)}ms`;
3797
- }
3798
3329
  function sum(items, cb) {
3799
3330
  return items.reduce((total, next) => {
3800
3331
  return total + Math.max(cb(next) || 0, 0);
@@ -3806,289 +3337,521 @@ class BasicReporter extends BaseReporter {
3806
3337
  super();
3807
3338
  this.isTTY = false;
3808
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
+ }
3809
3348
  reportSummary(files, errors) {
3810
3349
  this.ctx.logger.log();
3811
3350
  return super.reportSummary(files, errors);
3812
3351
  }
3813
3352
  }
3814
3353
 
3815
- const outputMap$1 = /* @__PURE__ */ new WeakMap();
3816
- function formatFilepath$1(path) {
3817
- const lastSlash = Math.max(path.lastIndexOf("/") + 1, 0);
3818
- const basename = path.slice(lastSlash);
3819
- let firstDot = basename.indexOf(".");
3820
- if (firstDot < 0) {
3821
- 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();
3822
3386
  }
3823
- firstDot += lastSlash;
3824
- return c.dim(path.slice(0, lastSlash)) + path.slice(lastSlash, firstDot) + c.dim(path.slice(firstDot));
3825
- }
3826
- function formatNumber$1(number) {
3827
- const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
3828
- return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
3829
- }
3830
- function renderHookState(task, hookName, level = 0) {
3831
- const state = task.result?.hooks?.[hookName];
3832
- if (state && state === "run") {
3833
- return `${" ".repeat(level)} ${getHookStateSymbol(task, hookName)} ${c.dim(
3834
- `[ ${hookName} ]`
3835
- )}`;
3836
- }
3837
- return "";
3838
- }
3839
- function renderBenchmarkItems$1(result) {
3840
- return [
3841
- result.name,
3842
- formatNumber$1(result.hz || 0),
3843
- formatNumber$1(result.p99 || 0),
3844
- `\xB1${result.rme.toFixed(2)}%`,
3845
- result.samples.length.toString()
3846
- ];
3847
- }
3848
- function renderBenchmark$1(task, tasks) {
3849
- const result = task.result?.benchmark;
3850
- if (!result) {
3851
- return task.name;
3852
- }
3853
- const benches = tasks.map((i) => i.meta?.benchmark ? i.result?.benchmark : void 0).filter(notNullish);
3854
- const allItems = benches.map(renderBenchmarkItems$1);
3855
- const items = renderBenchmarkItems$1(result);
3856
- const padded = items.map((i, idx) => {
3857
- const width = Math.max(...allItems.map((i2) => i2[idx].length));
3858
- return idx ? i.padStart(width, " ") : i.padEnd(width, " ");
3859
- });
3860
- return [
3861
- padded[0],
3862
- // name
3863
- c.dim(" "),
3864
- c.blue(padded[1]),
3865
- c.dim(" ops/sec "),
3866
- c.cyan(padded[3]),
3867
- c.dim(` (${padded[4]} samples)`),
3868
- result.rank === 1 ? c.bold(c.green(" fastest")) : result.rank === benches.length && benches.length > 2 ? c.bold(c.gray(" slowest")) : ""
3869
- ].join("");
3870
- }
3871
- function renderTree$1(tasks, options, level = 0, maxRows) {
3872
- const output = [];
3873
- let currentRowCount = 0;
3874
- for (const task of [...tasks].reverse()) {
3875
- const taskOutput = [];
3876
- let suffix = "";
3877
- let prefix = ` ${getStateSymbol(task)} `;
3878
- if (level === 0 && task.type === "suite" && "projectName" in task) {
3879
- prefix += formatProjectName(task.projectName);
3880
- }
3881
- if (level === 0 && task.type === "suite" && task.meta.typecheck) {
3882
- prefix += c.bgBlue(c.bold(" TS "));
3883
- 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;
3884
3421
  }
3885
- if (task.type === "test" && task.result?.retryCount && task.result.retryCount > 0) {
3886
- suffix += c.yellow(` (retry x${task.result.retryCount})`);
3422
+ if (current) {
3423
+ this.render(current?.message, current?.type);
3887
3424
  }
3888
- if (task.type === "suite") {
3889
- const tests = getTests(task);
3890
- suffix += c.dim(` (${tests.length})`);
3425
+ }
3426
+ render(message, type = "output") {
3427
+ if (this.finished) {
3428
+ this.clearWindow();
3429
+ return this.write(message || "", type);
3891
3430
  }
3892
- if (task.mode === "skip" || task.mode === "todo") {
3893
- const note = task.result?.note || "skipped";
3894
- suffix += ` ${c.dim(c.gray(`[${note}]`))}`;
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);
3895
3436
  }
3896
- if (task.type === "test" && task.result?.repeatCount && task.result.repeatCount > 0) {
3897
- suffix += c.yellow(` (repeat x${task.result.repeatCount})`);
3437
+ this.write(SYNC_START);
3438
+ this.clearWindow();
3439
+ if (message) {
3440
+ this.write(message, type);
3898
3441
  }
3899
- if (task.result?.duration != null) {
3900
- if (task.result.duration > options.slowTestThreshold) {
3901
- suffix += c.yellow(
3902
- ` ${Math.round(task.result.duration)}${c.dim("ms")}`
3903
- );
3904
- }
3442
+ if (padding > 0) {
3443
+ this.write("\n".repeat(padding));
3905
3444
  }
3906
- if (options.showHeap && task.result?.heap != null) {
3907
- suffix += c.magenta(
3908
- ` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`
3909
- );
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;
3910
3452
  }
3911
- let name = task.name;
3912
- if (level === 0) {
3913
- 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}`);
3914
3456
  }
3915
- const padding = " ".repeat(level);
3916
- const body = task.meta?.benchmark ? renderBenchmark$1(task, tasks) : name;
3917
- taskOutput.push(padding + prefix + body + suffix);
3918
- if (task.result?.state !== "pass" && outputMap$1.get(task) != null) {
3919
- let data = outputMap$1.get(task);
3920
- if (typeof data === "string") {
3921
- data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
3922
- if (data === "") {
3923
- 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() });
3924
3467
  }
3925
3468
  }
3926
- if (data != null) {
3927
- const out = `${" ".repeat(level)}${F_RIGHT} ${data}`;
3928
- taskOutput.push(` ${c.gray(cliTruncate(out, getCols(-3)))}`);
3929
- }
3930
- }
3931
- taskOutput.push(renderHookState(task, "beforeAll", level + 1));
3932
- taskOutput.push(renderHookState(task, "beforeEach", level + 1));
3933
- if (task.type === "suite" && task.tasks.length > 0) {
3934
- if (task.result?.state === "fail" || task.result?.state === "run" || options.renderSucceed) {
3935
- if (options.logger.ctx.config.hideSkippedTests) {
3936
- const filteredTasks = task.tasks.filter(
3937
- (t) => t.mode !== "skip" && t.mode !== "todo"
3938
- );
3939
- taskOutput.push(
3940
- renderTree$1(filteredTasks, options, level + 1, maxRows)
3941
- );
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);
3942
3518
  } else {
3943
- 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
+ }
3944
3541
  }
3945
3542
  }
3946
3543
  }
3947
- taskOutput.push(renderHookState(task, "afterAll", level + 1));
3948
- taskOutput.push(renderHookState(task, "afterEach", level + 1));
3949
- const rows = taskOutput.filter(Boolean);
3950
- output.push(rows.join("\n"));
3951
- currentRowCount += rows.length;
3952
- if (maxRows && currentRowCount >= maxRows) {
3953
- break;
3954
- }
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
+ );
3955
3552
  }
3956
- return output.reverse().join("\n");
3957
3553
  }
3958
- function createListRenderer(_tasks, options) {
3959
- let tasks = _tasks;
3960
- let timer;
3961
- const log = options.logger.logUpdate;
3962
- function update() {
3963
- if (options.logger.ctx.config.hideSkippedTests) {
3964
- const filteredTasks = tasks.filter(
3965
- (t) => t.mode !== "skip" && t.mode !== "todo"
3966
- );
3967
- log(
3968
- renderTree$1(
3969
- filteredTasks,
3970
- options,
3971
- 0,
3972
- // log-update already limits the amount of printed rows to fit the current terminal
3973
- // but we can optimize performance by doing it ourselves
3974
- process.stdout.rows
3975
- )
3976
- );
3977
- } else {
3978
- log(
3979
- renderTree$1(
3980
- tasks,
3981
- options,
3982
- 0,
3983
- // log-update already limits the amount of printed rows to fit the current terminal
3984
- // but we can optimize performance by doing it ourselves
3985
- process.stdout.rows
3986
- )
3987
- );
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;
3988
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);
3989
3626
  }
3990
- return {
3991
- start() {
3992
- if (timer) {
3993
- 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: () => {
3994
3637
  }
3995
- timer = setInterval(update, 16);
3996
- return this;
3997
- },
3998
- update(_tasks2) {
3999
- tasks = _tasks2;
4000
- return this;
4001
- },
4002
- stop() {
4003
- if (timer) {
4004
- clearInterval(timer);
4005
- 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: () => {
4006
3667
  }
4007
- log.clear();
4008
- if (options.logger.ctx.config.hideSkippedTests) {
4009
- const filteredTasks = tasks.filter(
4010
- (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))}`))
4011
3756
  );
4012
- options.logger.log(renderTree$1(filteredTasks, options));
4013
- } else {
4014
- 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
+ }
4015
3760
  }
4016
- return this;
4017
- },
4018
- clear() {
4019
- log.clear();
4020
3761
  }
4021
- };
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);
4022
3811
  }
4023
3812
 
4024
3813
  class DefaultReporter extends BaseReporter {
4025
- renderer;
4026
- rendererOptions = {};
4027
- renderSucceedDefault;
4028
- onPathsCollected(paths = []) {
4029
- if (this.isTTY) {
4030
- if (this.renderSucceedDefault === void 0) {
4031
- this.renderSucceedDefault = !!this.rendererOptions.renderSucceed;
4032
- }
4033
- if (this.renderSucceedDefault !== true) {
4034
- this.rendererOptions.renderSucceed = paths.length <= 1;
4035
- }
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();
4036
3827
  }
4037
3828
  }
4038
- async onTestRemoved(trigger) {
4039
- this.stopListRender();
4040
- this.ctx.logger.clearScreen(
4041
- c.yellow("Test removed...") + (trigger ? c.dim(` [ ${this.relative(trigger)} ]
4042
- `) : ""),
4043
- true
4044
- );
4045
- const files = this.ctx.state.getFiles(this.watchFilters);
4046
- createListRenderer(files, this.rendererOptions).stop();
4047
- this.ctx.logger.log();
4048
- super.reportSummary(files, this.ctx.state.getUnhandledErrors());
4049
- super.onWatcherStart();
3829
+ onInit(ctx) {
3830
+ super.onInit(ctx);
3831
+ this.summary?.onInit(ctx, { verbose: this.verbose });
4050
3832
  }
4051
- onCollected() {
3833
+ onPathsCollected(paths = []) {
4052
3834
  if (this.isTTY) {
4053
- this.rendererOptions.logger = this.ctx.logger;
4054
- this.rendererOptions.showHeap = this.ctx.config.logHeapUsage;
4055
- this.rendererOptions.slowTestThreshold = this.ctx.config.slowTestThreshold;
4056
- this.rendererOptions.mode = this.ctx.config.mode;
4057
- const files = this.ctx.state.getFiles(this.watchFilters);
4058
- if (!this.renderer) {
4059
- this.renderer = createListRenderer(files, this.rendererOptions).start();
4060
- } else {
4061
- 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;
4062
3840
  }
4063
3841
  }
3842
+ this.summary?.onPathsCollected(paths);
4064
3843
  }
4065
- onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
4066
- this.renderer?.update([
4067
- ...this.failedUnwatchedFiles,
4068
- ...files
4069
- ]);
4070
- this.stopListRender();
4071
- this.ctx.logger.log();
4072
- super.onFinished(files, errors);
4073
- }
4074
- async onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
4075
- this.stopListRender();
4076
- await super.onWatcherStart(files, errors);
4077
- }
4078
- stopListRender() {
4079
- this.renderer?.stop();
4080
- this.renderer = void 0;
3844
+ onTaskUpdate(packs) {
3845
+ this.summary?.onTaskUpdate(packs);
3846
+ super.onTaskUpdate(packs);
4081
3847
  }
4082
- async onWatcherRerun(files, trigger) {
4083
- this.stopListRender();
4084
- await super.onWatcherRerun(files, trigger);
3848
+ onWatcherRerun(files, trigger) {
3849
+ this.summary?.onWatcherRerun();
3850
+ super.onWatcherRerun(files, trigger);
4085
3851
  }
4086
- onUserConsoleLog(log) {
4087
- if (!this.shouldLog(log)) {
4088
- return;
4089
- }
4090
- this.renderer?.clear();
4091
- super.onUserConsoleLog(log);
3852
+ onFinished(files, errors) {
3853
+ this.summary?.onFinished();
3854
+ super.onFinished(files, errors);
4092
3855
  }
4093
3856
  }
4094
3857
 
@@ -4188,6 +3951,8 @@ function createDotRenderer(_tasks, options) {
4188
3951
 
4189
3952
  class DotReporter extends BaseReporter {
4190
3953
  renderer;
3954
+ onTaskUpdate() {
3955
+ }
4191
3956
  onCollected() {
4192
3957
  if (this.isTTY) {
4193
3958
  const files = this.ctx.state.getFiles(this.watchFilters);
@@ -4233,7 +3998,7 @@ class GithubActionsReporter {
4233
3998
  const projectErrors = new Array();
4234
3999
  for (const error of errors) {
4235
4000
  projectErrors.push({
4236
- project: this.ctx.getCoreWorkspaceProject(),
4001
+ project: this.ctx.getRootTestProject(),
4237
4002
  title: "Unhandled error",
4238
4003
  error
4239
4004
  });
@@ -4571,10 +4336,22 @@ class JUnitReporter {
4571
4336
  }
4572
4337
  async writeTasks(tasks, filename) {
4573
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
+ }
4574
4351
  await this.writeElement(
4575
4352
  "testcase",
4576
4353
  {
4577
- classname: this.options.classname ?? filename,
4354
+ classname,
4578
4355
  file: this.options.addFileAttribute ? filename : void 0,
4579
4356
  name: task.name,
4580
4357
  time: getDuration(task)
@@ -4820,13 +4597,10 @@ class TapFlatReporter extends TapReporter {
4820
4597
 
4821
4598
  class VerboseReporter extends DefaultReporter {
4822
4599
  verbose = true;
4823
- constructor() {
4824
- super();
4825
- this.rendererOptions.renderSucceed = true;
4826
- }
4600
+ renderSucceed = true;
4827
4601
  onTaskUpdate(packs) {
4828
4602
  if (this.isTTY) {
4829
- return;
4603
+ return super.onTaskUpdate(packs);
4830
4604
  }
4831
4605
  for (const pack of packs) {
4832
4606
  const task = this.ctx.state.idMap.get(pack[0]);
@@ -5250,4 +5024,4 @@ const ReportersMap = {
5250
5024
  "github-actions": GithubActionsReporter
5251
5025
  };
5252
5026
 
5253
- 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 };