modestbench 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +131 -34
- package/dist/cli/commands/analyze.cjs +60 -0
- package/dist/cli/commands/analyze.cjs.map +1 -0
- package/dist/cli/commands/analyze.d.cts +35 -0
- package/dist/cli/commands/analyze.d.cts.map +1 -0
- package/dist/cli/commands/analyze.d.ts +35 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +56 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/baseline.cjs +404 -0
- package/dist/cli/commands/baseline.cjs.map +1 -0
- package/dist/cli/commands/baseline.d.cts +72 -0
- package/dist/cli/commands/baseline.d.cts.map +1 -0
- package/dist/cli/commands/baseline.d.ts +72 -0
- package/dist/cli/commands/baseline.d.ts.map +1 -0
- package/dist/cli/commands/baseline.js +396 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/history.d.cts +1 -1
- package/dist/cli/commands/history.d.cts.map +1 -1
- package/dist/cli/commands/history.d.ts +1 -1
- package/dist/cli/commands/history.d.ts.map +1 -1
- package/dist/cli/commands/init.cjs +99 -166
- package/dist/cli/commands/init.cjs.map +1 -1
- package/dist/cli/commands/init.d.cts +4 -4
- package/dist/cli/commands/init.d.cts.map +1 -1
- package/dist/cli/commands/init.d.ts +4 -4
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +99 -166
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.cjs +146 -127
- package/dist/cli/commands/run.cjs.map +1 -1
- package/dist/cli/commands/run.d.cts +16 -3
- package/dist/cli/commands/run.d.cts.map +1 -1
- package/dist/cli/commands/run.d.ts +16 -3
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +145 -93
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/index.cjs +583 -394
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +4 -16
- package/dist/cli/index.d.cts.map +1 -1
- package/dist/cli/index.d.ts +4 -16
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +575 -386
- package/dist/cli/index.js.map +1 -1
- package/dist/config/budget-schema.cjs +172 -0
- package/dist/config/budget-schema.cjs.map +1 -0
- package/dist/config/budget-schema.d.cts +59 -0
- package/dist/config/budget-schema.d.cts.map +1 -0
- package/dist/config/budget-schema.d.ts +59 -0
- package/dist/config/budget-schema.d.ts.map +1 -0
- package/dist/config/budget-schema.js +166 -0
- package/dist/config/budget-schema.js.map +1 -0
- package/dist/config/schema.cjs +182 -2
- package/dist/config/schema.cjs.map +1 -1
- package/dist/config/schema.d.cts +122 -3
- package/dist/config/schema.d.cts.map +1 -1
- package/dist/config/schema.d.ts +122 -3
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +180 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/constants.cjs +45 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +41 -0
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +44 -1
- package/dist/constants.js.map +1 -1
- package/dist/core/engine.cjs +114 -23
- package/dist/core/engine.cjs.map +1 -1
- package/dist/core/engine.d.cts +7 -7
- package/dist/core/engine.d.cts.map +1 -1
- package/dist/core/engine.d.ts +7 -7
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +115 -24
- package/dist/core/engine.js.map +1 -1
- package/dist/core/engines/accurate-engine.cjs +171 -36
- package/dist/core/engines/accurate-engine.cjs.map +1 -1
- package/dist/core/engines/accurate-engine.d.cts +5 -0
- package/dist/core/engines/accurate-engine.d.cts.map +1 -1
- package/dist/core/engines/accurate-engine.d.ts +5 -0
- package/dist/core/engines/accurate-engine.d.ts.map +1 -1
- package/dist/core/engines/accurate-engine.js +171 -36
- package/dist/core/engines/accurate-engine.js.map +1 -1
- package/dist/core/engines/tinybench-engine.cjs +3 -2
- package/dist/core/engines/tinybench-engine.cjs.map +1 -1
- package/dist/core/engines/tinybench-engine.d.cts.map +1 -1
- package/dist/core/engines/tinybench-engine.d.ts.map +1 -1
- package/dist/core/engines/tinybench-engine.js +3 -2
- package/dist/core/engines/tinybench-engine.js.map +1 -1
- package/dist/core/output-path-resolver.cjs +8 -1
- package/dist/core/output-path-resolver.cjs.map +1 -1
- package/dist/core/output-path-resolver.d.cts.map +1 -1
- package/dist/core/output-path-resolver.d.ts.map +1 -1
- package/dist/core/output-path-resolver.js +9 -2
- package/dist/core/output-path-resolver.js.map +1 -1
- package/dist/errors/base.cjs +12 -3
- package/dist/errors/base.cjs.map +1 -1
- package/dist/errors/base.d.cts +7 -0
- package/dist/errors/base.d.cts.map +1 -1
- package/dist/errors/base.d.ts +7 -0
- package/dist/errors/base.d.ts.map +1 -1
- package/dist/errors/base.js +10 -2
- package/dist/errors/base.js.map +1 -1
- package/dist/errors/budget.cjs +37 -0
- package/dist/errors/budget.cjs.map +1 -0
- package/dist/errors/budget.d.cts +31 -0
- package/dist/errors/budget.d.cts.map +1 -0
- package/dist/errors/budget.d.ts +31 -0
- package/dist/errors/budget.d.ts.map +1 -0
- package/dist/errors/budget.js +33 -0
- package/dist/errors/budget.js.map +1 -0
- package/dist/errors/index.cjs +4 -1
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +1 -0
- package/dist/errors/index.d.cts.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/index.cjs +13 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/reporters/csv.cjs +37 -17
- package/dist/reporters/csv.cjs.map +1 -1
- package/dist/reporters/csv.d.cts +3 -6
- package/dist/reporters/csv.d.cts.map +1 -1
- package/dist/reporters/csv.d.ts +3 -6
- package/dist/reporters/csv.d.ts.map +1 -1
- package/dist/reporters/csv.js +37 -17
- package/dist/reporters/csv.js.map +1 -1
- package/dist/reporters/human.cjs +290 -67
- package/dist/reporters/human.cjs.map +1 -1
- package/dist/reporters/human.d.cts +25 -13
- package/dist/reporters/human.d.cts.map +1 -1
- package/dist/reporters/human.d.ts +25 -13
- package/dist/reporters/human.d.ts.map +1 -1
- package/dist/reporters/human.js +290 -67
- package/dist/reporters/human.js.map +1 -1
- package/dist/reporters/json.cjs +23 -48
- package/dist/reporters/json.cjs.map +1 -1
- package/dist/reporters/json.d.cts +2 -28
- package/dist/reporters/json.d.cts.map +1 -1
- package/dist/reporters/json.d.ts +2 -28
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +25 -50
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/profile-human.cjs +154 -0
- package/dist/reporters/profile-human.cjs.map +1 -0
- package/dist/reporters/profile-human.d.cts +44 -0
- package/dist/reporters/profile-human.d.cts.map +1 -0
- package/dist/reporters/profile-human.d.ts +44 -0
- package/dist/reporters/profile-human.d.ts.map +1 -0
- package/dist/reporters/profile-human.js +147 -0
- package/dist/reporters/profile-human.js.map +1 -0
- package/dist/reporters/simple.cjs +67 -45
- package/dist/reporters/simple.cjs.map +1 -1
- package/dist/reporters/simple.d.cts +14 -14
- package/dist/reporters/simple.d.cts.map +1 -1
- package/dist/reporters/simple.d.ts +14 -14
- package/dist/reporters/simple.d.ts.map +1 -1
- package/dist/reporters/simple.js +67 -45
- package/dist/reporters/simple.js.map +1 -1
- package/dist/schema/modestbench-config.schema.json +153 -0
- package/dist/services/baseline-storage.cjs +151 -0
- package/dist/services/baseline-storage.cjs.map +1 -0
- package/dist/services/baseline-storage.d.cts +55 -0
- package/dist/services/baseline-storage.d.cts.map +1 -0
- package/dist/services/baseline-storage.d.ts +55 -0
- package/dist/services/baseline-storage.d.ts.map +1 -0
- package/dist/services/baseline-storage.js +147 -0
- package/dist/services/baseline-storage.js.map +1 -0
- package/dist/services/budget-evaluator.cjs +146 -0
- package/dist/services/budget-evaluator.cjs.map +1 -0
- package/dist/services/budget-evaluator.d.cts +29 -0
- package/dist/services/budget-evaluator.d.cts.map +1 -0
- package/dist/services/budget-evaluator.d.ts +29 -0
- package/dist/services/budget-evaluator.d.ts.map +1 -0
- package/dist/services/budget-evaluator.js +142 -0
- package/dist/services/budget-evaluator.js.map +1 -0
- package/dist/services/config-manager.cjs +24 -10
- package/dist/services/config-manager.cjs.map +1 -1
- package/dist/services/config-manager.d.cts +6 -1
- package/dist/services/config-manager.d.cts.map +1 -1
- package/dist/services/config-manager.d.ts +6 -1
- package/dist/services/config-manager.d.ts.map +1 -1
- package/dist/services/config-manager.js +24 -10
- package/dist/services/config-manager.js.map +1 -1
- package/dist/services/file-loader.cjs +3 -6
- package/dist/services/file-loader.cjs.map +1 -1
- package/dist/services/file-loader.d.cts.map +1 -1
- package/dist/services/file-loader.d.ts.map +1 -1
- package/dist/services/file-loader.js +3 -6
- package/dist/services/file-loader.js.map +1 -1
- package/dist/services/profiler/profile-filter.cjs +116 -0
- package/dist/services/profiler/profile-filter.cjs.map +1 -0
- package/dist/services/profiler/profile-filter.d.cts +20 -0
- package/dist/services/profiler/profile-filter.d.cts.map +1 -0
- package/dist/services/profiler/profile-filter.d.ts +20 -0
- package/dist/services/profiler/profile-filter.d.ts.map +1 -0
- package/dist/services/profiler/profile-filter.js +112 -0
- package/dist/services/profiler/profile-filter.js.map +1 -0
- package/dist/services/profiler/profile-parser.cjs +139 -0
- package/dist/services/profiler/profile-parser.cjs.map +1 -0
- package/dist/services/profiler/profile-parser.d.cts +18 -0
- package/dist/services/profiler/profile-parser.d.cts.map +1 -0
- package/dist/services/profiler/profile-parser.d.ts +18 -0
- package/dist/services/profiler/profile-parser.d.ts.map +1 -0
- package/dist/services/profiler/profile-parser.js +132 -0
- package/dist/services/profiler/profile-parser.js.map +1 -0
- package/dist/services/profiler/profile-runner.cjs +90 -0
- package/dist/services/profiler/profile-runner.cjs.map +1 -0
- package/dist/services/profiler/profile-runner.d.cts +29 -0
- package/dist/services/profiler/profile-runner.d.cts.map +1 -0
- package/dist/services/profiler/profile-runner.d.ts +29 -0
- package/dist/services/profiler/profile-runner.d.ts.map +1 -0
- package/dist/services/profiler/profile-runner.js +86 -0
- package/dist/services/profiler/profile-runner.js.map +1 -0
- package/dist/services/progress-manager.cjs +10 -2
- package/dist/services/progress-manager.cjs.map +1 -1
- package/dist/services/progress-manager.d.cts +2 -0
- package/dist/services/progress-manager.d.cts.map +1 -1
- package/dist/services/progress-manager.d.ts +2 -0
- package/dist/services/progress-manager.d.ts.map +1 -1
- package/dist/services/progress-manager.js +10 -2
- package/dist/services/progress-manager.js.map +1 -1
- package/dist/services/reporter-registry.cjs +18 -24
- package/dist/services/reporter-registry.cjs.map +1 -1
- package/dist/services/reporter-registry.d.cts +18 -40
- package/dist/services/reporter-registry.d.cts.map +1 -1
- package/dist/services/reporter-registry.d.ts +18 -40
- package/dist/services/reporter-registry.d.ts.map +1 -1
- package/dist/services/reporter-registry.js +18 -24
- package/dist/services/reporter-registry.js.map +1 -1
- package/dist/types/budgets.cjs +8 -0
- package/dist/types/budgets.cjs.map +1 -0
- package/dist/types/budgets.d.cts +149 -0
- package/dist/types/budgets.d.cts.map +1 -0
- package/dist/types/budgets.d.ts +149 -0
- package/dist/types/budgets.d.ts.map +1 -0
- package/dist/types/budgets.js +7 -0
- package/dist/types/budgets.js.map +1 -0
- package/dist/types/cli.cjs +2 -11
- package/dist/types/cli.cjs.map +1 -1
- package/dist/types/cli.d.cts +3 -227
- package/dist/types/cli.d.cts.map +1 -1
- package/dist/types/cli.d.ts +3 -227
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/cli.js +2 -11
- package/dist/types/cli.js.map +1 -1
- package/dist/types/core.cjs +6 -1
- package/dist/types/core.cjs.map +1 -1
- package/dist/types/core.d.cts +15 -2
- package/dist/types/core.d.cts.map +1 -1
- package/dist/types/core.d.ts +15 -2
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +2 -1
- package/dist/types/core.js.map +1 -1
- package/dist/types/index.cjs +5 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/interfaces.d.cts +19 -8
- package/dist/types/interfaces.d.cts.map +1 -1
- package/dist/types/interfaces.d.ts +19 -8
- package/dist/types/interfaces.d.ts.map +1 -1
- package/dist/types/profiler.cjs +11 -0
- package/dist/types/profiler.cjs.map +1 -0
- package/dist/types/profiler.d.cts +102 -0
- package/dist/types/profiler.d.cts.map +1 -0
- package/dist/types/profiler.d.ts +102 -0
- package/dist/types/profiler.d.ts.map +1 -0
- package/dist/types/profiler.js +10 -0
- package/dist/types/profiler.js.map +1 -0
- package/dist/types/utility.cjs.map +1 -1
- package/dist/types/utility.d.cts +0 -8
- package/dist/types/utility.d.cts.map +1 -1
- package/dist/types/utility.d.ts +0 -8
- package/dist/types/utility.d.ts.map +1 -1
- package/dist/types/utility.js.map +1 -1
- package/dist/utils/identifiers.cjs +32 -0
- package/dist/utils/identifiers.cjs.map +1 -0
- package/dist/utils/identifiers.d.cts +32 -0
- package/dist/utils/identifiers.d.cts.map +1 -0
- package/dist/utils/identifiers.d.ts +32 -0
- package/dist/utils/identifiers.d.ts.map +1 -0
- package/dist/utils/identifiers.js +27 -0
- package/dist/utils/identifiers.js.map +1 -0
- package/dist/utils/package.cjs +40 -0
- package/dist/utils/package.cjs.map +1 -0
- package/dist/utils/package.d.cts +15 -0
- package/dist/utils/package.d.cts.map +1 -0
- package/dist/utils/package.d.ts +15 -0
- package/dist/utils/package.d.ts.map +1 -0
- package/dist/utils/package.js +33 -0
- package/dist/utils/package.js.map +1 -0
- package/dist/utils/type-guards.cjs +48 -0
- package/dist/utils/type-guards.cjs.map +1 -0
- package/dist/utils/type-guards.d.cts +22 -0
- package/dist/utils/type-guards.d.cts.map +1 -0
- package/dist/utils/type-guards.d.ts +22 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +43 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/package.json +18 -19
- package/src/cli/commands/analyze.ts +101 -0
- package/src/cli/commands/baseline.ts +577 -0
- package/src/cli/commands/history.ts +1 -1
- package/src/cli/commands/init.ts +116 -194
- package/src/cli/commands/run.ts +183 -113
- package/src/cli/index.ts +425 -183
- package/src/config/budget-schema.ts +189 -0
- package/src/config/schema.ts +260 -1
- package/src/constants.ts +53 -1
- package/src/core/engine.ts +169 -22
- package/src/core/engines/accurate-engine.ts +195 -44
- package/src/core/engines/tinybench-engine.ts +3 -2
- package/src/core/output-path-resolver.ts +10 -2
- package/src/errors/base.ts +11 -2
- package/src/errors/budget.ts +38 -0
- package/src/errors/index.ts +3 -0
- package/src/index.ts +9 -0
- package/src/reporters/csv.ts +54 -25
- package/src/reporters/human.ts +434 -115
- package/src/reporters/json.ts +26 -71
- package/src/reporters/profile-human.ts +210 -0
- package/src/reporters/simple.ts +88 -54
- package/src/services/baseline-storage.ts +199 -0
- package/src/services/budget-evaluator.ts +182 -0
- package/src/services/config-manager.ts +24 -9
- package/src/services/file-loader.ts +3 -6
- package/src/services/profiler/profile-filter.ts +147 -0
- package/src/services/profiler/profile-parser.ts +194 -0
- package/src/services/profiler/profile-runner.ts +121 -0
- package/src/services/progress-manager.ts +12 -2
- package/src/services/reporter-registry.ts +46 -81
- package/src/types/budgets.ts +180 -0
- package/src/types/cli.ts +5 -238
- package/src/types/core.ts +52 -10
- package/src/types/index.ts +5 -0
- package/src/types/interfaces.ts +24 -6
- package/src/types/profiler.ts +135 -0
- package/src/types/utility.ts +0 -10
- package/src/utils/identifiers.ts +58 -0
- package/src/utils/package.ts +35 -0
- package/src/utils/type-guards.ts +51 -0
package/dist/reporters/human.cjs
CHANGED
|
@@ -19,8 +19,10 @@ const ansi_js_1 = require("../utils/ansi.cjs");
|
|
|
19
19
|
class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
20
20
|
currentFile = '';
|
|
21
21
|
currentSuite = '';
|
|
22
|
+
currentSuiteMaxNameLen = 0; // Track max name length for current suite alignment
|
|
22
23
|
failures = [];
|
|
23
24
|
lastProgressLine = '';
|
|
25
|
+
maxTimePadWidth = 0; // Track maximum time padding width to prevent jitter
|
|
24
26
|
progressWindowActive = false; // Track if progress window is rendered
|
|
25
27
|
quiet;
|
|
26
28
|
showProgress;
|
|
@@ -40,6 +42,63 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
40
42
|
this.quiet = options.quiet ?? false;
|
|
41
43
|
this.showProgress = options.progress ?? true;
|
|
42
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Format bytes in human-readable format
|
|
47
|
+
*/
|
|
48
|
+
static formatBytes(bytes) {
|
|
49
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
50
|
+
let size = bytes;
|
|
51
|
+
let unitIndex = 0;
|
|
52
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
53
|
+
size /= 1024;
|
|
54
|
+
unitIndex++;
|
|
55
|
+
}
|
|
56
|
+
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Format file path - show relative path if within CWD, otherwise absolute
|
|
60
|
+
*/
|
|
61
|
+
static formatPath(filePath) {
|
|
62
|
+
const cwd = process.cwd();
|
|
63
|
+
const absolutePath = node_path_1.default.resolve(filePath);
|
|
64
|
+
// Check if the file is within the current working directory
|
|
65
|
+
if (absolutePath.startsWith(cwd + node_path_1.default.sep) || absolutePath === cwd) {
|
|
66
|
+
return node_path_1.default.relative(cwd, absolutePath);
|
|
67
|
+
}
|
|
68
|
+
return absolutePath;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Simple pluralization helper
|
|
72
|
+
*/
|
|
73
|
+
static pluralize(str, count) {
|
|
74
|
+
return count === 1 ? str : `${str}s`;
|
|
75
|
+
}
|
|
76
|
+
onBudgetResult(summary) {
|
|
77
|
+
if (summary.total === 0 || this.quiet) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.clearProgress();
|
|
81
|
+
this.printLine();
|
|
82
|
+
const budgetHeader = `${this.colorize('magenta', ansi_js_1.ansiChars.block.full.repeat(2))} ${this.colorize('brightWhite', this.colorize('bold', 'Performance Budgets'))}`;
|
|
83
|
+
this.printLine(budgetHeader);
|
|
84
|
+
this.printLine();
|
|
85
|
+
for (const result of summary.results) {
|
|
86
|
+
const icon = result.passed ? ansi_js_1.ansiChars.checkmark : ansi_js_1.ansiChars.cross;
|
|
87
|
+
const iconColor = result.passed ? 'brightCyan' : 'brightRed';
|
|
88
|
+
this.printLine(` ${this.colorize(iconColor, icon)} ${this.colorize('white', result.taskId)}`);
|
|
89
|
+
if (!result.passed && result.violations.length > 0) {
|
|
90
|
+
for (const violation of result.violations) {
|
|
91
|
+
this.printLine(` ${this.colorize('brightRed', violation.message)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
this.printLine();
|
|
96
|
+
const statusText = summary.failed === 0
|
|
97
|
+
? `${this.colorize('brightCyan', ansi_js_1.ansiChars.checkmark)} All ${summary.total} budget(s) passed`
|
|
98
|
+
: `${this.colorize('brightRed', ansi_js_1.ansiChars.cross)} ${summary.failed} of ${summary.total} budget(s) failed`;
|
|
99
|
+
this.printLine(` ${statusText}`);
|
|
100
|
+
this.printLine();
|
|
101
|
+
}
|
|
43
102
|
onEnd(run) {
|
|
44
103
|
if (this.quiet) {
|
|
45
104
|
return;
|
|
@@ -51,11 +110,13 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
51
110
|
let totalSuites = 0;
|
|
52
111
|
let totalPassed = 0;
|
|
53
112
|
let totalFailed = 0;
|
|
113
|
+
let totalAborted = 0;
|
|
54
114
|
for (const file of run.files) {
|
|
55
115
|
totalSuites += file.suites.length;
|
|
56
116
|
for (const suite of file.suites) {
|
|
57
|
-
totalPassed += suite.tasks.filter((t) => !t.error).length;
|
|
117
|
+
totalPassed += suite.tasks.filter((t) => !t.error && !t.aborted).length;
|
|
58
118
|
totalFailed += suite.tasks.filter((t) => t.error).length;
|
|
119
|
+
totalAborted += suite.tasks.filter((t) => t.aborted).length;
|
|
59
120
|
}
|
|
60
121
|
}
|
|
61
122
|
// Results header
|
|
@@ -64,15 +125,22 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
64
125
|
this.printLine();
|
|
65
126
|
this.printLine(`${this.colorize('brightBlue', ' Files:')} ${this.colorize('brightWhite', String(totalFiles))}`);
|
|
66
127
|
this.printLine(`${this.colorize('brightBlue', ' Suites:')} ${this.colorize('brightWhite', String(totalSuites))}`);
|
|
67
|
-
this.printLine(`${this.colorize('brightBlue', ' Tasks:')} ${this.colorize('brightWhite', String(totalPassed + totalFailed))}`);
|
|
68
|
-
if (totalFailed > 0) {
|
|
69
|
-
|
|
70
|
-
|
|
128
|
+
this.printLine(`${this.colorize('brightBlue', ' Tasks:')} ${this.colorize('brightWhite', String(totalPassed + totalFailed + totalAborted))}`);
|
|
129
|
+
if (totalFailed > 0 || totalAborted > 0) {
|
|
130
|
+
if (totalFailed > 0) {
|
|
131
|
+
this.printLine(`${this.colorize('brightRed', ansi_js_1.ansiChars.cross + ' Failed:')} ${this.colorize('brightWhite', String(totalFailed))}`);
|
|
132
|
+
}
|
|
133
|
+
if (totalPassed > 0) {
|
|
134
|
+
this.printLine(`${this.colorize('brightCyan', ansi_js_1.ansiChars.checkmark + ' Passed:')} ${this.colorize('brightWhite', String(totalPassed))}`);
|
|
135
|
+
}
|
|
136
|
+
if (totalAborted > 0) {
|
|
137
|
+
this.printLine(`${this.colorize('brightYellow', ansi_js_1.ansiChars.approx + ' Aborted:')} ${this.colorize('brightWhite', String(totalAborted))}`);
|
|
138
|
+
}
|
|
71
139
|
}
|
|
72
140
|
else {
|
|
73
141
|
this.printLine(`${this.colorize('brightCyan', ansi_js_1.ansiChars.checkmark + ' All tasks passed:')} ${this.colorize('brightWhite', String(totalPassed))}`);
|
|
74
142
|
}
|
|
75
|
-
this.printLine(`${this.colorize('cyan', ansi_js_1.ansiChars.approx + ' Duration:')} ${this.colorize('brightWhite',
|
|
143
|
+
this.printLine(`${this.colorize('cyan', ansi_js_1.ansiChars.approx + ' Duration:')} ${this.colorize('brightWhite', reporter_registry_js_1.BaseReporter.formatDuration(duration * 1000000))}`);
|
|
76
144
|
this.printLine();
|
|
77
145
|
if (totalFailed > 0) {
|
|
78
146
|
// Display failed tasks with details
|
|
@@ -81,14 +149,15 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
81
149
|
this.printLine(this.colorize('brightRed', this.colorize('bold', 'Failed Tasks:')));
|
|
82
150
|
this.printLine();
|
|
83
151
|
for (const failure of this.failures) {
|
|
84
|
-
const displayPath =
|
|
152
|
+
const displayPath = HumanReporter.formatPath(failure.file);
|
|
85
153
|
this.printLine(` ${this.colorize('dim', displayPath)} ${this.colorize('dim', '›')} ${this.colorize('white', failure.suite)} ${this.colorize('dim', '›')} ${this.colorize('brightWhite', failure.task)}`);
|
|
86
154
|
this.printLine(` ${this.colorize('brightRed', failure.error)}`);
|
|
87
155
|
this.printLine();
|
|
88
156
|
}
|
|
89
157
|
}
|
|
90
158
|
}
|
|
91
|
-
else {
|
|
159
|
+
else if (totalAborted === 0) {
|
|
160
|
+
// Only show "Rad" if no failures AND no aborts
|
|
92
161
|
const successMessage = `${this.colorize('brightMagenta', 'Rad. ☮')}`;
|
|
93
162
|
this.printLine(successMessage);
|
|
94
163
|
}
|
|
@@ -114,7 +183,7 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
114
183
|
this.printLine(this.colorize('red', ` ${ansi_js_1.ansiChars.cross} ${totalFailed} failed, ${totalPassed} passed`));
|
|
115
184
|
}
|
|
116
185
|
else {
|
|
117
|
-
this.printLine(` ${this.colorize('magenta', ansi_js_1.ansiChars.checkmark)} ${totalPassed > 1 ? this.colorize('brightMagenta', 'All ') : ''}${this.colorize('bold', this.colorize('brightMagenta', `${totalPassed}`))} ${this.colorize('brightMagenta', `${
|
|
186
|
+
this.printLine(` ${this.colorize('magenta', ansi_js_1.ansiChars.checkmark)} ${totalPassed > 1 ? this.colorize('brightMagenta', 'All ') : ''}${this.colorize('bold', this.colorize('brightMagenta', `${totalPassed}`))} ${this.colorize('brightMagenta', `${HumanReporter.pluralize('task', totalPassed)} passed`)}`);
|
|
118
187
|
}
|
|
119
188
|
this.printLine();
|
|
120
189
|
}
|
|
@@ -123,7 +192,7 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
123
192
|
if (this.quiet) {
|
|
124
193
|
return;
|
|
125
194
|
}
|
|
126
|
-
const displayPath =
|
|
195
|
+
const displayPath = HumanReporter.formatPath(file);
|
|
127
196
|
const fileMarker = `${ansi_js_1.colors.magenta}${ansi_js_1.ansiChars.block.dark}${ansi_js_1.ansiChars.block.dark}${ansi_js_1.colors.reset}`;
|
|
128
197
|
this.printLine(`${fileMarker} ${ansi_js_1.colors.underline}${this.colorize('brightMagenta', this.colorize('bold', displayPath))}${ansi_js_1.colors.reset}`);
|
|
129
198
|
}
|
|
@@ -136,7 +205,7 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
136
205
|
if (!process.stdout.isTTY) {
|
|
137
206
|
return;
|
|
138
207
|
}
|
|
139
|
-
const { elapsed, percentage, tasksCompleted, totalTasks } = state;
|
|
208
|
+
const { currentTask, elapsed, percentage, tasksCompleted, totalTasks } = state;
|
|
140
209
|
// Pad task counts for alignment
|
|
141
210
|
const totalTasksWidth = String(totalTasks).length;
|
|
142
211
|
const paddedTasksCompleted = String(tasksCompleted).padStart(totalTasksWidth, ' ');
|
|
@@ -145,7 +214,7 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
145
214
|
const elapsedStrRaw = this.formatTimeRemaining(elapsedSeconds);
|
|
146
215
|
// Calculate ETA if we have completed tasks and determine padding width
|
|
147
216
|
let etaStr = '';
|
|
148
|
-
let padWidth = elapsedStrRaw.length;
|
|
217
|
+
let padWidth = Math.max(this.maxTimePadWidth, elapsedStrRaw.length);
|
|
149
218
|
if (tasksCompleted > 0) {
|
|
150
219
|
const avgTimePerTask = elapsed / tasksCompleted;
|
|
151
220
|
const remainingTasks = totalTasks - tasksCompleted;
|
|
@@ -153,12 +222,21 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
153
222
|
const etaSeconds = Math.round(etaMs / 1000);
|
|
154
223
|
const etaTimeStr = this.formatTimeRemaining(etaSeconds);
|
|
155
224
|
padWidth = Math.max(padWidth, etaTimeStr.length);
|
|
156
|
-
etaStr = ` ${this.colorize('
|
|
225
|
+
etaStr = ` ${this.colorize('gray', '|')} ${this.colorize('gray', 'ETA:')} ${this.colorize('brightBlue', etaTimeStr)}`;
|
|
157
226
|
}
|
|
227
|
+
// Remember the maximum width we've ever used to prevent jitter
|
|
228
|
+
this.maxTimePadWidth = Math.max(this.maxTimePadWidth, padWidth);
|
|
158
229
|
// Pad elapsed time to match the longest time string
|
|
159
|
-
const elapsedStr = elapsedStrRaw.padStart(
|
|
230
|
+
const elapsedStr = elapsedStrRaw.padStart(this.maxTimePadWidth, ' ');
|
|
160
231
|
const roundedPercentage = percentage.toFixed(2);
|
|
161
|
-
|
|
232
|
+
// Build progress line with current task if available
|
|
233
|
+
let line = `${this.colorize('brightCyan', ansi_js_1.ansiChars.approx)} ${this.colorize('white', paddedTasksCompleted)}${this.colorize('gray', '/')}${this.colorize('white', String(totalTasks))} ${this.colorize('gray', 'tasks')} ${this.colorize('gray', '(')}${this.colorize('brightBlue', roundedPercentage + '%')}${this.colorize('gray', ')')} ${this.colorize('gray', '|')} ${this.colorize('gray', 'Elapsed:')} ${this.colorize('cyan', elapsedStr)}${etaStr}`;
|
|
234
|
+
if (currentTask) {
|
|
235
|
+
const truncatedTask = currentTask.length > 60
|
|
236
|
+
? currentTask.substring(0, 57) + '...'
|
|
237
|
+
: currentTask;
|
|
238
|
+
line += ` ${this.colorize('gray', '|')} ${this.colorize('white', truncatedTask)}`;
|
|
239
|
+
}
|
|
162
240
|
this.lastProgressLine = line;
|
|
163
241
|
this.renderProgressWindow();
|
|
164
242
|
}
|
|
@@ -166,6 +244,7 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
166
244
|
this.startTime = Date.now();
|
|
167
245
|
this.failures = []; // Reset failures for new run
|
|
168
246
|
this.lastProgressLine = ''; // Reset for new run
|
|
247
|
+
this.maxTimePadWidth = 0; // Reset time padding width for new run
|
|
169
248
|
if (this.quiet) {
|
|
170
249
|
return;
|
|
171
250
|
}
|
|
@@ -181,7 +260,7 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
181
260
|
\x1b[48;5;0m \x1b[48;5;14m \x1b[38;5;30;48;5;38m▄\x1b[38;5;14;48;5;14m▄\x1b[48;5;14m \x1b[38;5;45;48;5;14m▄\x1b[38;5;89;48;5;14m▄\x1b[38;5;89;48;5;89m▄\x1b[38;5;14;48;5;31m▄\x1b[48;5;14m \x1b[38;5;37;48;5;89m▄\x1b[48;5;198m \x1b[38;5;198;48;5;198m▄\x1b[38;5;31;48;5;14m▄\x1b[48;5;14m \x1b[48;5;0m \x1b[m \x1b[2mnode.js:\x1b[m \x1b[36m${run.environment.nodeVersion} \x1b[m
|
|
182
261
|
\x1b[48;5;0m \x1b[48;5;14m \x1b[38;5;44;48;5;31m▄\x1b[48;5;14m \x1b[38;5;126;48;5;38m▄\x1b[38;5;198;48;5;237m▄\x1b[38;5;237;48;5;37m▄\x1b[48;5;14m \x1b[38;5;14;48;5;14m▄\x1b[38;5;162;48;5;198m▄▄\x1b[38;5;53;48;5;240m▄\x1b[48;5;14m \x1b[48;5;0m \x1b[m \x1b[2mplatform:\x1b[m \x1b[36m${run.environment.platform} ${run.environment.arch} \x1b[m
|
|
183
262
|
\x1b[48;5;0m \x1b[38;5;45;48;5;14m▄\x1b[48;5;14m \x1b[38;5;14;48;5;37m▄\x1b[38;5;14;48;5;5m▄\x1b[38;5;14;48;5;44m▄\x1b[48;5;14m \x1b[38;5;45;48;5;14m▄\x1b[48;5;0m \x1b[m \x1b[2mcpu:\x1b[m \x1b[36m${run.environment.cpu.model} \x1b[2m(\x1b[m\x1b[36m${run.environment.cpu.cores} cores\x1b[2m) \x1b[m
|
|
184
|
-
\x1b[49;38;5;0m▀▀\x1b[38;5;0;48;5;6m▄\x1b[38;5;232;48;5;14m▄\x1b[38;5;38;48;5;14m▄\x1b[48;5;14m \x1b[38;5;30;48;5;14m▄\x1b[38;5;0;48;5;14m▄\x1b[38;5;0;48;5;23m▄\x1b[49;38;5;0m▀▀\x1b[m \x1b[2mmem:\x1b[m \x1b[36m${
|
|
263
|
+
\x1b[49;38;5;0m▀▀\x1b[38;5;0;48;5;6m▄\x1b[38;5;232;48;5;14m▄\x1b[38;5;38;48;5;14m▄\x1b[48;5;14m \x1b[38;5;30;48;5;14m▄\x1b[38;5;0;48;5;14m▄\x1b[38;5;0;48;5;23m▄\x1b[49;38;5;0m▀▀\x1b[m \x1b[2mmem:\x1b[m \x1b[36m${HumanReporter.formatBytes(run.environment.memory.total)} \x1b[m
|
|
185
264
|
\x1b[49m \x1b[49;38;5;0m▀\x1b[38;5;0;48;5;236m▄\x1b[38;5;0;48;5;45m▄\x1b[38;5;23;48;5;14m▄\x1b[48;5;14m \x1b[38;5;236;48;5;14m▄\x1b[38;5;0;48;5;44m▄\x1b[38;5;0;48;5;232m▄\x1b[49;38;5;0m▀\x1b[49m \x1b[m
|
|
186
265
|
\x1b[49m \x1b[49;38;5;0m▀▀\x1b[38;5;0;48;5;37m▄\x1b[38;5;0;48;5;14m▄\x1b[38;5;0;48;5;30m▄\x1b[49;38;5;0m▀▀\x1b[49m \x1b[m
|
|
187
266
|
`;
|
|
@@ -216,22 +295,53 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
216
295
|
if (this.quiet) {
|
|
217
296
|
return;
|
|
218
297
|
}
|
|
219
|
-
//
|
|
220
|
-
this.printAlignedSuiteResults();
|
|
298
|
+
// Tasks are printed immediately in onTaskResult, so just print suite summary
|
|
221
299
|
// Skip displaying summary for the implicit "default" suite
|
|
222
300
|
if (result.name === 'default') {
|
|
223
301
|
return;
|
|
224
302
|
}
|
|
225
|
-
const passed = result.tasks.filter((t) => !t.error).length;
|
|
303
|
+
const passed = result.tasks.filter((t) => !t.error && !t.aborted).length;
|
|
226
304
|
const failed = result.tasks.filter((t) => t.error).length;
|
|
305
|
+
const aborted = result.tasks.filter((t) => t.aborted).length;
|
|
306
|
+
const durationStr = reporter_registry_js_1.BaseReporter.formatDuration(result.duration * 1000000); // ms to ns
|
|
307
|
+
// Build summary parts
|
|
308
|
+
const parts = [];
|
|
227
309
|
if (failed > 0) {
|
|
228
|
-
|
|
310
|
+
parts.push(this.colorize('red', `${ansi_js_1.ansiChars.cross} ${failed} failed`));
|
|
311
|
+
}
|
|
312
|
+
if (passed > 0) {
|
|
313
|
+
parts.push(this.colorize('green', `${passed} passed`));
|
|
314
|
+
}
|
|
315
|
+
if (aborted > 0) {
|
|
316
|
+
parts.push(this.colorize('brightYellow', `${aborted} aborted`));
|
|
317
|
+
}
|
|
318
|
+
const summary = parts.join(', ');
|
|
319
|
+
const timeInfo = `${this.colorize('gray', 'in')} ${this.colorize('cyan', durationStr)}`;
|
|
320
|
+
if (failed > 0 || aborted > 0) {
|
|
321
|
+
this.printLine(` ${summary} ${timeInfo}`);
|
|
229
322
|
}
|
|
230
323
|
else {
|
|
231
|
-
this.printLine(` ${this.colorize('magenta', ansi_js_1.ansiChars.checkmark)} ${this.colorize('bold', this.colorize('brightWhite', `${passed}`))} ${this.colorize('brightWhite', `${
|
|
324
|
+
this.printLine(` ${this.colorize('magenta', ansi_js_1.ansiChars.checkmark)} ${this.colorize('bold', this.colorize('brightWhite', `${passed}`))} ${this.colorize('brightWhite', `${HumanReporter.pluralize('task', passed)} passed`)} ${timeInfo}`);
|
|
232
325
|
}
|
|
233
326
|
this.printLine();
|
|
234
327
|
}
|
|
328
|
+
onSuiteInit(suite, taskNames) {
|
|
329
|
+
// Pre-calculate max name length for optimal alignment
|
|
330
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
331
|
+
const STATS_RESERVED_WIDTH = 70;
|
|
332
|
+
const MAX_NAME_WIDTH = Math.max(40, Math.min(60, terminalWidth - 4 - 2 - 2 - STATS_RESERVED_WIDTH));
|
|
333
|
+
// Calculate the actual max name length from non-wrapped names
|
|
334
|
+
let maxLen = 0;
|
|
335
|
+
for (const name of taskNames) {
|
|
336
|
+
const nameLen = this.getVisibleLength(name.trim());
|
|
337
|
+
// Only count names that won't wrap
|
|
338
|
+
if (nameLen <= MAX_NAME_WIDTH) {
|
|
339
|
+
maxLen = Math.max(maxLen, nameLen);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// Use the max of actual names or MAX_NAME_WIDTH for consistency
|
|
343
|
+
this.currentSuiteMaxNameLen = Math.max(maxLen, MAX_NAME_WIDTH);
|
|
344
|
+
}
|
|
235
345
|
onSuiteStart(suite) {
|
|
236
346
|
this.currentSuite = suite;
|
|
237
347
|
if (this.quiet) {
|
|
@@ -250,8 +360,14 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
250
360
|
if (this.quiet) {
|
|
251
361
|
return;
|
|
252
362
|
}
|
|
253
|
-
//
|
|
363
|
+
// Always buffer the result for suite summary (including aborted tasks)
|
|
254
364
|
this.suiteResults.push(result);
|
|
365
|
+
// Skip printing aborted tasks (they're counted in summary but not shown individually)
|
|
366
|
+
if (result.aborted) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
// Print immediately with current alignment
|
|
370
|
+
this.printTaskResult(result);
|
|
255
371
|
}
|
|
256
372
|
onTaskStart(task) {
|
|
257
373
|
if (this.quiet) {
|
|
@@ -291,31 +407,6 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
291
407
|
}
|
|
292
408
|
return `${ansi_js_1.colors[color]}${text}${ansi_js_1.colors.reset}`;
|
|
293
409
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Format bytes in human-readable format
|
|
296
|
-
*/
|
|
297
|
-
formatBytes(bytes) {
|
|
298
|
-
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
299
|
-
let size = bytes;
|
|
300
|
-
let unitIndex = 0;
|
|
301
|
-
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
302
|
-
size /= 1024;
|
|
303
|
-
unitIndex++;
|
|
304
|
-
}
|
|
305
|
-
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Format file path - show relative path if within CWD, otherwise absolute
|
|
309
|
-
*/
|
|
310
|
-
formatPath(filePath) {
|
|
311
|
-
const cwd = process.cwd();
|
|
312
|
-
const absolutePath = node_path_1.default.resolve(filePath);
|
|
313
|
-
// Check if the file is within the current working directory
|
|
314
|
-
if (absolutePath.startsWith(cwd + node_path_1.default.sep) || absolutePath === cwd) {
|
|
315
|
-
return node_path_1.default.relative(cwd, absolutePath);
|
|
316
|
-
}
|
|
317
|
-
return absolutePath;
|
|
318
|
-
}
|
|
319
410
|
/**
|
|
320
411
|
* Format duration in human-readable format for progress display
|
|
321
412
|
*/
|
|
@@ -342,12 +433,6 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
342
433
|
// eslint-disable-next-line no-control-regex
|
|
343
434
|
return str.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
344
435
|
}
|
|
345
|
-
/**
|
|
346
|
-
* Simple pluralization helper
|
|
347
|
-
*/
|
|
348
|
-
pluralize(str, count) {
|
|
349
|
-
return count === 1 ? str : `${str}s`;
|
|
350
|
-
}
|
|
351
436
|
/**
|
|
352
437
|
* Print all task results in a suite with aligned columns
|
|
353
438
|
*/
|
|
@@ -355,10 +440,17 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
355
440
|
if (this.suiteResults.length === 0) {
|
|
356
441
|
return;
|
|
357
442
|
}
|
|
358
|
-
const MAX_NAME_WIDTH = 60;
|
|
359
443
|
const BASE_INDENT = ' '; // 4 spaces
|
|
360
444
|
const bullet = this.colorize('dim', this.colorize('gray', ansi_js_1.ansiChars.bullet));
|
|
361
|
-
|
|
445
|
+
// Calculate maximum name width based on terminal width
|
|
446
|
+
// Reserve space for: indent (4) + status (1) + space (1) + name + ": " (2) + stats (~60 chars)
|
|
447
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
448
|
+
const STATS_RESERVED_WIDTH = 70; // Approx space for duration + rme + ops/sec with padding
|
|
449
|
+
const MAX_NAME_WIDTH = Math.max(40, Math.min(60, terminalWidth - BASE_INDENT.length - 2 - 2 - STATS_RESERVED_WIDTH));
|
|
450
|
+
// Filter out aborted tasks (they're counted in suite summary but not printed)
|
|
451
|
+
const formatted = this.suiteResults
|
|
452
|
+
.filter((result) => !result.aborted)
|
|
453
|
+
.map((result) => {
|
|
362
454
|
const status = result.error
|
|
363
455
|
? this.colorize('red', ansi_js_1.ansiChars.cross)
|
|
364
456
|
: this.colorize('brightCyan', ansi_js_1.ansiChars.checkmark);
|
|
@@ -380,9 +472,9 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
380
472
|
status,
|
|
381
473
|
};
|
|
382
474
|
}
|
|
383
|
-
const duration =
|
|
384
|
-
const opsPerSec =
|
|
385
|
-
const rme =
|
|
475
|
+
const duration = reporter_registry_js_1.BaseReporter.formatDuration(result.mean); // already in nanoseconds
|
|
476
|
+
const opsPerSec = reporter_registry_js_1.BaseReporter.formatOpsPerSecond(result.opsPerSecond);
|
|
477
|
+
const rme = reporter_registry_js_1.BaseReporter.formatPercentage(result.marginOfError); // already a percentage
|
|
386
478
|
return {
|
|
387
479
|
durationLen: this.getVisibleLength(duration),
|
|
388
480
|
durationStr: duration,
|
|
@@ -405,9 +497,6 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
405
497
|
const maxDurationLen = Math.max(...formatted.filter((t) => !t.error).map((t) => t.durationLen), 0);
|
|
406
498
|
const maxRmeLen = Math.max(...formatted.filter((t) => !t.error).map((t) => t.rmeLen), 0);
|
|
407
499
|
const maxOpsLen = Math.max(...formatted.filter((t) => !t.error).map((t) => t.opsPerSecLen), 0);
|
|
408
|
-
// Calculate the position where numbers start for unwrapped lines
|
|
409
|
-
// BASE_INDENT (4) + status (1 char) + space (1) + maxNameLen + ": " (2) = 8 + maxNameLen
|
|
410
|
-
const numbersStartPos = BASE_INDENT.length + 2 + maxNameLen + 2;
|
|
411
500
|
// Print each task with aligned columns
|
|
412
501
|
for (const task of formatted) {
|
|
413
502
|
if (task.error) {
|
|
@@ -421,15 +510,33 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
421
510
|
this.printLine(`${BASE_INDENT}${task.status} ${this.colorize('white', task.name)} ${this.colorize('red', 'FAILED')}`);
|
|
422
511
|
}
|
|
423
512
|
else if (task.nameLength > MAX_NAME_WIDTH) {
|
|
424
|
-
// Long name - wrap to
|
|
425
|
-
this.
|
|
426
|
-
|
|
427
|
-
//
|
|
428
|
-
const leadingPad = ' '.repeat(numbersStartPos);
|
|
513
|
+
// Long name - wrap to multiple lines, align last line with short names
|
|
514
|
+
const wrappedLines = this.wrapText(task.name, MAX_NAME_WIDTH);
|
|
515
|
+
const continueIndent = BASE_INDENT + ' '; // 6 spaces for continuation lines
|
|
516
|
+
// Format stats string
|
|
429
517
|
const durationPad = ' '.repeat(maxDurationLen - task.durationLen);
|
|
430
518
|
const rmePad = ' '.repeat(maxRmeLen - task.rmeLen);
|
|
431
519
|
const opsPad = ' '.repeat(maxOpsLen - task.opsPerSecLen);
|
|
432
|
-
|
|
520
|
+
const statsStr = `${durationPad}${this.colorize('cyan', task.durationStr)} ${bullet} ${ansi_js_1.ansiChars.plusMinus}${rmePad}${this.colorize('brightBlue', task.rmeStr)} ${bullet} ${opsPad}${this.colorize('magenta', task.opsPerSecStr)}`;
|
|
521
|
+
// Print first line with status
|
|
522
|
+
this.printLine(`${BASE_INDENT}${task.status} ${this.colorize('white', wrappedLines[0])}`);
|
|
523
|
+
// Print middle continuation lines (all but first and last)
|
|
524
|
+
for (let i = 1; i < wrappedLines.length - 1; i++) {
|
|
525
|
+
this.printLine(`${continueIndent}${this.colorize('white', wrappedLines[i])}`);
|
|
526
|
+
}
|
|
527
|
+
// Print last line with colon and stats aligned with short names
|
|
528
|
+
if (wrappedLines.length > 1) {
|
|
529
|
+
const lastLine = wrappedLines[wrappedLines.length - 1];
|
|
530
|
+
const lastLineLen = this.getVisibleLength(lastLine);
|
|
531
|
+
// Pad the last line to align the ':' with short names
|
|
532
|
+
const lastLinePad = ' '.repeat(Math.max(0, maxNameLen - lastLineLen));
|
|
533
|
+
this.printLine(`${continueIndent}${this.colorize('white', lastLine)}${lastLinePad}: ${statsStr}`);
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
// Single wrapped line
|
|
537
|
+
const lastLinePad = ' '.repeat(maxNameLen - task.nameLength);
|
|
538
|
+
this.printLine(`${BASE_INDENT}${task.status} ${this.colorize('white', task.name)}${lastLinePad}: ${statsStr}`);
|
|
539
|
+
}
|
|
433
540
|
if (this.verbose && task.iterations > 0) {
|
|
434
541
|
this.printLine(` ${this.colorize('dim', `${task.iterations} iterations`)}`);
|
|
435
542
|
}
|
|
@@ -457,6 +564,84 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
457
564
|
console.log(message);
|
|
458
565
|
this.renderProgressWindow();
|
|
459
566
|
}
|
|
567
|
+
/**
|
|
568
|
+
* Print a single task result immediately with current alignment
|
|
569
|
+
*/
|
|
570
|
+
printTaskResult(result) {
|
|
571
|
+
// Clear progress bar temporarily
|
|
572
|
+
this.clearProgress();
|
|
573
|
+
const BASE_INDENT = ' '; // 4 spaces
|
|
574
|
+
const bullet = this.colorize('dim', this.colorize('gray', ansi_js_1.ansiChars.bullet));
|
|
575
|
+
// Calculate terminal width constraints
|
|
576
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
577
|
+
const STATS_RESERVED_WIDTH = 70;
|
|
578
|
+
const MAX_NAME_WIDTH = Math.max(40, Math.min(60, terminalWidth - BASE_INDENT.length - 2 - 2 - STATS_RESERVED_WIDTH));
|
|
579
|
+
// Status marker
|
|
580
|
+
const status = result.error
|
|
581
|
+
? this.colorize('red', ansi_js_1.ansiChars.cross)
|
|
582
|
+
: this.colorize('brightCyan', ansi_js_1.ansiChars.checkmark);
|
|
583
|
+
const name = result.name.trim();
|
|
584
|
+
const nameLength = this.getVisibleLength(name);
|
|
585
|
+
// Handle errors
|
|
586
|
+
if (result.error) {
|
|
587
|
+
this.failures.push({
|
|
588
|
+
error: result.error?.message || String(result.error),
|
|
589
|
+
file: this.currentFile,
|
|
590
|
+
suite: this.currentSuite,
|
|
591
|
+
task: name,
|
|
592
|
+
});
|
|
593
|
+
this.printLine(`${BASE_INDENT}${status} ${this.colorize('white', name)} ${this.colorize('red', 'FAILED')}`);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
// Format stats
|
|
597
|
+
const duration = reporter_registry_js_1.BaseReporter.formatDuration(result.mean);
|
|
598
|
+
const opsPerSec = reporter_registry_js_1.BaseReporter.formatOpsPerSecond(result.opsPerSecond);
|
|
599
|
+
const rme = reporter_registry_js_1.BaseReporter.formatPercentage(result.marginOfError);
|
|
600
|
+
// Use fixed widths for stats columns (reasonable maximums)
|
|
601
|
+
const DURATION_WIDTH = 10; // "999.99ms" max
|
|
602
|
+
const RME_WIDTH = 8; // "±999.99%" max
|
|
603
|
+
const OPS_WIDTH = 15; // "999.99K ops/sec" max
|
|
604
|
+
const durationLen = this.getVisibleLength(duration);
|
|
605
|
+
const rmeLen = this.getVisibleLength(rme);
|
|
606
|
+
const opsLen = this.getVisibleLength(opsPerSec);
|
|
607
|
+
// Stats formatting with fixed widths
|
|
608
|
+
const durationPad = ' '.repeat(DURATION_WIDTH - durationLen);
|
|
609
|
+
const rmePad = ' '.repeat(RME_WIDTH - rmeLen);
|
|
610
|
+
const opsPad = ' '.repeat(OPS_WIDTH - opsLen);
|
|
611
|
+
const statsStr = `${durationPad}${this.colorize('cyan', duration)} ${bullet} ${ansi_js_1.ansiChars.plusMinus}${rmePad}${this.colorize('brightBlue', rme)} ${bullet} ${opsPad}${this.colorize('magenta', opsPerSec)}`;
|
|
612
|
+
// Handle long names (wrap)
|
|
613
|
+
if (nameLength > MAX_NAME_WIDTH) {
|
|
614
|
+
const wrappedLines = this.wrapText(name, MAX_NAME_WIDTH);
|
|
615
|
+
const continueIndent = BASE_INDENT + ' '; // 6 spaces for continuation lines
|
|
616
|
+
// Print first line with status
|
|
617
|
+
this.printLine(`${BASE_INDENT}${status} ${this.colorize('white', wrappedLines[0])}`);
|
|
618
|
+
// Print middle lines (all but first and last)
|
|
619
|
+
for (let i = 1; i < wrappedLines.length - 1; i++) {
|
|
620
|
+
this.printLine(`${continueIndent}${this.colorize('white', wrappedLines[i])}`);
|
|
621
|
+
}
|
|
622
|
+
// Print last line with colon and stats aligned
|
|
623
|
+
// Use pre-calculated currentSuiteMaxNameLen for perfect alignment
|
|
624
|
+
if (wrappedLines.length > 1) {
|
|
625
|
+
const lastLine = wrappedLines[wrappedLines.length - 1];
|
|
626
|
+
const lastLineLen = this.getVisibleLength(lastLine);
|
|
627
|
+
const lastLinePad = ' '.repeat(Math.max(0, this.currentSuiteMaxNameLen - lastLineLen));
|
|
628
|
+
this.printLine(`${continueIndent}${this.colorize('white', lastLine)}${lastLinePad}: ${statsStr}`);
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
// Single wrapped line (shouldn't happen if nameLength > MAX but handle it)
|
|
632
|
+
const lastLinePad = ' '.repeat(Math.max(0, this.currentSuiteMaxNameLen - nameLength));
|
|
633
|
+
this.printLine(`${BASE_INDENT}${status} ${this.colorize('white', name)}${lastLinePad}: ${statsStr}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
// Normal length - print on same line with pre-calculated alignment
|
|
638
|
+
const namePad = ' '.repeat(Math.max(0, this.currentSuiteMaxNameLen - nameLength));
|
|
639
|
+
this.printLine(`${BASE_INDENT}${status} ${this.colorize('white', name)}${namePad}: ${statsStr}`);
|
|
640
|
+
}
|
|
641
|
+
if (this.verbose && result.iterations > 0) {
|
|
642
|
+
this.printLine(` ${this.colorize('dim', `${result.iterations} iterations`)}`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
460
645
|
/**
|
|
461
646
|
* Render the progress window at the bottom
|
|
462
647
|
*/
|
|
@@ -473,6 +658,44 @@ class HumanReporter extends reporter_registry_js_1.BaseReporter {
|
|
|
473
658
|
console.log(this.lastProgressLine);
|
|
474
659
|
this.progressWindowActive = true;
|
|
475
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* Wrap text to a maximum width, breaking at word boundaries when possible
|
|
663
|
+
*/
|
|
664
|
+
wrapText(text, maxWidth) {
|
|
665
|
+
if (this.getVisibleLength(text) <= maxWidth) {
|
|
666
|
+
return [text];
|
|
667
|
+
}
|
|
668
|
+
const lines = [];
|
|
669
|
+
let currentLine = '';
|
|
670
|
+
const words = text.split(/(\s+)/); // Keep whitespace in split
|
|
671
|
+
for (const word of words) {
|
|
672
|
+
const testLine = currentLine + word;
|
|
673
|
+
if (this.getVisibleLength(testLine) <= maxWidth) {
|
|
674
|
+
currentLine = testLine;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
// If current line has content, save it
|
|
678
|
+
if (currentLine.trim()) {
|
|
679
|
+
lines.push(currentLine.trimEnd());
|
|
680
|
+
currentLine = word.trim() + ' ';
|
|
681
|
+
}
|
|
682
|
+
else {
|
|
683
|
+
// Single word is too long, force break it
|
|
684
|
+
if (this.getVisibleLength(word) > maxWidth) {
|
|
685
|
+
lines.push(word.substring(0, maxWidth));
|
|
686
|
+
currentLine = word.substring(maxWidth);
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
currentLine = word;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
if (currentLine.trim()) {
|
|
695
|
+
lines.push(currentLine.trimEnd());
|
|
696
|
+
}
|
|
697
|
+
return lines;
|
|
698
|
+
}
|
|
476
699
|
}
|
|
477
700
|
exports.HumanReporter = HumanReporter;
|
|
478
701
|
//# sourceMappingURL=human.js.map
|