headlamp 0.1.9 → 0.1.11
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/README.md +32 -0
- package/dist/cli.cjs +1904 -714
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +1969 -809
- package/dist/index.js.map +4 -4
- package/package.json +3 -2
package/dist/cli.cjs
CHANGED
|
@@ -93,7 +93,7 @@ var init_TimeoutError = __esm({
|
|
|
93
93
|
|
|
94
94
|
// node_modules/es-toolkit/dist/promise/delay.mjs
|
|
95
95
|
function delay(ms, { signal } = {}) {
|
|
96
|
-
return new Promise((
|
|
96
|
+
return new Promise((resolve10, reject) => {
|
|
97
97
|
const abortError = () => {
|
|
98
98
|
reject(new AbortError());
|
|
99
99
|
};
|
|
@@ -106,7 +106,7 @@ function delay(ms, { signal } = {}) {
|
|
|
106
106
|
}
|
|
107
107
|
const timeoutId = setTimeout(() => {
|
|
108
108
|
signal?.removeEventListener("abort", abortHandler);
|
|
109
|
-
|
|
109
|
+
resolve10();
|
|
110
110
|
}, ms);
|
|
111
111
|
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
112
112
|
});
|
|
@@ -171,11 +171,11 @@ var init_exec = __esm({
|
|
|
171
171
|
child.stderr?.on("data", (chunk) => {
|
|
172
172
|
stderr += String(chunk);
|
|
173
173
|
});
|
|
174
|
-
const exec = new Promise((
|
|
174
|
+
const exec = new Promise((resolve10, reject) => {
|
|
175
175
|
child.on("error", reject);
|
|
176
176
|
child.on(
|
|
177
177
|
"close",
|
|
178
|
-
(code) => Number(code) === 0 ?
|
|
178
|
+
(code) => Number(code) === 0 ? resolve10(stdout) : reject(new Error(stderr || `exit ${code}`))
|
|
179
179
|
);
|
|
180
180
|
});
|
|
181
181
|
try {
|
|
@@ -195,7 +195,7 @@ var init_exec = __esm({
|
|
|
195
195
|
throw caughtError;
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
|
-
runExitCode = async (cmd, args, opts = {}) => new Promise((
|
|
198
|
+
runExitCode = async (cmd, args, opts = {}) => new Promise((resolve10, reject) => {
|
|
199
199
|
const child = (0, import_node_child_process.spawn)(cmd, [...args], {
|
|
200
200
|
cwd: opts.cwd,
|
|
201
201
|
env: opts.env,
|
|
@@ -204,9 +204,9 @@ var init_exec = __esm({
|
|
|
204
204
|
windowsHide: true
|
|
205
205
|
});
|
|
206
206
|
child.on("error", reject);
|
|
207
|
-
child.on("close", (code) =>
|
|
207
|
+
child.on("close", (code) => resolve10(Number(code)));
|
|
208
208
|
});
|
|
209
|
-
runWithCapture = async (cmd, args, opts) => new Promise((
|
|
209
|
+
runWithCapture = async (cmd, args, opts) => new Promise((resolve10, reject) => {
|
|
210
210
|
const child = (0, import_node_child_process.spawn)(cmd, [...args], {
|
|
211
211
|
cwd: opts.cwd,
|
|
212
212
|
env: opts.env,
|
|
@@ -222,7 +222,7 @@ var init_exec = __esm({
|
|
|
222
222
|
buf += String(chunk);
|
|
223
223
|
});
|
|
224
224
|
child.on("error", reject);
|
|
225
|
-
child.on("close", (code) =>
|
|
225
|
+
child.on("close", (code) => resolve10({ code: Number(code), output: buf }));
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
});
|
|
@@ -272,7 +272,7 @@ var init_args = __esm({
|
|
|
272
272
|
isSome = (opt) => opt._tag === "some";
|
|
273
273
|
step = (actions, skipNext = false) => [actions, skipNext];
|
|
274
274
|
rule = {
|
|
275
|
-
when: (predicate, build) => (value,
|
|
275
|
+
when: (predicate, build) => (value, env) => predicate(value, env) ? Some(build(value, env)) : None,
|
|
276
276
|
eq: (flag, build) => rule.when(
|
|
277
277
|
(value) => value === flag,
|
|
278
278
|
() => build()
|
|
@@ -282,12 +282,12 @@ var init_args = __esm({
|
|
|
282
282
|
(value) => build(value)
|
|
283
283
|
),
|
|
284
284
|
inSet: (select, build) => rule.when(
|
|
285
|
-
(value,
|
|
285
|
+
(value, env) => select(env).has(value),
|
|
286
286
|
(value) => build(value)
|
|
287
287
|
),
|
|
288
288
|
withLookahead: (lookaheadFlag, build) => rule.when(
|
|
289
|
-
(value,
|
|
290
|
-
(value,
|
|
289
|
+
(value, env) => value === lookaheadFlag && typeof env.lookahead === "string" && env.lookahead.length > 0,
|
|
290
|
+
(value, env) => build(value, env.lookahead)
|
|
291
291
|
)
|
|
292
292
|
};
|
|
293
293
|
STRING_EMPTY = "";
|
|
@@ -420,7 +420,7 @@ var init_args = __esm({
|
|
|
420
420
|
),
|
|
421
421
|
rule.startsWith("--testPathPattern=", (value) => step([ActionBuilders.jestArg(value)])),
|
|
422
422
|
rule.inSet(
|
|
423
|
-
(
|
|
423
|
+
(env) => env.jestFlags,
|
|
424
424
|
(value) => step([ActionBuilders.jestArg(value)])
|
|
425
425
|
),
|
|
426
426
|
rule.when(
|
|
@@ -478,12 +478,12 @@ var init_args = __esm({
|
|
|
478
478
|
rule.eq("--changed", () => step([ActionBuilders.changed("all")])),
|
|
479
479
|
rule.startsWith("--changed=", (value) => {
|
|
480
480
|
const raw = (value.split("=")[1] ?? "").trim().toLowerCase();
|
|
481
|
-
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
|
|
481
|
+
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : raw === "branch" ? "branch" : "all";
|
|
482
482
|
return step([ActionBuilders.changed(mode)]);
|
|
483
483
|
}),
|
|
484
484
|
rule.withLookahead("--changed", (_flag, lookahead) => {
|
|
485
485
|
const raw = String(lookahead).trim().toLowerCase();
|
|
486
|
-
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
|
|
486
|
+
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : raw === "branch" ? "branch" : "all";
|
|
487
487
|
return step([ActionBuilders.changed(mode)], true);
|
|
488
488
|
}),
|
|
489
489
|
rule.withLookahead(
|
|
@@ -516,9 +516,9 @@ var init_args = __esm({
|
|
|
516
516
|
}
|
|
517
517
|
const tokenValue = token ?? STRING_EMPTY;
|
|
518
518
|
const nextToken = tokens[index + INDEX_STEP];
|
|
519
|
-
let
|
|
519
|
+
let env = { jestFlags: jestOnlyFlags };
|
|
520
520
|
if (typeof nextToken === "string" && nextToken.length > 0) {
|
|
521
|
-
|
|
521
|
+
env = { jestFlags: jestOnlyFlags, lookahead: nextToken };
|
|
522
522
|
}
|
|
523
523
|
const firstMatch = (rs, value, envForRules) => {
|
|
524
524
|
for (const ruleFn of rs) {
|
|
@@ -529,7 +529,7 @@ var init_args = __esm({
|
|
|
529
529
|
}
|
|
530
530
|
return None;
|
|
531
531
|
};
|
|
532
|
-
const matched = firstMatch(rules, tokenValue,
|
|
532
|
+
const matched = firstMatch(rules, tokenValue, env);
|
|
533
533
|
const isTestFileToken = (candidate) => /\.(test|spec)\.[tj]sx?$/.test(candidate) || /(^|\/)tests?\//.test(candidate);
|
|
534
534
|
const isPathLike = (candidate) => /[\\/]/.test(candidate) || /\.(m?[tj]sx?)$/i.test(candidate);
|
|
535
535
|
const [matchedActions, shouldSkipNext] = isSome(matched) ? matched.value : (() => {
|
|
@@ -1987,19 +1987,19 @@ var require_lib = __commonJS({
|
|
|
1987
1987
|
"node_modules/json5/lib/index.js"(exports2, module2) {
|
|
1988
1988
|
var parse = require_parse();
|
|
1989
1989
|
var stringify = require_stringify();
|
|
1990
|
-
var
|
|
1990
|
+
var JSON53 = {
|
|
1991
1991
|
parse,
|
|
1992
1992
|
stringify
|
|
1993
1993
|
};
|
|
1994
|
-
module2.exports =
|
|
1994
|
+
module2.exports = JSON53;
|
|
1995
1995
|
}
|
|
1996
1996
|
});
|
|
1997
1997
|
|
|
1998
1998
|
// src/lib/program.ts
|
|
1999
|
-
var
|
|
1999
|
+
var path11 = __toESM(require("node:path"), 1);
|
|
2000
2000
|
var os2 = __toESM(require("node:os"), 1);
|
|
2001
2001
|
var fsSync3 = __toESM(require("node:fs"), 1);
|
|
2002
|
-
var
|
|
2002
|
+
var fs7 = __toESM(require("node:fs/promises"), 1);
|
|
2003
2003
|
var LibReport = __toESM(require("istanbul-lib-report"), 1);
|
|
2004
2004
|
var Reports = __toESM(require("istanbul-reports"), 1);
|
|
2005
2005
|
var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
|
|
@@ -3370,7 +3370,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3370
3370
|
);
|
|
3371
3371
|
}
|
|
3372
3372
|
};
|
|
3373
|
-
var shortenPathPreservingFilename = (
|
|
3373
|
+
var shortenPathPreservingFilename = (relPath2, maxWidth, opts) => {
|
|
3374
3374
|
const ellipsis = opts?.ellipsis ?? "\u2026";
|
|
3375
3375
|
const START_HEAD = Math.max(0, opts?.keepHead ?? 1);
|
|
3376
3376
|
const START_TAIL = Math.max(0, opts?.keepTail ?? 1);
|
|
@@ -3542,7 +3542,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3542
3542
|
}
|
|
3543
3543
|
return null;
|
|
3544
3544
|
};
|
|
3545
|
-
const normalized =
|
|
3545
|
+
const normalized = relPath2.replace(/\\/g, "/");
|
|
3546
3546
|
if (visibleWidth(normalized) <= maxWidth) {
|
|
3547
3547
|
return normalized;
|
|
3548
3548
|
}
|
|
@@ -3998,11 +3998,343 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3998
3998
|
}
|
|
3999
3999
|
};
|
|
4000
4000
|
|
|
4001
|
-
// src/lib/jest-
|
|
4002
|
-
var
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4001
|
+
// src/lib/jest-reporter-source.ts
|
|
4002
|
+
var JEST_BRIDGE_REPORTER_SOURCE = `const fs = require('fs');
|
|
4003
|
+
const path = require('path');
|
|
4004
|
+
|
|
4005
|
+
const isObject = (v) => typeof v === 'object' && v !== null;
|
|
4006
|
+
const sanitizeError = (err) => {
|
|
4007
|
+
if (!isObject(err)) return err;
|
|
4008
|
+
const out = {};
|
|
4009
|
+
const name = err.name || (err.constructor && err.constructor.name) || undefined;
|
|
4010
|
+
if (name) out.name = String(name);
|
|
4011
|
+
if (typeof err.message === 'string') out.message = err.message;
|
|
4012
|
+
if (typeof err.stack === 'string') out.stack = err.stack;
|
|
4013
|
+
if (err.code !== undefined) out.code = err.code;
|
|
4014
|
+
if (err.expected !== undefined) out.expected = err.expected;
|
|
4015
|
+
if (err.received !== undefined) out.received = err.received;
|
|
4016
|
+
if (err.matcherResult && isObject(err.matcherResult)) {
|
|
4017
|
+
const mr = err.matcherResult;
|
|
4018
|
+
let messageText;
|
|
4019
|
+
try {
|
|
4020
|
+
messageText = typeof mr.message === 'function' ? String(mr.message()) : (typeof mr.message === 'string' ? mr.message : undefined);
|
|
4021
|
+
} catch {}
|
|
4022
|
+
out.matcherResult = {
|
|
4023
|
+
matcherName: typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
|
|
4024
|
+
message: messageText,
|
|
4025
|
+
stack: typeof mr.stack === 'string' ? mr.stack : undefined,
|
|
4026
|
+
expected: mr.expected,
|
|
4027
|
+
received: mr.received,
|
|
4028
|
+
actual: mr.actual,
|
|
4029
|
+
pass: typeof mr.pass === 'boolean' ? mr.pass : undefined,
|
|
4030
|
+
};
|
|
4031
|
+
}
|
|
4032
|
+
if (err.cause) {
|
|
4033
|
+
out.cause = sanitizeError(err.cause);
|
|
4034
|
+
}
|
|
4035
|
+
// Copy own enumerable props to preserve custom data
|
|
4036
|
+
try {
|
|
4037
|
+
for (const key of Object.keys(err)) {
|
|
4038
|
+
if (!(key in out)) out[key] = err[key];
|
|
4039
|
+
}
|
|
4040
|
+
} catch {}
|
|
4041
|
+
return out;
|
|
4042
|
+
};
|
|
4043
|
+
const sanitizeDetail = (d) => {
|
|
4044
|
+
if (typeof d === 'string') return d;
|
|
4045
|
+
if (!isObject(d)) return d;
|
|
4046
|
+
// Common Jest detail shapes
|
|
4047
|
+
const out = {};
|
|
4048
|
+
if (d.message) out.message = d.message;
|
|
4049
|
+
if (d.stack) out.stack = d.stack;
|
|
4050
|
+
if (d.error) out.error = sanitizeError(d.error);
|
|
4051
|
+
if (d.matcherResult) out.matcherResult = sanitizeError({ matcherResult: d.matcherResult }).matcherResult;
|
|
4052
|
+
if (d.expected !== undefined) out.expected = d.expected;
|
|
4053
|
+
if (d.received !== undefined) out.received = d.received;
|
|
4054
|
+
// Copy the rest
|
|
4055
|
+
try {
|
|
4056
|
+
for (const key of Object.keys(d)) {
|
|
4057
|
+
if (!(key in out)) out[key] = d[key];
|
|
4058
|
+
}
|
|
4059
|
+
} catch {}
|
|
4060
|
+
return out;
|
|
4061
|
+
};
|
|
4062
|
+
|
|
4063
|
+
class BridgeReporter {
|
|
4064
|
+
constructor(globalConfig, options) {
|
|
4065
|
+
this.out = process.env.JEST_BRIDGE_OUT || (options && options.outFile) || path.join(process.cwd(), 'coverage', 'jest-run.json');
|
|
4066
|
+
this.buf = { startTime: Date.now(), testResults: [], aggregated: null };
|
|
4067
|
+
}
|
|
4068
|
+
onRunStart() { this.buf.startTime = Date.now(); }
|
|
4069
|
+
onTestResult(_test, tr) {
|
|
4070
|
+
const mapAssertion = (a) => ({
|
|
4071
|
+
title: a.title,
|
|
4072
|
+
fullName: a.fullName || [...(a.ancestorTitles || []), a.title].join(' '),
|
|
4073
|
+
status: a.status,
|
|
4074
|
+
duration: a.duration || 0,
|
|
4075
|
+
location: a.location || null,
|
|
4076
|
+
failureMessages: (a.failureMessages || []).map(String),
|
|
4077
|
+
failureDetails: (a.failureDetails || []).map(sanitizeDetail),
|
|
4078
|
+
});
|
|
4079
|
+
this.buf.testResults.push({
|
|
4080
|
+
testFilePath: tr.testFilePath,
|
|
4081
|
+
status: tr.numFailingTests ? 'failed' : 'passed',
|
|
4082
|
+
failureMessage: tr.failureMessage || '',
|
|
4083
|
+
failureDetails: (tr.failureDetails || []).map(sanitizeDetail),
|
|
4084
|
+
testExecError: tr.testExecError ? sanitizeError(tr.testExecError) : null,
|
|
4085
|
+
console: tr.console || null,
|
|
4086
|
+
perfStats: tr.perfStats || {},
|
|
4087
|
+
testResults: (tr.testResults || []).map(mapAssertion),
|
|
4088
|
+
});
|
|
4089
|
+
}
|
|
4090
|
+
onRunComplete(_contexts, agg) {
|
|
4091
|
+
this.buf.aggregated = {
|
|
4092
|
+
numTotalTestSuites: agg.numTotalTestSuites,
|
|
4093
|
+
numPassedTestSuites: agg.numPassedTestSuites,
|
|
4094
|
+
numFailedTestSuites: agg.numFailedTestSuites,
|
|
4095
|
+
numTotalTests: agg.numTotalTests,
|
|
4096
|
+
numPassedTests: agg.numPassedTests,
|
|
4097
|
+
numFailedTests: agg.numFailedTests,
|
|
4098
|
+
numPendingTests: agg.numPendingTests,
|
|
4099
|
+
numTodoTests: agg.numTodoTests,
|
|
4100
|
+
startTime: agg.startTime,
|
|
4101
|
+
success: agg.success,
|
|
4102
|
+
runTimeMs: agg.testResults.reduce((t, r) => t + Math.max(0, (r.perfStats?.end || 0) - (r.perfStats?.start || 0)), 0),
|
|
4103
|
+
};
|
|
4104
|
+
fs.mkdirSync(path.dirname(this.out), { recursive: true });
|
|
4105
|
+
fs.writeFileSync(this.out, JSON.stringify(this.buf), 'utf8');
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
module.exports = BridgeReporter;`;
|
|
4109
|
+
|
|
4110
|
+
// src/lib/jest-environment-source.ts
|
|
4111
|
+
var JEST_BRIDGE_ENV_SOURCE = `
|
|
4112
|
+
'use strict';
|
|
4113
|
+
|
|
4114
|
+
const NodeEnvironment = require('jest-environment-node').TestEnvironment || require('jest-environment-node');
|
|
4115
|
+
|
|
4116
|
+
module.exports = class BridgeEnv extends NodeEnvironment {
|
|
4117
|
+
constructor(config, context) {
|
|
4118
|
+
super(config, context);
|
|
4119
|
+
const { AsyncLocalStorage } = require('node:async_hooks');
|
|
4120
|
+
this._als = new AsyncLocalStorage();
|
|
4121
|
+
this._cleanup = [];
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
_ctx() {
|
|
4125
|
+
try { const s = this._als.getStore(); if (s) return s; } catch {}
|
|
4126
|
+
try {
|
|
4127
|
+
const st = this.global.expect && typeof this.global.expect.getState === 'function' ? this.global.expect.getState() : {};
|
|
4128
|
+
return { testPath: st.testPath, currentTestName: st.currentTestName };
|
|
4129
|
+
} catch { return {}; }
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
async setup() {
|
|
4133
|
+
await super.setup();
|
|
4134
|
+
|
|
4135
|
+
try { Error.stackTraceLimit = Math.max(Error.stackTraceLimit || 10, 50); } catch {}
|
|
4136
|
+
|
|
4137
|
+
const print = (payload) => { try { this.global.console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {} };
|
|
4138
|
+
const toErr = (x) => { try { return x instanceof Error ? x : new Error(String(x)); } catch { return new Error('unknown'); } };
|
|
4139
|
+
|
|
4140
|
+
const onRej = (reason) => {
|
|
4141
|
+
const e = toErr(reason);
|
|
4142
|
+
const c = this._ctx();
|
|
4143
|
+
print({ type: 'unhandledRejection', name: e.name, message: e.message, stack: e.stack, code: e.code ?? undefined, ...c });
|
|
4144
|
+
};
|
|
4145
|
+
const onExc = (error) => {
|
|
4146
|
+
const e = toErr(error);
|
|
4147
|
+
const c = this._ctx();
|
|
4148
|
+
print({ type: 'uncaughtException', name: e.name, message: e.message, stack: e.stack, code: e.code ?? undefined, ...c });
|
|
4149
|
+
};
|
|
4150
|
+
|
|
4151
|
+
this.global.process.on('unhandledRejection', onRej);
|
|
4152
|
+
this.global.process.on('uncaughtException', onExc);
|
|
4153
|
+
this._cleanup.push(() => {
|
|
4154
|
+
this.global.process.off('unhandledRejection', onRej);
|
|
4155
|
+
this.global.process.off('uncaughtException', onExc);
|
|
4156
|
+
});
|
|
4157
|
+
|
|
4158
|
+
// Signal environment readiness so we can confirm the custom env loaded
|
|
4159
|
+
try { const c = this._ctx(); print({ type: 'envReady', ...c }); } catch {}
|
|
4160
|
+
|
|
4161
|
+
try {
|
|
4162
|
+
const http = this.global.require ? this.global.require('http') : require('http');
|
|
4163
|
+
const originalEmit = http && http.Server && http.Server.prototype && http.Server.prototype.emit;
|
|
4164
|
+
if (originalEmit) {
|
|
4165
|
+
const MAX = 64 * 1024;
|
|
4166
|
+
const asString = (x) => { try { if (typeof x === 'string') return x; if (Buffer.isBuffer(x)) return x.toString('utf8'); return String(x); } catch { return ''; } };
|
|
4167
|
+
|
|
4168
|
+
const patched = function(eventName, req, res) {
|
|
4169
|
+
try {
|
|
4170
|
+
if (eventName === 'request' && req && res && typeof res.write === 'function' && typeof res.end === 'function') {
|
|
4171
|
+
const startAt = Date.now();
|
|
4172
|
+
const safeHeader = (k) => { try { return req && req.headers ? String((req.headers[k.toLowerCase()] ?? '')) : ''; } catch { return ''; } };
|
|
4173
|
+
const reqIdHeader = safeHeader('x-request-id');
|
|
4174
|
+
const chunks = [];
|
|
4175
|
+
const write = res.write.bind(res);
|
|
4176
|
+
const end = res.end.bind(res);
|
|
4177
|
+
const method = req.method ? String(req.method) : undefined;
|
|
4178
|
+
const url = (req.originalUrl || req.url) ? String(req.originalUrl || req.url) : undefined;
|
|
4179
|
+
|
|
4180
|
+
res.write = function(chunk, enc, cb) {
|
|
4181
|
+
try { const s = asString(chunk); if (s) chunks.push(s); } catch {}
|
|
4182
|
+
return write(chunk, enc, cb);
|
|
4183
|
+
};
|
|
4184
|
+
res.end = function(chunk, enc, cb) {
|
|
4185
|
+
try { const s = asString(chunk); if (s) chunks.push(s); } catch {}
|
|
4186
|
+
try {
|
|
4187
|
+
const preview = chunks.join('').slice(0, MAX);
|
|
4188
|
+
const statusCode = typeof res.statusCode === 'number' ? res.statusCode : undefined;
|
|
4189
|
+
const ct = (typeof res.getHeader === 'function' && res.getHeader('content-type')) || undefined;
|
|
4190
|
+
const routePath = (req && req.route && req.route.path) || (req && req.baseUrl && req.path ? (req.baseUrl + req.path) : undefined);
|
|
4191
|
+
const jsonParsed = (() => { try { return JSON.parse(preview); } catch { return undefined; } })();
|
|
4192
|
+
const requestId = reqIdHeader || (jsonParsed && typeof jsonParsed === 'object' ? (jsonParsed.requestId || jsonParsed.reqId || '') : '');
|
|
4193
|
+
const ctx = (global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx) ? global.__JEST_BRIDGE_ENV_REF._ctx() : {};
|
|
4194
|
+
const payload = {
|
|
4195
|
+
type: 'httpResponse',
|
|
4196
|
+
timestampMs: Date.now(),
|
|
4197
|
+
durationMs: Math.max(0, Date.now() - startAt),
|
|
4198
|
+
method, url, statusCode,
|
|
4199
|
+
route: routePath ? String(routePath) : undefined,
|
|
4200
|
+
contentType: ct ? String(ct) : undefined,
|
|
4201
|
+
headers: (typeof res.getHeaders === 'function') ? res.getHeaders() : undefined,
|
|
4202
|
+
requestId: requestId ? String(requestId) : undefined,
|
|
4203
|
+
bodyPreview: preview,
|
|
4204
|
+
json: jsonParsed,
|
|
4205
|
+
testPath: ctx.testPath, currentTestName: ctx.currentTestName,
|
|
4206
|
+
};
|
|
4207
|
+
try {
|
|
4208
|
+
if (!global.__JEST_HTTP_EVENTS__) global.__JEST_HTTP_EVENTS__ = [];
|
|
4209
|
+
const arr = global.__JEST_HTTP_EVENTS__;
|
|
4210
|
+
arr.push({ timestampMs: payload.timestampMs, durationMs: payload.durationMs, method: payload.method, url: payload.url, route: payload.route, statusCode: payload.statusCode, contentType: payload.contentType, requestId: payload.requestId, json: payload.json, bodyPreview: payload.bodyPreview });
|
|
4211
|
+
if (arr.length > 25) arr.splice(0, arr.length - 25);
|
|
4212
|
+
} catch {}
|
|
4213
|
+
try { console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
|
|
4214
|
+
} catch {}
|
|
4215
|
+
return end(chunk, enc, cb);
|
|
4216
|
+
};
|
|
4217
|
+
try {
|
|
4218
|
+
res.on('close', function onClose() {
|
|
4219
|
+
try {
|
|
4220
|
+
const ended = typeof res.writableEnded === 'boolean' ? res.writableEnded : false;
|
|
4221
|
+
if (!ended) {
|
|
4222
|
+
const routePath = (req && req.route && req.route.path) || (req && req.baseUrl && req.path ? (req.baseUrl + req.path) : undefined);
|
|
4223
|
+
const ctx = (global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx) ? global.__JEST_BRIDGE_ENV_REF._ctx() : {};
|
|
4224
|
+
const payload = {
|
|
4225
|
+
type: 'httpAbort',
|
|
4226
|
+
timestampMs: Date.now(),
|
|
4227
|
+
durationMs: Math.max(0, Date.now() - startAt),
|
|
4228
|
+
method, url,
|
|
4229
|
+
route: routePath ? String(routePath) : undefined,
|
|
4230
|
+
testPath: ctx.testPath, currentTestName: ctx.currentTestName,
|
|
4231
|
+
};
|
|
4232
|
+
try { console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
|
|
4233
|
+
}
|
|
4234
|
+
} catch {}
|
|
4235
|
+
});
|
|
4236
|
+
} catch {}
|
|
4237
|
+
}
|
|
4238
|
+
} catch {}
|
|
4239
|
+
return originalEmit.apply(this, arguments);
|
|
4240
|
+
};
|
|
4241
|
+
|
|
4242
|
+
try { this.global.__JEST_BRIDGE_ENV_REF = this; } catch {}
|
|
4243
|
+
http.Server.prototype.emit = patched;
|
|
4244
|
+
|
|
4245
|
+
this._cleanup.push(() => {
|
|
4246
|
+
try { if (http.Server && http.Server.prototype) http.Server.prototype.emit = originalEmit; } catch {}
|
|
4247
|
+
try { delete this.global.__JEST_BRIDGE_ENV_REF; } catch {}
|
|
4248
|
+
});
|
|
4249
|
+
}
|
|
4250
|
+
} catch {}
|
|
4251
|
+
|
|
4252
|
+
// Wrap test functions to emit rich assertion events on failures
|
|
4253
|
+
try {
|
|
4254
|
+
const g = this.global;
|
|
4255
|
+
const ctxFn = () => {
|
|
4256
|
+
try {
|
|
4257
|
+
const ref = g.__JEST_BRIDGE_ENV_REF;
|
|
4258
|
+
return ref && typeof ref._ctx === 'function' ? ref._ctx() : {};
|
|
4259
|
+
} catch { return {}; }
|
|
4260
|
+
};
|
|
4261
|
+
const emitAssertion = (err) => {
|
|
4262
|
+
try {
|
|
4263
|
+
const e = toErr(err);
|
|
4264
|
+
const mr = e && typeof e === 'object' && e.matcherResult ? e.matcherResult : undefined;
|
|
4265
|
+
const messageText = (() => { try { return mr && typeof mr.message === 'function' ? String(mr.message()) : (e.message || ''); } catch { return e.message || ''; } })();
|
|
4266
|
+
const expectedPreview = (() => { try { return mr && mr.expected !== undefined ? JSON.stringify(mr.expected, null, 2) : undefined; } catch { return undefined; } })();
|
|
4267
|
+
const actualPreview = (() => { try { return mr && mr.received !== undefined ? JSON.stringify(mr.received, null, 2) : undefined; } catch { return undefined; } })();
|
|
4268
|
+
const c = ctxFn();
|
|
4269
|
+
const expectedRaw = (() => { try { return mr?.expected; } catch { return undefined; } })();
|
|
4270
|
+
const receivedRaw = (() => { try { return mr?.received; } catch { return undefined; } })();
|
|
4271
|
+
print({
|
|
4272
|
+
type: 'assertionFailure',
|
|
4273
|
+
timestampMs: Date.now(),
|
|
4274
|
+
matcher: mr && typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
|
|
4275
|
+
expectedPreview,
|
|
4276
|
+
actualPreview,
|
|
4277
|
+
expectedNumber: typeof expectedRaw === 'number' ? expectedRaw : undefined,
|
|
4278
|
+
receivedNumber: typeof receivedRaw === 'number' ? receivedRaw : undefined,
|
|
4279
|
+
message: messageText,
|
|
4280
|
+
stack: e.stack,
|
|
4281
|
+
...c,
|
|
4282
|
+
});
|
|
4283
|
+
} catch {}
|
|
4284
|
+
};
|
|
4285
|
+
const wrap = (orig) => {
|
|
4286
|
+
if (!orig || typeof orig !== 'function') return orig;
|
|
4287
|
+
const wrapped = function(name, fn, timeout) {
|
|
4288
|
+
if (typeof fn !== 'function') return orig.call(this, name, fn, timeout);
|
|
4289
|
+
const run = function() {
|
|
4290
|
+
try {
|
|
4291
|
+
const res = fn.apply(this, arguments);
|
|
4292
|
+
if (res && typeof res.then === 'function') {
|
|
4293
|
+
return res.catch((err) => { emitAssertion(err); throw err; });
|
|
4294
|
+
}
|
|
4295
|
+
return res;
|
|
4296
|
+
} catch (err) {
|
|
4297
|
+
emitAssertion(err);
|
|
4298
|
+
throw err;
|
|
4299
|
+
}
|
|
4300
|
+
};
|
|
4301
|
+
return orig.call(this, name, run, timeout);
|
|
4302
|
+
};
|
|
4303
|
+
try { wrapped.only = orig.only && typeof orig.only === 'function' ? wrap(orig.only) : orig.only; } catch {}
|
|
4304
|
+
try { wrapped.skip = orig.skip && typeof orig.skip === 'function' ? wrap(orig.skip) : orig.skip; } catch {}
|
|
4305
|
+
return wrapped;
|
|
4306
|
+
};
|
|
4307
|
+
try { g.it = wrap(g.it); } catch {}
|
|
4308
|
+
try { g.test = wrap(g.test); } catch {}
|
|
4309
|
+
} catch {}
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4312
|
+
async handleTestEvent(evt, state) {
|
|
4313
|
+
if (evt.name === 'test_start') {
|
|
4314
|
+
const store = { testPath: state.testPath, currentTestName: evt.test.name };
|
|
4315
|
+
try { this._als.enterWith(store); } catch {}
|
|
4316
|
+
} else if (evt.name === 'test_done') {
|
|
4317
|
+
try { this._als.enterWith({}); } catch {}
|
|
4318
|
+
try {
|
|
4319
|
+
const events = Array.isArray(global.__JEST_HTTP_EVENTS__) ? global.__JEST_HTTP_EVENTS__ : [];
|
|
4320
|
+
if (events.length) {
|
|
4321
|
+
const batch = events.slice(-10);
|
|
4322
|
+
const payload = { type: 'httpResponseBatch', events: batch, testPath: state.testPath, currentTestName: evt.test.name };
|
|
4323
|
+
try { this.global.console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
|
|
4324
|
+
try { global.__JEST_HTTP_EVENTS__ = []; } catch {}
|
|
4325
|
+
}
|
|
4326
|
+
} catch {}
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
|
|
4330
|
+
async teardown() {
|
|
4331
|
+
for (let i = this._cleanup.length - 1; i >= 0; i--) {
|
|
4332
|
+
try { this._cleanup[i](); } catch {}
|
|
4333
|
+
}
|
|
4334
|
+
await super.teardown();
|
|
4335
|
+
}
|
|
4336
|
+
};
|
|
4337
|
+
`;
|
|
4006
4338
|
|
|
4007
4339
|
// src/lib/stacks.ts
|
|
4008
4340
|
var isStackLine = (line) => /\s+at\s+/.test(line);
|
|
@@ -4065,30 +4397,81 @@ var collapseStacks = (lines) => {
|
|
|
4065
4397
|
return out;
|
|
4066
4398
|
};
|
|
4067
4399
|
|
|
4068
|
-
// src/lib/
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4400
|
+
// src/lib/fp.ts
|
|
4401
|
+
function pipe(initial, ...fns) {
|
|
4402
|
+
return fns.reduce((acc, fn) => fn(acc), initial);
|
|
4403
|
+
}
|
|
4404
|
+
var some = (value) => ({ tag: "Some", value });
|
|
4405
|
+
var none = { tag: "None" };
|
|
4406
|
+
var unfoldr = (initial, step2) => {
|
|
4407
|
+
const out = [];
|
|
4408
|
+
for (let state = initial; ; ) {
|
|
4409
|
+
const result = step2(state);
|
|
4410
|
+
if (result.tag === "None") {
|
|
4411
|
+
break;
|
|
4412
|
+
}
|
|
4413
|
+
const [element, next] = result.value;
|
|
4414
|
+
out.push(element);
|
|
4415
|
+
state = next;
|
|
4075
4416
|
}
|
|
4076
|
-
|
|
4077
|
-
return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
|
|
4417
|
+
return out;
|
|
4078
4418
|
};
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4419
|
+
|
|
4420
|
+
// src/lib/formatter/parse.ts
|
|
4421
|
+
var isFailureStart = (lineText) => /^\s*●\s+/.test(lineText);
|
|
4422
|
+
var isSuiteLine = (lineText) => /^\s*(PASS|FAIL)\s+/.test(lineText);
|
|
4423
|
+
var isSummaryLine = (lineText) => /^\s*(Test Suites:|Tests:|Snapshots:|Time:|Ran all)/.test(lineText);
|
|
4424
|
+
var collectFailure = (allLines, startIndex) => {
|
|
4425
|
+
const title = stripAnsiSimple(allLines[startIndex]).replace(/^\s*●\s+/, "").trim();
|
|
4426
|
+
const buf = [allLines[startIndex]];
|
|
4427
|
+
let i = startIndex + 1;
|
|
4428
|
+
for (; i < allLines.length; i += 1) {
|
|
4429
|
+
const simple = stripAnsiSimple(allLines[i]);
|
|
4430
|
+
const nextIsStart = isFailureStart(simple) || isSuiteLine(simple) || isSummaryLine(simple);
|
|
4431
|
+
const prevBlank = stripAnsiSimple(allLines[i - 1] ?? "").trim() === "";
|
|
4432
|
+
if (nextIsStart && prevBlank) {
|
|
4433
|
+
break;
|
|
4434
|
+
}
|
|
4435
|
+
buf.push(allLines[i]);
|
|
4086
4436
|
}
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4437
|
+
return [{ tag: "FailureBlock", title, lines: buf }, i];
|
|
4438
|
+
};
|
|
4439
|
+
var parseSuite = (lineText) => {
|
|
4440
|
+
const match = lineText.match(/^\s*(PASS|FAIL)\s+(.+)$/);
|
|
4441
|
+
return { tag: "PassFail", badge: match[1], rel: match[2] };
|
|
4442
|
+
};
|
|
4443
|
+
var parseChunks = (raw) => {
|
|
4444
|
+
const lines = raw.split(/\r?\n/);
|
|
4445
|
+
return unfoldr({ index: 0 }, (state) => {
|
|
4446
|
+
if (state.index >= lines.length) {
|
|
4447
|
+
return none;
|
|
4448
|
+
}
|
|
4449
|
+
const line = lines[state.index];
|
|
4450
|
+
const simple = stripAnsiSimple(line);
|
|
4451
|
+
if (isFailureStart(simple)) {
|
|
4452
|
+
const [chunk, next] = collectFailure(lines, state.index);
|
|
4453
|
+
return some([chunk, { index: next }]);
|
|
4454
|
+
}
|
|
4455
|
+
if (isSuiteLine(simple)) {
|
|
4456
|
+
return some([parseSuite(simple), { index: state.index + 1 }]);
|
|
4457
|
+
}
|
|
4458
|
+
if (isSummaryLine(simple)) {
|
|
4459
|
+
return some([{ tag: "Summary", line }, { index: state.index + 1 }]);
|
|
4460
|
+
}
|
|
4461
|
+
if (isStackLine(simple)) {
|
|
4462
|
+
return some([{ tag: "Stack", line }, { index: state.index + 1 }]);
|
|
4463
|
+
}
|
|
4464
|
+
return some([{ tag: "Other", line }, { index: state.index + 1 }]);
|
|
4465
|
+
});
|
|
4090
4466
|
};
|
|
4091
|
-
|
|
4467
|
+
|
|
4468
|
+
// src/lib/formatter/render.ts
|
|
4469
|
+
var path9 = __toESM(require("node:path"), 1);
|
|
4470
|
+
|
|
4471
|
+
// src/lib/formatter/fns.ts
|
|
4472
|
+
var fs4 = __toESM(require("node:fs"), 1);
|
|
4473
|
+
var util = __toESM(require("node:util"), 1);
|
|
4474
|
+
var import_json5 = __toESM(require_lib(), 1);
|
|
4092
4475
|
var colorTokens = {
|
|
4093
4476
|
pass: Colors.Success,
|
|
4094
4477
|
fail: Colors.Failure,
|
|
@@ -4099,31 +4482,17 @@ var colorTokens = {
|
|
|
4099
4482
|
failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `)),
|
|
4100
4483
|
runPill: (text) => BackgroundColors.Run(ansi.white(` ${text} `))
|
|
4101
4484
|
};
|
|
4102
|
-
var
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
if (typeof value === "string") {
|
|
4110
|
-
const text = normalizeBlock(value.trim());
|
|
4111
|
-
if (/^[[{]/.test(text)) {
|
|
4112
|
-
try {
|
|
4113
|
-
const parsed = import_json5.default.parse(text);
|
|
4114
|
-
return JSON.stringify(parsed, null, 2);
|
|
4115
|
-
} catch {
|
|
4116
|
-
}
|
|
4117
|
-
}
|
|
4118
|
-
return value;
|
|
4119
|
-
}
|
|
4120
|
-
if (Array.isArray(value) || value && typeof value === "object") {
|
|
4121
|
-
try {
|
|
4122
|
-
return JSON.stringify(value, null, 2);
|
|
4123
|
-
} catch {
|
|
4124
|
-
}
|
|
4485
|
+
var drawRule = (label) => {
|
|
4486
|
+
const width = Math.max(
|
|
4487
|
+
40,
|
|
4488
|
+
process.stdout && process.stdout.columns || 80
|
|
4489
|
+
);
|
|
4490
|
+
if (!label) {
|
|
4491
|
+
return ansi.dim("\u2500".repeat(width));
|
|
4125
4492
|
}
|
|
4126
|
-
|
|
4493
|
+
const plain = stripAnsiSimple(label);
|
|
4494
|
+
const pad = Math.max(1, width - plain.length - 1);
|
|
4495
|
+
return `${ansi.dim("\u2500".repeat(pad))} ${label}`;
|
|
4127
4496
|
};
|
|
4128
4497
|
var drawFailLine = () => {
|
|
4129
4498
|
const width = Math.max(
|
|
@@ -4133,9 +4502,29 @@ var drawFailLine = () => {
|
|
|
4133
4502
|
return colorTokens.fail("\u2500".repeat(width));
|
|
4134
4503
|
};
|
|
4135
4504
|
var renderRunLine = (cwd) => `${colorTokens.runPill("RUN")} ${ansi.dim(cwd.replace(/\\/g, "/"))}`;
|
|
4505
|
+
var buildFileBadgeLine = (rel, failedCount) => failedCount > 0 ? `${colorTokens.failPill("FAIL")} ${ansi.white(rel)}` : `${colorTokens.passPill("PASS")} ${ansi.white(rel)}`;
|
|
4506
|
+
var buildPerFileOverview = (rel, assertions) => {
|
|
4507
|
+
const out = [];
|
|
4508
|
+
out.push(`${ansi.magenta(rel)} ${ansi.dim(`(${assertions.length})`)}`);
|
|
4509
|
+
for (const assertion of assertions) {
|
|
4510
|
+
const name = assertion.fullName;
|
|
4511
|
+
if (assertion.status === "passed") {
|
|
4512
|
+
out.push(` ${colorTokens.pass("\u2713")} ${ansi.dim(name)}`);
|
|
4513
|
+
} else if (assertion.status === "todo") {
|
|
4514
|
+
out.push(` ${colorTokens.todo("\u2610")} ${ansi.dim(name)} ${colorTokens.todo("[todo]")}`);
|
|
4515
|
+
} else if (assertion.status === "pending") {
|
|
4516
|
+
out.push(` ${colorTokens.skip("\u2193")} ${ansi.dim(name)} ${colorTokens.skip("[skipped]")}`);
|
|
4517
|
+
} else {
|
|
4518
|
+
out.push(` ${colorTokens.fail("\xD7")} ${ansi.white(name)}`);
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
out.push("");
|
|
4522
|
+
return out;
|
|
4523
|
+
};
|
|
4524
|
+
var isObjectRecord = (value) => typeof value === "object" && value !== null;
|
|
4136
4525
|
var colorStackLine = (line, projectHint) => {
|
|
4137
4526
|
const plainLine = stripAnsiSimple(line);
|
|
4138
|
-
if (
|
|
4527
|
+
if (!/\s+at\s+/.test(plainLine)) {
|
|
4139
4528
|
return plainLine;
|
|
4140
4529
|
}
|
|
4141
4530
|
const match = plainLine.match(/\(?([^\s()]+):(\d+):(\d+)\)?$/);
|
|
@@ -4151,298 +4540,144 @@ var colorStackLine = (line, projectHint) => {
|
|
|
4151
4540
|
`(${coloredPath}${ansi.dim(":")}${ansi.white(`${lineNumber}:${columnNumber}`)})`
|
|
4152
4541
|
);
|
|
4153
4542
|
};
|
|
4154
|
-
var
|
|
4155
|
-
const
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
break;
|
|
4160
|
-
}
|
|
4161
|
-
if (/^\s*\^+\s*$/.test(raw)) {
|
|
4162
|
-
out.push(` ${colorTokens.fail(raw.trimEnd())}`);
|
|
4163
|
-
continue;
|
|
4164
|
-
}
|
|
4165
|
-
const pointerMatch = raw.match(/^\s*>(\s*\d+)\s*\|\s?(.*)$/);
|
|
4166
|
-
if (pointerMatch) {
|
|
4167
|
-
const num = ansi.dim(pointerMatch[1].trim());
|
|
4168
|
-
const code = ansi.yellow(pointerMatch[2] ?? "");
|
|
4169
|
-
out.push(` ${colorTokens.fail(">")} ${num} ${ansi.dim("|")} ${code}`);
|
|
4170
|
-
continue;
|
|
4171
|
-
}
|
|
4172
|
-
const normalMatch = raw.match(/^\s*(\d+)\s*\|\s?(.*)$/);
|
|
4173
|
-
if (normalMatch) {
|
|
4174
|
-
const num = ansi.dim(normalMatch[1]);
|
|
4175
|
-
const code = ansi.dim(normalMatch[2] ?? "");
|
|
4176
|
-
out.push(` ${num} ${ansi.dim("|")} ${code}`);
|
|
4177
|
-
continue;
|
|
4178
|
-
}
|
|
4179
|
-
out.push(` ${raw}`);
|
|
4543
|
+
var extractBridgePath = (raw, cwd) => {
|
|
4544
|
+
const re = /Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g;
|
|
4545
|
+
const matches = Array.from(raw.matchAll(re));
|
|
4546
|
+
if (matches.length === 0) {
|
|
4547
|
+
return null;
|
|
4180
4548
|
}
|
|
4181
|
-
|
|
4549
|
+
const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["'`]|["'`]$/g, "");
|
|
4550
|
+
return /^\//.test(jsonPath) ? jsonPath : `${cwd.replace(/\\/g, "/")}/${jsonPath}`;
|
|
4182
4551
|
};
|
|
4552
|
+
var findCodeFrameStart = (lines) => lines.findIndex((line) => /^\s*(>?\s*\d+\s*\|)/.test(stripAnsiSimple(line)));
|
|
4183
4553
|
var _sourceCache = /* @__PURE__ */ new Map();
|
|
4184
4554
|
var readSource = (file) => {
|
|
4185
|
-
const
|
|
4186
|
-
const
|
|
4187
|
-
if (
|
|
4188
|
-
return
|
|
4555
|
+
const normalized = file.replace(/\\/g, "/");
|
|
4556
|
+
const hit = _sourceCache.get(normalized);
|
|
4557
|
+
if (hit) {
|
|
4558
|
+
return hit;
|
|
4189
4559
|
}
|
|
4190
4560
|
try {
|
|
4191
|
-
const
|
|
4192
|
-
|
|
4193
|
-
_sourceCache.set(normalizedFile, arr);
|
|
4561
|
+
const arr = fs4.readFileSync(normalized, "utf8").split(/\r?\n/);
|
|
4562
|
+
_sourceCache.set(normalized, arr);
|
|
4194
4563
|
return arr;
|
|
4195
4564
|
} catch {
|
|
4196
4565
|
return [];
|
|
4197
4566
|
}
|
|
4198
4567
|
};
|
|
4568
|
+
var renderInlineCodeFrame = (lines, start) => {
|
|
4569
|
+
const out = [];
|
|
4570
|
+
for (let i = start; i < lines.length; i += 1) {
|
|
4571
|
+
const raw = stripAnsiSimple(lines[i]);
|
|
4572
|
+
if (!raw.trim()) {
|
|
4573
|
+
break;
|
|
4574
|
+
}
|
|
4575
|
+
if (/^\s*\^+\s*$/.test(raw)) {
|
|
4576
|
+
out.push(` ${Colors.Failure(raw.trimEnd())}`);
|
|
4577
|
+
} else {
|
|
4578
|
+
const ptr = raw.match(/^\s*>(\s*\d+)\s*\|\s?(.*)$/);
|
|
4579
|
+
if (ptr) {
|
|
4580
|
+
const num = ansi.dim(ptr[1].trim());
|
|
4581
|
+
const code = ansi.yellow(ptr[2] ?? "");
|
|
4582
|
+
out.push(` ${Colors.Failure(">")} ${num} ${ansi.dim("|")} ${code}`);
|
|
4583
|
+
} else {
|
|
4584
|
+
const nor = raw.match(/^\s*(\d+)\s*\|\s?(.*)$/);
|
|
4585
|
+
if (nor) {
|
|
4586
|
+
const num = ansi.dim(nor[1]);
|
|
4587
|
+
const code = ansi.dim(nor[2] ?? "");
|
|
4588
|
+
out.push(` ${num} ${ansi.dim("|")} ${code}`);
|
|
4589
|
+
} else {
|
|
4590
|
+
out.push(` ${raw}`);
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
return out;
|
|
4596
|
+
};
|
|
4199
4597
|
var renderSourceCodeFrame = (file, line, context = 3) => {
|
|
4200
4598
|
const lines = readSource(file);
|
|
4201
|
-
if (
|
|
4599
|
+
if (lines.length === 0 || !Number.isFinite(line)) {
|
|
4202
4600
|
return [];
|
|
4203
4601
|
}
|
|
4204
4602
|
const idx = Math.max(1, Math.min(line, lines.length));
|
|
4205
4603
|
const start = Math.max(1, idx - context);
|
|
4206
4604
|
const end = Math.min(lines.length, idx + context);
|
|
4207
4605
|
const out = [];
|
|
4208
|
-
for (let
|
|
4209
|
-
const num = ansi.dim(String(
|
|
4210
|
-
const code =
|
|
4211
|
-
if (
|
|
4212
|
-
out.push(` ${
|
|
4606
|
+
for (let current = start; current <= end; current += 1) {
|
|
4607
|
+
const num = ansi.dim(String(current));
|
|
4608
|
+
const code = current === idx ? ansi.yellow(lines[current - 1] ?? "") : ansi.dim(lines[current - 1] ?? "");
|
|
4609
|
+
if (current === idx) {
|
|
4610
|
+
out.push(` ${Colors.Failure(">")} ${num} ${ansi.dim("|")} ${code}`);
|
|
4213
4611
|
} else {
|
|
4214
4612
|
out.push(` ${num} ${ansi.dim("|")} ${code}`);
|
|
4215
4613
|
}
|
|
4216
4614
|
}
|
|
4217
|
-
out.push(` ${
|
|
4615
|
+
out.push(` ${Colors.Failure("^")}`);
|
|
4218
4616
|
return out;
|
|
4219
4617
|
};
|
|
4220
|
-
var
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
return i;
|
|
4225
|
-
}
|
|
4618
|
+
var stackLocation = (line) => {
|
|
4619
|
+
const match = stripAnsiSimple(line).match(/\(?([^\s()]+):(\d+):\d+\)?$/);
|
|
4620
|
+
if (!match) {
|
|
4621
|
+
return null;
|
|
4226
4622
|
}
|
|
4227
|
-
return
|
|
4623
|
+
return { file: match[1].replace(/\\/g, "/"), line: Number(match[2]) };
|
|
4228
4624
|
};
|
|
4229
|
-
var
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4625
|
+
var deepestProjectLoc = (stackLines, projectHint) => {
|
|
4626
|
+
for (let i = stackLines.length - 1; i >= 0; i -= 1) {
|
|
4627
|
+
const simple = stripAnsiSimple(stackLines[i]);
|
|
4628
|
+
if (isStackLine(simple) && projectHint.test(simple) && !/node_modules|vitest|jest/.test(simple)) {
|
|
4629
|
+
return stackLocation(stackLines[i]);
|
|
4630
|
+
}
|
|
4233
4631
|
}
|
|
4234
|
-
|
|
4235
|
-
return tail.map((frameLine) => ` ${colorStackLine(frameLine, projectHint)}`);
|
|
4236
|
-
};
|
|
4237
|
-
var firstProjectFrames = (lines, projectHint, max = 2) => {
|
|
4238
|
-
const onlyStack = lines.filter((ln) => isStackLine(stripAnsiSimple(ln)));
|
|
4239
|
-
const projectOnly = onlyStack.filter((ln) => projectHint.test(stripAnsiSimple(ln)));
|
|
4240
|
-
return projectOnly.slice(0, max).map((ln) => ` ${colorStackLine(ln, projectHint)}`);
|
|
4632
|
+
return null;
|
|
4241
4633
|
};
|
|
4242
|
-
var
|
|
4243
|
-
var extractAssertionMessage = (msgLines) => {
|
|
4244
|
-
const lines = msgLines.map((rawLine) => stripAnsiSimple(rawLine));
|
|
4634
|
+
var buildCodeFrameSection = (messageLines, ctx, synthLoc) => {
|
|
4245
4635
|
const out = [];
|
|
4246
|
-
const
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
out.push(lines[hintIdx]);
|
|
4636
|
+
const start = findCodeFrameStart(messageLines);
|
|
4637
|
+
if (start >= 0) {
|
|
4638
|
+
out.push(...renderInlineCodeFrame(messageLines, start), "");
|
|
4639
|
+
return out;
|
|
4251
4640
|
}
|
|
4252
|
-
|
|
4253
|
-
out.push(
|
|
4254
|
-
for (let i = start + 1; i < lines.length; i += 1) {
|
|
4255
|
-
const candidate = lines[i];
|
|
4256
|
-
if (isTerminator(candidate)) {
|
|
4257
|
-
break;
|
|
4258
|
-
}
|
|
4259
|
-
out.push(candidate);
|
|
4260
|
-
}
|
|
4261
|
-
};
|
|
4262
|
-
const expectedIdx = lines.findIndex(
|
|
4263
|
-
(candidateLine) => /^\s*Expected:/.test(candidateLine)
|
|
4264
|
-
);
|
|
4265
|
-
const receivedIdx = lines.findIndex(
|
|
4266
|
-
(candidateLine) => /^\s*Received:/.test(candidateLine)
|
|
4267
|
-
);
|
|
4268
|
-
const diffIdx = lines.findIndex(
|
|
4269
|
-
(candidateLine) => /^\s*(?:- Expected|\+ Received|Difference:)/.test(candidateLine)
|
|
4270
|
-
);
|
|
4271
|
-
if (expectedIdx >= 0) {
|
|
4272
|
-
collectBlock(expectedIdx);
|
|
4273
|
-
}
|
|
4274
|
-
if (receivedIdx >= 0) {
|
|
4275
|
-
collectBlock(receivedIdx);
|
|
4276
|
-
}
|
|
4277
|
-
if (diffIdx >= 0) {
|
|
4278
|
-
collectBlock(diffIdx);
|
|
4279
|
-
}
|
|
4280
|
-
if (out.length === 0 && hintIdx >= 0) {
|
|
4281
|
-
for (let i = hintIdx + 1; i < lines.length && out.length < 4; i += 1) {
|
|
4282
|
-
const candidate = lines[i];
|
|
4283
|
-
if (isTerminator(candidate)) {
|
|
4284
|
-
break;
|
|
4285
|
-
}
|
|
4286
|
-
out.push(candidate);
|
|
4287
|
-
}
|
|
4641
|
+
if (ctx.showStacks && synthLoc) {
|
|
4642
|
+
out.push(...renderSourceCodeFrame(synthLoc.file, synthLoc.line), "");
|
|
4288
4643
|
}
|
|
4289
4644
|
return out;
|
|
4290
4645
|
};
|
|
4291
|
-
var
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
const
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
this.out = process.env.JEST_BRIDGE_OUT || (options && options.outFile) || path.join(process.cwd(), 'coverage', 'jest-run.json');
|
|
4301
|
-
this.buf = { startTime: Date.now(), testResults: [], aggregated: null };
|
|
4302
|
-
}
|
|
4303
|
-
onRunStart() { this.buf.startTime = Date.now(); }
|
|
4304
|
-
onTestResult(_test, tr) {
|
|
4305
|
-
const mapAssertion = (a) => ({
|
|
4306
|
-
title: a.title,
|
|
4307
|
-
fullName: a.fullName || [...(a.ancestorTitles || []), a.title].join(' '),
|
|
4308
|
-
status: a.status,
|
|
4309
|
-
duration: a.duration || 0,
|
|
4310
|
-
location: a.location || null,
|
|
4311
|
-
failureMessages: (a.failureMessages || []).map(String),
|
|
4312
|
-
});
|
|
4313
|
-
this.buf.testResults.push({
|
|
4314
|
-
testFilePath: tr.testFilePath,
|
|
4315
|
-
status: tr.numFailingTests ? 'failed' : 'passed',
|
|
4316
|
-
failureMessage: tr.failureMessage || '',
|
|
4317
|
-
failureDetails: tr.failureDetails || [],
|
|
4318
|
-
console: tr.console || null,
|
|
4319
|
-
perfStats: tr.perfStats || {},
|
|
4320
|
-
testResults: (tr.testResults || []).map(mapAssertion),
|
|
4321
|
-
});
|
|
4322
|
-
}
|
|
4323
|
-
onRunComplete(_contexts, agg) {
|
|
4324
|
-
this.buf.aggregated = {
|
|
4325
|
-
numTotalTestSuites: agg.numTotalTestSuites,
|
|
4326
|
-
numPassedTestSuites: agg.numPassedTestSuites,
|
|
4327
|
-
numFailedTestSuites: agg.numFailedTestSuites,
|
|
4328
|
-
numTotalTests: agg.numTotalTests,
|
|
4329
|
-
numPassedTests: agg.numPassedTests,
|
|
4330
|
-
numFailedTests: agg.numFailedTests,
|
|
4331
|
-
numPendingTests: agg.numPendingTests,
|
|
4332
|
-
numTodoTests: agg.numTodoTests,
|
|
4333
|
-
startTime: agg.startTime,
|
|
4334
|
-
success: agg.success,
|
|
4335
|
-
runTimeMs: agg.testResults.reduce((t, r) => t + Math.max(0, (r.perfStats?.end || 0) - (r.perfStats?.start || 0)), 0),
|
|
4336
|
-
};
|
|
4337
|
-
fs.mkdirSync(path.dirname(this.out), { recursive: true });
|
|
4338
|
-
fs.writeFileSync(this.out, JSON.stringify(this.buf), 'utf8');
|
|
4339
|
-
}
|
|
4340
|
-
}
|
|
4341
|
-
module.exports = BridgeReporter;`;
|
|
4342
|
-
var asDict = (value) => value && typeof value === "object" ? value : null;
|
|
4343
|
-
var get = (objectValue, key) => objectValue ? objectValue[key] : void 0;
|
|
4344
|
-
var getStr = (objectValue, key) => {
|
|
4345
|
-
const candidate = get(objectValue, key);
|
|
4346
|
-
return typeof candidate === "string" ? candidate : void 0;
|
|
4347
|
-
};
|
|
4348
|
-
function linesFromDetails(details) {
|
|
4349
|
-
const stacks = [];
|
|
4350
|
-
const messages = [];
|
|
4351
|
-
if (!details) {
|
|
4352
|
-
return { stacks, messages };
|
|
4353
|
-
}
|
|
4354
|
-
const pushMaybe = (value, bucket) => {
|
|
4355
|
-
if (typeof value === "string" && value.trim()) {
|
|
4356
|
-
bucket.push(...value.split(/\r?\n/));
|
|
4357
|
-
}
|
|
4358
|
-
};
|
|
4359
|
-
for (const detail of details) {
|
|
4360
|
-
if (typeof detail === "string") {
|
|
4361
|
-
if (/\s+at\s.+\(.+:\d+:\d+\)/.test(detail)) {
|
|
4362
|
-
pushMaybe(detail, stacks);
|
|
4363
|
-
} else {
|
|
4364
|
-
pushMaybe(detail, messages);
|
|
4365
|
-
}
|
|
4366
|
-
continue;
|
|
4367
|
-
}
|
|
4368
|
-
const dict = asDict(detail);
|
|
4369
|
-
if (dict) {
|
|
4370
|
-
pushMaybe(getStr(dict, "stack"), stacks);
|
|
4371
|
-
pushMaybe(getStr(dict, "message"), messages);
|
|
4372
|
-
const err = asDict(get(dict, "error"));
|
|
4373
|
-
pushMaybe(getStr(err, "stack"), stacks);
|
|
4374
|
-
pushMaybe(getStr(err, "message"), messages);
|
|
4375
|
-
const matcherResult = asDict(get(dict, "matcherResult"));
|
|
4376
|
-
pushMaybe(getStr(matcherResult, "stack"), stacks);
|
|
4377
|
-
pushMaybe(getStr(matcherResult, "message"), messages);
|
|
4378
|
-
pushMaybe(getStr(matcherResult, "expected"), messages);
|
|
4379
|
-
pushMaybe(getStr(matcherResult, "received"), messages);
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
|
-
return { stacks, messages };
|
|
4383
|
-
}
|
|
4384
|
-
function labelForMessage(lines) {
|
|
4385
|
-
const joined = lines.join(" ");
|
|
4386
|
-
const matched = joined.match(/\b(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/) || joined.match(/\bError\b/);
|
|
4387
|
-
if (matched) {
|
|
4388
|
-
const typeName = matched[1] ?? "Error";
|
|
4389
|
-
return `${typeName}:`;
|
|
4390
|
-
}
|
|
4391
|
-
return /expect\(.+?\)\.(?:to|not\.)/.test(joined) ? "Assertion:" : "Message:";
|
|
4392
|
-
}
|
|
4393
|
-
function extractExpectedReceived(details, lines) {
|
|
4394
|
-
if (details) {
|
|
4395
|
-
for (const detail of details) {
|
|
4396
|
-
const dict = asDict(detail);
|
|
4397
|
-
const matcherResult = dict && asDict(get(dict, "matcherResult"));
|
|
4398
|
-
if (matcherResult) {
|
|
4399
|
-
const expected = get(matcherResult, "expected");
|
|
4400
|
-
const received = get(matcherResult, "received");
|
|
4401
|
-
if (expected !== void 0 || received !== void 0) {
|
|
4402
|
-
return { expected, received };
|
|
4403
|
-
}
|
|
4404
|
-
}
|
|
4646
|
+
var normalizeBlock = (raw) => raw.replace(/^\s*Array\s*\[/, "[").replace(/^\s*Object\s*\{/, "{").replace(/,(\s*[\]}])/g, "$1");
|
|
4647
|
+
var stringifyPrettierish = (value) => {
|
|
4648
|
+
if (typeof value === "string") {
|
|
4649
|
+
const text = normalizeBlock(value.trim());
|
|
4650
|
+
try {
|
|
4651
|
+
const parsed = import_json5.default.parse(text);
|
|
4652
|
+
return JSON.stringify(parsed, null, 2);
|
|
4653
|
+
} catch {
|
|
4654
|
+
return value;
|
|
4405
4655
|
}
|
|
4406
4656
|
}
|
|
4407
|
-
if (
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
}
|
|
4418
|
-
if (/^\s*Received:/.test(simple)) {
|
|
4419
|
-
mode = "rec";
|
|
4420
|
-
receivedLines.push(simple.replace(/^\s*Received:\s*/, ""));
|
|
4421
|
-
continue;
|
|
4422
|
-
}
|
|
4423
|
-
if (/^\s*[-+]\s/.test(simple)) {
|
|
4424
|
-
continue;
|
|
4425
|
-
}
|
|
4426
|
-
if (!simple.trim()) {
|
|
4427
|
-
mode = "none";
|
|
4428
|
-
} else if (mode === "exp") {
|
|
4429
|
-
expectedLines.push(simple);
|
|
4430
|
-
} else if (mode === "rec") {
|
|
4431
|
-
receivedLines.push(simple);
|
|
4432
|
-
}
|
|
4433
|
-
}
|
|
4434
|
-
if (expectedLines.length || receivedLines.length) {
|
|
4435
|
-
return { expected: expectedLines.join("\n"), received: receivedLines.join("\n") };
|
|
4436
|
-
}
|
|
4437
|
-
const unified = extractFromUnifiedDiff(lines);
|
|
4438
|
-
if (unified.expected !== void 0 || unified.received !== void 0) {
|
|
4439
|
-
return unified;
|
|
4657
|
+
if (Array.isArray(value) || isObjectRecord(value)) {
|
|
4658
|
+
try {
|
|
4659
|
+
return JSON.stringify(value, null, 2);
|
|
4660
|
+
} catch {
|
|
4661
|
+
return util.inspect(value, {
|
|
4662
|
+
depth: 10,
|
|
4663
|
+
breakLength: Infinity,
|
|
4664
|
+
compact: false,
|
|
4665
|
+
sorted: true
|
|
4666
|
+
});
|
|
4440
4667
|
}
|
|
4441
4668
|
}
|
|
4442
|
-
return {
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4669
|
+
return util.inspect(value, {
|
|
4670
|
+
depth: 10,
|
|
4671
|
+
breakLength: Infinity,
|
|
4672
|
+
compact: false,
|
|
4673
|
+
sorted: true
|
|
4674
|
+
});
|
|
4675
|
+
};
|
|
4676
|
+
var isArrayOfPrimitives = (value) => Array.isArray(value) && value.every(
|
|
4677
|
+
(element) => ["string", "number", "boolean"].includes(typeof element) || element === null
|
|
4678
|
+
);
|
|
4679
|
+
var extractFromUnifiedDiff = (rawLines) => {
|
|
4680
|
+
const lines = (rawLines ?? []).map((lineText) => stripAnsiSimple(lineText));
|
|
4446
4681
|
let startIndex = -1;
|
|
4447
4682
|
for (let i = 0; i < lines.length; i += 1) {
|
|
4448
4683
|
const lt = lines[i];
|
|
@@ -4489,12 +4724,10 @@ function extractFromUnifiedDiff(rawLines) {
|
|
|
4489
4724
|
receivedParts.push(unsigned);
|
|
4490
4725
|
}
|
|
4491
4726
|
if (!expDone && expectedParts.length > 0) {
|
|
4492
|
-
|
|
4493
|
-
expDone = canParseJsonish(expJoined);
|
|
4727
|
+
expDone = canParseJsonish(expectedParts.join("\n"));
|
|
4494
4728
|
}
|
|
4495
4729
|
if (!recDone && receivedParts.length > 0) {
|
|
4496
|
-
|
|
4497
|
-
recDone = canParseJsonish(recJoined);
|
|
4730
|
+
recDone = canParseJsonish(receivedParts.join("\n"));
|
|
4498
4731
|
}
|
|
4499
4732
|
if (opened && expDone && recDone) {
|
|
4500
4733
|
break;
|
|
@@ -4524,32 +4757,108 @@ function extractFromUnifiedDiff(rawLines) {
|
|
|
4524
4757
|
result.received = recStr;
|
|
4525
4758
|
}
|
|
4526
4759
|
return result;
|
|
4527
|
-
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4760
|
+
};
|
|
4761
|
+
var extractExpectedReceived = (details, lines) => {
|
|
4762
|
+
if (details) {
|
|
4763
|
+
for (const detail of details) {
|
|
4764
|
+
const dict = isObjectRecord(detail) ? detail : void 0;
|
|
4765
|
+
const matcher = dict && isObjectRecord(dict.matcherResult) ? dict.matcherResult : void 0;
|
|
4766
|
+
if (matcher) {
|
|
4767
|
+
const expectedValue = matcher.expected;
|
|
4768
|
+
const receivedValue = matcher.received;
|
|
4769
|
+
const matcherName = String(
|
|
4770
|
+
matcher.matcherName || ""
|
|
4771
|
+
);
|
|
4772
|
+
if (matcherName === "toHaveBeenCalledTimes" || matcherName === "toBeCalledTimes") {
|
|
4773
|
+
const getCallsCount = (actual) => {
|
|
4774
|
+
if (isObjectRecord(actual) && Array.isArray(actual.calls)) {
|
|
4775
|
+
return actual.calls.length;
|
|
4776
|
+
}
|
|
4777
|
+
if (typeof actual === "number") {
|
|
4778
|
+
return actual;
|
|
4779
|
+
}
|
|
4780
|
+
if (Array.isArray(actual)) {
|
|
4781
|
+
return actual.length;
|
|
4782
|
+
}
|
|
4783
|
+
return void 0;
|
|
4784
|
+
};
|
|
4785
|
+
const expectedNumber = getCallsCount(expectedValue);
|
|
4786
|
+
const actualValue = matcher.actual ?? receivedValue;
|
|
4787
|
+
const receivedNumber = getCallsCount(actualValue);
|
|
4788
|
+
if (expectedNumber !== void 0 || receivedNumber !== void 0) {
|
|
4789
|
+
return { expected: expectedNumber, received: receivedNumber };
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
if (expectedValue !== void 0 && receivedValue !== void 0) {
|
|
4793
|
+
return { expected: expectedValue, received: receivedValue };
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
if (lines && lines.length) {
|
|
4799
|
+
const expectedLines = [];
|
|
4800
|
+
const receivedLines = [];
|
|
4801
|
+
let mode = "none";
|
|
4802
|
+
for (const rawLine of lines) {
|
|
4803
|
+
const simple = stripAnsiSimple(rawLine);
|
|
4804
|
+
if (/^\s*Expected:/.test(simple)) {
|
|
4805
|
+
mode = "exp";
|
|
4806
|
+
expectedLines.push(simple.replace(/^\s*Expected:\s*/, ""));
|
|
4807
|
+
continue;
|
|
4808
|
+
}
|
|
4809
|
+
if (/^\s*Received:/.test(simple)) {
|
|
4810
|
+
mode = "rec";
|
|
4811
|
+
receivedLines.push(simple.replace(/^\s*Received:\s*/, ""));
|
|
4812
|
+
continue;
|
|
4813
|
+
}
|
|
4814
|
+
if (/^\s*[-+]\s/.test(simple)) {
|
|
4815
|
+
continue;
|
|
4816
|
+
}
|
|
4817
|
+
if (!simple.trim()) {
|
|
4818
|
+
mode = "none";
|
|
4819
|
+
} else if (mode === "exp") {
|
|
4820
|
+
expectedLines.push(simple);
|
|
4821
|
+
} else if (mode === "rec") {
|
|
4822
|
+
receivedLines.push(simple);
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4825
|
+
if (expectedLines.length || receivedLines.length) {
|
|
4826
|
+
return { expected: expectedLines.join("\n"), received: receivedLines.join("\n") };
|
|
4827
|
+
}
|
|
4828
|
+
const unified = extractFromUnifiedDiff(lines);
|
|
4829
|
+
if (unified.expected !== void 0 || unified.received !== void 0) {
|
|
4830
|
+
return unified;
|
|
4831
|
+
}
|
|
4533
4832
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4833
|
+
return {};
|
|
4834
|
+
};
|
|
4835
|
+
var buildPrettyDiffSection = (details, messageLines) => {
|
|
4836
|
+
const payload = extractExpectedReceived(details, messageLines);
|
|
4837
|
+
if (payload.expected === void 0 && payload.received === void 0) {
|
|
4838
|
+
return [];
|
|
4839
|
+
}
|
|
4840
|
+
const expectedString = stringifyPrettierish(payload.expected);
|
|
4841
|
+
const receivedString = stringifyPrettierish(payload.received);
|
|
4842
|
+
const out = [];
|
|
4843
|
+
const expectedLenLabel = Array.isArray(payload.expected) ? ansi.dim(` (len ${payload.expected.length})`) : "";
|
|
4844
|
+
out.push(` ${ansi.bold("Expected")}${expectedLenLabel}`);
|
|
4536
4845
|
out.push(
|
|
4537
|
-
|
|
4538
|
-
expected && Array.isArray(expected) ? `(len ${expected.length})` : ""
|
|
4539
|
-
)}`
|
|
4846
|
+
expectedString.split("\n").map((expectedLine) => ` ${Colors.Success(expectedLine)}`).join("\n")
|
|
4540
4847
|
);
|
|
4541
|
-
|
|
4848
|
+
const receivedLenLabel = Array.isArray(payload.received) ? ansi.dim(` (len ${payload.received.length})`) : "";
|
|
4849
|
+
out.push(` ${ansi.bold("Received")}${receivedLenLabel}`);
|
|
4542
4850
|
out.push(
|
|
4543
|
-
|
|
4544
|
-
received && Array.isArray(received) ? `(len ${received.length})` : ""
|
|
4545
|
-
)}`
|
|
4851
|
+
receivedString.split("\n").map((receivedLine) => ` ${Colors.Failure(receivedLine)}`).join("\n")
|
|
4546
4852
|
);
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
const
|
|
4552
|
-
|
|
4853
|
+
if (isArrayOfPrimitives(payload.expected) && isArrayOfPrimitives(payload.received)) {
|
|
4854
|
+
const expectedSet = new Set(
|
|
4855
|
+
payload.expected.map((element) => String(element))
|
|
4856
|
+
);
|
|
4857
|
+
const receivedSet = new Set(
|
|
4858
|
+
payload.received.map((element) => String(element))
|
|
4859
|
+
);
|
|
4860
|
+
const missing = Array.from(expectedSet).filter((element) => !receivedSet.has(element));
|
|
4861
|
+
const unexpected = Array.from(receivedSet).filter((element) => !expectedSet.has(element));
|
|
4553
4862
|
const parts = [];
|
|
4554
4863
|
if (missing.length) {
|
|
4555
4864
|
parts.push(
|
|
@@ -4562,67 +4871,85 @@ function renderPrettyDiff(payload) {
|
|
|
4562
4871
|
);
|
|
4563
4872
|
}
|
|
4564
4873
|
if (parts.length) {
|
|
4565
|
-
out.push(` ${ansi.dim("Difference:")} ${
|
|
4874
|
+
out.push(` ${ansi.dim("Difference:")} ${Colors.Failure(parts.join(ansi.dim(" | ")))}`);
|
|
4566
4875
|
}
|
|
4567
4876
|
}
|
|
4568
4877
|
out.push("");
|
|
4569
4878
|
return out;
|
|
4570
|
-
}
|
|
4571
|
-
|
|
4572
|
-
const
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
const errorLine = details.messages.find(
|
|
4577
|
-
(lineText) => /\b(?:Error|TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/.test(lineText)
|
|
4879
|
+
};
|
|
4880
|
+
var buildMessageSection = (messageLines, details, _ctx, opts) => {
|
|
4881
|
+
const out = [];
|
|
4882
|
+
const lines = messageLines.map((lineText) => stripAnsiSimple(lineText));
|
|
4883
|
+
const hintIdx = lines.findIndex(
|
|
4884
|
+
(candidate) => /expect\(.+?\)\.(?:to|not\.)/.test(candidate) || /\b(?:AssertionError|Error):/.test(candidate)
|
|
4578
4885
|
);
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
const firstNonEmpty = details.messages.find((lineText) => lineText.trim().length);
|
|
4583
|
-
if (firstNonEmpty) {
|
|
4584
|
-
return [firstNonEmpty];
|
|
4585
|
-
}
|
|
4586
|
-
return [];
|
|
4587
|
-
}
|
|
4588
|
-
function colorUnifiedDiffLine(simple) {
|
|
4589
|
-
if (/^\s*-\s/.test(simple)) {
|
|
4590
|
-
return colorTokens.fail(simple);
|
|
4886
|
+
const acc = [];
|
|
4887
|
+
if (hintIdx >= 0) {
|
|
4888
|
+
acc.push(lines[hintIdx]);
|
|
4591
4889
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4890
|
+
const pushBlock = (start) => {
|
|
4891
|
+
acc.push(lines[start]);
|
|
4892
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
4893
|
+
const candidate = lines[i];
|
|
4894
|
+
if (!candidate.trim() || isStackLine(candidate)) {
|
|
4895
|
+
break;
|
|
4896
|
+
}
|
|
4897
|
+
acc.push(candidate);
|
|
4898
|
+
}
|
|
4899
|
+
};
|
|
4900
|
+
const expectedIdx = lines.findIndex((lineText) => /^\s*Expected:/.test(lineText));
|
|
4901
|
+
const receivedIdx = lines.findIndex((lineText) => /^\s*Received:/.test(lineText));
|
|
4902
|
+
const diffIdx = lines.findIndex(
|
|
4903
|
+
(lineText) => /^\s*(?:- Expected|\+ Received|Difference:)/.test(lineText)
|
|
4904
|
+
);
|
|
4905
|
+
if (expectedIdx >= 0) {
|
|
4906
|
+
pushBlock(expectedIdx);
|
|
4594
4907
|
}
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
var findCodeFrameStart = (lines) => lines.findIndex((line) => /^\s*(>?\s*\d+\s*\|)/.test(stripAnsiSimple(line)));
|
|
4598
|
-
var deepestProjectLoc = (stackLines, projectHint) => {
|
|
4599
|
-
const idx = findLastProjectFrameIndex(stackLines, projectHint);
|
|
4600
|
-
return idx >= 0 ? stackLocation(stackLines[idx]) : null;
|
|
4601
|
-
};
|
|
4602
|
-
var buildCodeFrameSection = (messageLines, ctx, synthLoc) => {
|
|
4603
|
-
const lines = [];
|
|
4604
|
-
const start = findCodeFrameStart(messageLines);
|
|
4605
|
-
if (start >= 0) {
|
|
4606
|
-
lines.push(...renderCodeFrame(messageLines, start), "");
|
|
4607
|
-
return lines;
|
|
4908
|
+
if (receivedIdx >= 0) {
|
|
4909
|
+
pushBlock(receivedIdx);
|
|
4608
4910
|
}
|
|
4609
|
-
if (
|
|
4610
|
-
|
|
4911
|
+
if (diffIdx >= 0) {
|
|
4912
|
+
pushBlock(diffIdx);
|
|
4611
4913
|
}
|
|
4612
|
-
|
|
4613
|
-
};
|
|
4614
|
-
var buildMessageSection = (messageLines, details, ctx, opts) => {
|
|
4615
|
-
const out = [];
|
|
4616
|
-
const primary = pickPrimaryMessage(messageLines, details);
|
|
4617
|
-
const filtered = opts?.suppressDiff ? primary.filter((raw) => {
|
|
4914
|
+
const filtered = opts?.suppressDiff ? acc.filter((raw) => {
|
|
4618
4915
|
const simple = stripAnsiSimple(raw);
|
|
4619
4916
|
return !/^\s*(Expected:|Received:|Difference:)\b/.test(simple) && !/^\s*[-+]\s/.test(simple) && !/^\s*(Array\s*\[|Object\s*\{)/.test(simple);
|
|
4620
|
-
}) :
|
|
4621
|
-
|
|
4622
|
-
|
|
4917
|
+
}) : acc;
|
|
4918
|
+
const hasOnlyBareError = filtered.length === 0 || filtered.length === 1 && /^\s*(?:Error|AssertionError):?\s*$/.test(filtered[0] ?? "");
|
|
4919
|
+
const fallbackLines = [];
|
|
4920
|
+
if (hasOnlyBareError) {
|
|
4921
|
+
const startFrom = hintIdx >= 0 ? hintIdx + 1 : 0;
|
|
4922
|
+
for (let i = startFrom; i < lines.length; i += 1) {
|
|
4923
|
+
const candidate = lines[i];
|
|
4924
|
+
if (!candidate.trim()) {
|
|
4925
|
+
break;
|
|
4926
|
+
}
|
|
4927
|
+
if (isStackLine(candidate)) {
|
|
4928
|
+
break;
|
|
4929
|
+
}
|
|
4930
|
+
fallbackLines.push(candidate);
|
|
4931
|
+
}
|
|
4932
|
+
if (fallbackLines.length === 0 && details && details.messages && details.messages.length) {
|
|
4933
|
+
fallbackLines.push(
|
|
4934
|
+
...details.messages.map((messageText) => stripAnsiSimple(messageText)).filter((messageText) => messageText.trim().length > 0).slice(0, 6)
|
|
4935
|
+
);
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
if (filtered.length > 0) {
|
|
4939
|
+
const label = (() => {
|
|
4940
|
+
const joined = filtered.join(" ");
|
|
4941
|
+
const matchResult = joined.match(/\b(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/) || joined.match(/\bError\b/);
|
|
4942
|
+
if (matchResult) {
|
|
4943
|
+
const typeName = matchResult[1] ?? "Error";
|
|
4944
|
+
return `${typeName}:`;
|
|
4945
|
+
}
|
|
4946
|
+
return /expect\(.+?\)\.(?:to|not\.)/.test(joined) ? "Assertion:" : "Message:";
|
|
4947
|
+
})();
|
|
4623
4948
|
out.push(` ${ansi.bold(label)}`);
|
|
4624
|
-
|
|
4625
|
-
|
|
4949
|
+
const body = hasOnlyBareError ? fallbackLines : filtered;
|
|
4950
|
+
for (const lineText of body) {
|
|
4951
|
+
const colored = /^\s*-\s/.test(lineText) ? Colors.Failure(lineText) : /^\s*\+\s/.test(lineText) ? Colors.Success(lineText) : lineText;
|
|
4952
|
+
out.push(` ${ansi.yellow(colored)}`);
|
|
4626
4953
|
}
|
|
4627
4954
|
if (opts?.stackPreview && opts.stackPreview.length) {
|
|
4628
4955
|
for (const frame of opts.stackPreview) {
|
|
@@ -4633,32 +4960,85 @@ var buildMessageSection = (messageLines, details, ctx, opts) => {
|
|
|
4633
4960
|
}
|
|
4634
4961
|
return out;
|
|
4635
4962
|
};
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
if (!Array.isArray(maybeConsole)) {
|
|
4642
|
-
return out;
|
|
4963
|
+
var linesFromDetails = (details) => {
|
|
4964
|
+
const stacks = [];
|
|
4965
|
+
const messages = [];
|
|
4966
|
+
if (!details) {
|
|
4967
|
+
return { stacks, messages };
|
|
4643
4968
|
}
|
|
4644
|
-
const
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
}
|
|
4649
|
-
const
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4969
|
+
const pushMaybe = (value, bucket) => {
|
|
4970
|
+
if (typeof value === "string" && value.trim()) {
|
|
4971
|
+
bucket.push(...value.split(/\r?\n/));
|
|
4972
|
+
}
|
|
4973
|
+
};
|
|
4974
|
+
const visitDeep = (value, depth) => {
|
|
4975
|
+
if (depth > 3 || value == null) {
|
|
4976
|
+
return;
|
|
4977
|
+
}
|
|
4978
|
+
if (typeof value === "string") {
|
|
4979
|
+
pushMaybe(value, messages);
|
|
4980
|
+
return;
|
|
4981
|
+
}
|
|
4982
|
+
if (typeof value !== "object") {
|
|
4983
|
+
return;
|
|
4984
|
+
}
|
|
4985
|
+
const obj = value;
|
|
4986
|
+
if (typeof obj.message === "string") {
|
|
4987
|
+
pushMaybe(obj.message, messages);
|
|
4988
|
+
}
|
|
4989
|
+
if (typeof obj.stack === "string") {
|
|
4990
|
+
pushMaybe(obj.stack, stacks);
|
|
4991
|
+
}
|
|
4992
|
+
if (typeof obj.expected === "string") {
|
|
4993
|
+
pushMaybe(obj.expected, messages);
|
|
4994
|
+
}
|
|
4995
|
+
if (typeof obj.received === "string") {
|
|
4996
|
+
pushMaybe(obj.received, messages);
|
|
4997
|
+
}
|
|
4998
|
+
const arrays = ["errors", "causes", "aggregatedErrors"];
|
|
4999
|
+
for (const key of arrays) {
|
|
5000
|
+
const arr = obj[key];
|
|
5001
|
+
if (Array.isArray(arr)) {
|
|
5002
|
+
for (const element of arr) {
|
|
5003
|
+
visitDeep(element, depth + 1);
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
const nestedCandidates = ["error", "cause", "matcherResult"];
|
|
5008
|
+
for (const key of nestedCandidates) {
|
|
5009
|
+
if (obj[key] && typeof obj[key] === "object") {
|
|
5010
|
+
visitDeep(obj[key], depth + 1);
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
5013
|
+
};
|
|
5014
|
+
for (const detail of details) {
|
|
5015
|
+
if (typeof detail === "string") {
|
|
5016
|
+
if (/\s+at\s.+\(.+:\d+:\d+\)/.test(detail)) {
|
|
5017
|
+
pushMaybe(detail, stacks);
|
|
5018
|
+
} else {
|
|
5019
|
+
pushMaybe(detail, messages);
|
|
5020
|
+
}
|
|
5021
|
+
} else if (isObjectRecord(detail)) {
|
|
5022
|
+
pushMaybe(detail.stack, stacks);
|
|
5023
|
+
pushMaybe(detail.message, messages);
|
|
5024
|
+
const err = isObjectRecord(detail.error) ? detail.error : void 0;
|
|
5025
|
+
if (err) {
|
|
5026
|
+
pushMaybe(err.stack, stacks);
|
|
5027
|
+
pushMaybe(err.message, messages);
|
|
5028
|
+
}
|
|
5029
|
+
const matcher = isObjectRecord(detail.matcherResult) ? detail.matcherResult : void 0;
|
|
5030
|
+
if (matcher) {
|
|
5031
|
+
pushMaybe(matcher.stack, stacks);
|
|
5032
|
+
pushMaybe(matcher.message, messages);
|
|
5033
|
+
pushMaybe(matcher.expected, messages);
|
|
5034
|
+
pushMaybe(matcher.received, messages);
|
|
5035
|
+
}
|
|
5036
|
+
if (messages.length === 0 && stacks.length === 0) {
|
|
5037
|
+
visitDeep(detail, 0);
|
|
5038
|
+
}
|
|
4658
5039
|
}
|
|
4659
|
-
out.push("");
|
|
4660
5040
|
}
|
|
4661
|
-
return
|
|
5041
|
+
return { stacks, messages };
|
|
4662
5042
|
};
|
|
4663
5043
|
var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
4664
5044
|
const out = [];
|
|
@@ -4667,13 +5047,18 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
4667
5047
|
out.push(` ${ansi.dim("(hidden by TEST_CLI_STACKS=)")}`, "");
|
|
4668
5048
|
return out;
|
|
4669
5049
|
}
|
|
4670
|
-
const
|
|
5050
|
+
const onlyStack = mergedForStack.filter(
|
|
5051
|
+
(lineText) => isStackLine(stripAnsiSimple(lineText))
|
|
5052
|
+
);
|
|
5053
|
+
const tail = onlyStack.slice(-4);
|
|
4671
5054
|
if (tail.length) {
|
|
4672
|
-
|
|
5055
|
+
for (const frameLine of tail) {
|
|
5056
|
+
out.push(` ${colorStackLine(String(frameLine), ctx.projectHint)}`);
|
|
5057
|
+
}
|
|
4673
5058
|
const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
4674
5059
|
if (loc) {
|
|
4675
5060
|
const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
|
|
4676
|
-
out.push(` ${ansi.dim("at")} ${osc8(`${
|
|
5061
|
+
out.push(` ${ansi.dim("at")} ${osc8(`${loc.file.split("/").pop()}:${loc.line}`, href)}`);
|
|
4677
5062
|
}
|
|
4678
5063
|
out.push("");
|
|
4679
5064
|
return out;
|
|
@@ -4688,171 +5073,460 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
4688
5073
|
out.push(` ${ansi.dim("(no stack provided)")}`, "");
|
|
4689
5074
|
return out;
|
|
4690
5075
|
};
|
|
4691
|
-
var
|
|
4692
|
-
var
|
|
5076
|
+
var MAX_CONSOLE_ERRORS_TO_SHOW = 3;
|
|
5077
|
+
var isConsoleEntry = (candidate) => typeof candidate === "object" && candidate !== null;
|
|
5078
|
+
var buildConsoleSection = (maybeConsole) => {
|
|
4693
5079
|
const out = [];
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
5080
|
+
if (!Array.isArray(maybeConsole)) {
|
|
5081
|
+
return out;
|
|
5082
|
+
}
|
|
5083
|
+
const entries = maybeConsole.filter(isConsoleEntry);
|
|
5084
|
+
const errorsOnly = entries.filter((entry) => String(entry?.type ?? "").toLowerCase() === "error");
|
|
5085
|
+
const scored = errorsOnly.map((entry) => {
|
|
5086
|
+
const raw = entry?.message;
|
|
5087
|
+
const msg = Array.isArray(raw) ? raw.map(String).join(" ") : typeof raw === "string" ? raw : String(raw ?? "");
|
|
5088
|
+
return { msg, score: msg.length };
|
|
5089
|
+
}).filter((item) => item.msg.trim().length > 0).sort((left, right) => right.score - left.score).slice(0, MAX_CONSOLE_ERRORS_TO_SHOW);
|
|
5090
|
+
if (scored.length) {
|
|
5091
|
+
out.push(ansi.dim(" Console errors:"));
|
|
5092
|
+
for (const item of scored) {
|
|
5093
|
+
out.push(` ${ansi.dim("\u2022")} ${item.msg}`);
|
|
4705
5094
|
}
|
|
5095
|
+
out.push("");
|
|
4706
5096
|
}
|
|
4707
|
-
out.push("");
|
|
4708
5097
|
return out;
|
|
4709
5098
|
};
|
|
4710
|
-
var
|
|
4711
|
-
const
|
|
4712
|
-
const
|
|
4713
|
-
const
|
|
4714
|
-
|
|
5099
|
+
var buildFallbackMessageBlock = (messageLines, details) => {
|
|
5100
|
+
const normalize2 = (arr) => arr.map((lineText) => stripAnsiSimple(lineText)).filter((line) => line.trim().length > 0);
|
|
5101
|
+
const normalized = normalize2(messageLines);
|
|
5102
|
+
const informative = normalized.filter((line) => !/^\s*(?:Error|AssertionError):?\s*$/.test(line));
|
|
5103
|
+
if (informative.length > 0) {
|
|
5104
|
+
return [];
|
|
5105
|
+
}
|
|
5106
|
+
const errorIdx = normalized.findIndex(
|
|
5107
|
+
(line) => /(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError|Error):?/.test(line)
|
|
4715
5108
|
);
|
|
4716
|
-
const
|
|
4717
|
-
|
|
5109
|
+
const collected = [];
|
|
5110
|
+
if (errorIdx >= 0) {
|
|
5111
|
+
for (let i = errorIdx; i < normalized.length && collected.length < 8; i += 1) {
|
|
5112
|
+
const ln = normalized[i];
|
|
5113
|
+
if (!ln.trim()) {
|
|
5114
|
+
break;
|
|
5115
|
+
}
|
|
5116
|
+
if (isStackLine(ln)) {
|
|
5117
|
+
break;
|
|
5118
|
+
}
|
|
5119
|
+
collected.push(ln);
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
const fromDetails = collected.length > 0 ? [] : normalize2(details.messages).slice(0, 6);
|
|
5123
|
+
const linesToShow = collected.length > 0 ? collected : fromDetails;
|
|
5124
|
+
if (linesToShow.length === 0) {
|
|
5125
|
+
return [];
|
|
5126
|
+
}
|
|
4718
5127
|
const out = [];
|
|
4719
|
-
|
|
4720
|
-
const
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
5128
|
+
out.push(` ${ansi.bold("Message:")}`);
|
|
5129
|
+
for (const lineText of linesToShow) {
|
|
5130
|
+
out.push(` ${ansi.yellow(lineText)}`);
|
|
5131
|
+
}
|
|
5132
|
+
out.push("");
|
|
5133
|
+
return out;
|
|
5134
|
+
};
|
|
5135
|
+
var buildThrownSection = (details) => {
|
|
5136
|
+
const toLines = (value) => {
|
|
5137
|
+
if (value == null) {
|
|
5138
|
+
return [];
|
|
5139
|
+
}
|
|
5140
|
+
if (typeof value === "string") {
|
|
5141
|
+
return value.split(/\r?\n/);
|
|
5142
|
+
}
|
|
5143
|
+
try {
|
|
5144
|
+
return JSON.stringify(value, null, 2).split(/\r?\n/);
|
|
5145
|
+
} catch {
|
|
5146
|
+
return [String(value)];
|
|
5147
|
+
}
|
|
5148
|
+
};
|
|
5149
|
+
const candidates = [];
|
|
5150
|
+
for (const d of details) {
|
|
5151
|
+
const obj = d && typeof d === "object" ? d : null;
|
|
5152
|
+
if (obj && obj.error && typeof obj.error === "object") {
|
|
5153
|
+
const err = obj.error;
|
|
5154
|
+
if (typeof err.name === "string") {
|
|
5155
|
+
candidates.push(`name: ${err.name}`);
|
|
4735
5156
|
}
|
|
4736
|
-
|
|
4737
|
-
(
|
|
4738
|
-
);
|
|
4739
|
-
const location = firstTestLocation(block, projectHint);
|
|
4740
|
-
const rel = location ? location.split(":")[0].replace(/\\/g, "/").replace(`${cwd}/`, "") : "";
|
|
4741
|
-
const key = `${rel}|${title}`;
|
|
4742
|
-
if (seenFailures.has(key)) {
|
|
4743
|
-
lineIndex = scanIndex;
|
|
4744
|
-
continue;
|
|
5157
|
+
if (typeof err.message === "string") {
|
|
5158
|
+
candidates.push(`message: ${err.message}`);
|
|
4745
5159
|
}
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
if (
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
}
|
|
4765
|
-
const payload = extractExpectedReceived(void 0, linesBlock);
|
|
4766
|
-
const hasPretty = payload.expected !== void 0 || payload.received !== void 0;
|
|
4767
|
-
out.push(...renderPrettyDiff(payload));
|
|
4768
|
-
const detailsForMsg = linesFromDetails(void 0);
|
|
4769
|
-
const collapsedForTail = collapseStacks(linesBlock.slice(0));
|
|
4770
|
-
const stackPreview = showStacks ? firstProjectFrames(collapsedForTail, projectHint, 2) : [];
|
|
4771
|
-
out.push(
|
|
4772
|
-
...buildMessageSection(
|
|
4773
|
-
linesBlock,
|
|
4774
|
-
detailsForMsg,
|
|
4775
|
-
{ projectHint, editorCmd: opts?.editorCmd, showStacks },
|
|
4776
|
-
{ suppressDiff: hasPretty, stackPreview }
|
|
4777
|
-
)
|
|
4778
|
-
);
|
|
4779
|
-
if (showStacks && stackPreview.length === 0) {
|
|
4780
|
-
const collapsed = collapseStacks(linesBlock.slice(0));
|
|
4781
|
-
out.push(
|
|
4782
|
-
...buildStackSection(collapsed, {
|
|
4783
|
-
projectHint,
|
|
4784
|
-
editorCmd: opts?.editorCmd,
|
|
4785
|
-
showStacks
|
|
4786
|
-
})
|
|
4787
|
-
);
|
|
5160
|
+
if (typeof err.code === "string" || typeof err.code === "number") {
|
|
5161
|
+
candidates.push(`code: ${String(err.code)}`);
|
|
5162
|
+
}
|
|
5163
|
+
if (typeof err.cause === "string") {
|
|
5164
|
+
candidates.push(`cause: ${err.cause}`);
|
|
5165
|
+
}
|
|
5166
|
+
if (err.cause && typeof err.cause === "object") {
|
|
5167
|
+
candidates.push("cause:");
|
|
5168
|
+
candidates.push(...toLines(err.cause));
|
|
5169
|
+
}
|
|
5170
|
+
const rest = { ...err };
|
|
5171
|
+
delete rest.name;
|
|
5172
|
+
delete rest.message;
|
|
5173
|
+
delete rest.code;
|
|
5174
|
+
delete rest.stack;
|
|
5175
|
+
if (Object.keys(rest).length > 0) {
|
|
5176
|
+
candidates.push("details:");
|
|
5177
|
+
candidates.push(...toLines(rest));
|
|
4788
5178
|
}
|
|
4789
|
-
out.push(drawFailLine());
|
|
4790
|
-
out.push("");
|
|
4791
|
-
lineIndex = scanIndex;
|
|
4792
|
-
continue;
|
|
4793
5179
|
}
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
5180
|
+
}
|
|
5181
|
+
if (!candidates.length) {
|
|
5182
|
+
return [];
|
|
5183
|
+
}
|
|
5184
|
+
const out = [];
|
|
5185
|
+
out.push(` ${ansi.bold("Thrown:")}`);
|
|
5186
|
+
for (const line of candidates.slice(0, 50)) {
|
|
5187
|
+
out.push(` ${ansi.yellow(line)}`);
|
|
5188
|
+
}
|
|
5189
|
+
out.push("");
|
|
5190
|
+
return out;
|
|
5191
|
+
};
|
|
5192
|
+
var mkPrettyFns = () => ({
|
|
5193
|
+
drawRule,
|
|
5194
|
+
drawFailLine,
|
|
5195
|
+
renderRunLine,
|
|
5196
|
+
buildPerFileOverview,
|
|
5197
|
+
buildFileBadgeLine,
|
|
5198
|
+
extractBridgePath,
|
|
5199
|
+
buildCodeFrameSection,
|
|
5200
|
+
buildMessageSection,
|
|
5201
|
+
buildPrettyDiffSection,
|
|
5202
|
+
buildStackSection,
|
|
5203
|
+
deepestProjectLoc,
|
|
5204
|
+
findCodeFrameStart,
|
|
5205
|
+
linesFromDetails,
|
|
5206
|
+
buildFallbackMessageBlock,
|
|
5207
|
+
buildThrownSection
|
|
5208
|
+
});
|
|
5209
|
+
|
|
5210
|
+
// src/lib/formatter/render.ts
|
|
5211
|
+
var relPath = (abs, cwd) => abs.replace(/\\/g, "/").replace(`${cwd}/`, "");
|
|
5212
|
+
var renderChunks = (chunks, ctx, fns, opts) => {
|
|
5213
|
+
const out = [];
|
|
5214
|
+
const seenFiles = /* @__PURE__ */ new Set();
|
|
5215
|
+
const seenFailures = /* @__PURE__ */ new Set();
|
|
5216
|
+
const onlyFailures = Boolean(opts?.onlyFailures);
|
|
5217
|
+
let currentRelFile = null;
|
|
5218
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5219
|
+
for (const ch of chunks) {
|
|
5220
|
+
if (ch.tag === "PassFail") {
|
|
5221
|
+
const rel = relPath(ch.rel, ctx.cwd);
|
|
4799
5222
|
if (seenFiles.has(rel)) {
|
|
4800
|
-
lineIndex += 1;
|
|
4801
5223
|
continue;
|
|
4802
5224
|
}
|
|
4803
|
-
seenFiles.add(rel);
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
out.push(
|
|
5225
|
+
seenFiles.add(rel);
|
|
5226
|
+
currentRelFile = rel;
|
|
5227
|
+
if (!(onlyFailures && ch.badge === "PASS")) {
|
|
5228
|
+
out.push(fns.buildFileBadgeLine(rel, ch.badge === "FAIL" ? 1 : 0));
|
|
5229
|
+
}
|
|
5230
|
+
continue;
|
|
5231
|
+
}
|
|
5232
|
+
if (ch.tag === "FailureBlock") {
|
|
5233
|
+
out.push(fns.drawFailLine());
|
|
5234
|
+
const location = firstTestLocation(ch.lines, ctx.projectHint);
|
|
5235
|
+
const rel = location ? relPath(location.split(":")[0] ?? "", ctx.cwd) : "";
|
|
5236
|
+
const headerText = rel ? `${rel} > ${ch.title}` : ch.title;
|
|
5237
|
+
out.push(`${Colors.Failure("\xD7")} ${ansi.white(headerText)}`);
|
|
5238
|
+
const codeStart = fns.findCodeFrameStart(ch.lines);
|
|
5239
|
+
const collapsedForSrc = collapseStacks(ch.lines.slice(0));
|
|
5240
|
+
const deepestLoc = fns.deepestProjectLoc(collapsedForSrc, ctx.projectHint);
|
|
5241
|
+
let effectiveLoc = deepestLoc;
|
|
5242
|
+
if (!effectiveLoc && currentRelFile) {
|
|
5243
|
+
try {
|
|
5244
|
+
const abs = path9.resolve(ctx.cwd, currentRelFile);
|
|
5245
|
+
const source = ctx.readSource(abs);
|
|
5246
|
+
const testName = (() => {
|
|
5247
|
+
const parts = ch.title.split(">");
|
|
5248
|
+
return (parts[parts.length - 1] || ch.title).trim();
|
|
5249
|
+
})();
|
|
5250
|
+
const itRe = new RegExp(
|
|
5251
|
+
String.raw`\b(?:it|test)\s*\(\s*['\"]${escapeRegExp(testName)}['\"]`
|
|
5252
|
+
);
|
|
5253
|
+
let index = source.findIndex((line) => itRe.test(line));
|
|
5254
|
+
if (index < 0) {
|
|
5255
|
+
index = source.findIndex((line) => /\bexpect\s*\(/.test(line));
|
|
5256
|
+
} else {
|
|
5257
|
+
const windowEnd = Math.min(source.length, index + 80);
|
|
5258
|
+
for (let i = index; i < windowEnd; i += 1) {
|
|
5259
|
+
if (/\bexpect\s*\(/.test(source[i])) {
|
|
5260
|
+
index = i;
|
|
5261
|
+
break;
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
if (index >= 0) {
|
|
5266
|
+
effectiveLoc = { file: abs.replace(/\\/g, "/"), line: index + 1 };
|
|
5267
|
+
}
|
|
5268
|
+
} catch {
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
if (codeStart >= 0) {
|
|
5272
|
+
out.push("", ...fns.buildCodeFrameSection(ch.lines, ctx, effectiveLoc), "");
|
|
5273
|
+
} else {
|
|
5274
|
+
out.push("", ...fns.buildCodeFrameSection(ch.lines, ctx, effectiveLoc), "");
|
|
5275
|
+
}
|
|
5276
|
+
const pretty = fns.buildPrettyDiffSection(void 0, ch.lines);
|
|
5277
|
+
out.push(...pretty);
|
|
5278
|
+
const hasPretty = pretty.length > 0;
|
|
5279
|
+
const details = fns.linesFromDetails(void 0);
|
|
5280
|
+
const minimal = (() => {
|
|
5281
|
+
const plain = ch.lines.map((ln) => stripAnsiSimple(ln));
|
|
5282
|
+
const hint = plain.findIndex(
|
|
5283
|
+
(lineText) => /expect\(.+?\)\.(?:to|not\.)/.test(lineText) || /\bError:?\b/.test(lineText)
|
|
5284
|
+
);
|
|
5285
|
+
const acc = [];
|
|
5286
|
+
const start = hint >= 0 ? hint : 0;
|
|
5287
|
+
for (let i = start; i < plain.length; i += 1) {
|
|
5288
|
+
const ln = plain[i];
|
|
5289
|
+
if (!ln.trim()) {
|
|
5290
|
+
break;
|
|
5291
|
+
}
|
|
5292
|
+
if (isStackLine(ln)) {
|
|
5293
|
+
break;
|
|
5294
|
+
}
|
|
5295
|
+
acc.push(ln);
|
|
5296
|
+
}
|
|
5297
|
+
return acc;
|
|
5298
|
+
})();
|
|
5299
|
+
const collapsedForTail = collapseStacks(ch.lines.slice(0));
|
|
5300
|
+
const stackPreview = ctx.showStacks ? collapsedForTail.filter((ln) => isStackLine(stripAnsiSimple(ln))).filter((ln) => ctx.projectHint.test(stripAnsiSimple(ln))).slice(0, 2).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`) : [];
|
|
5301
|
+
out.push(
|
|
5302
|
+
...fns.buildMessageSection(minimal.length ? minimal : ch.lines, details, ctx, {
|
|
5303
|
+
suppressDiff: hasPretty,
|
|
5304
|
+
stackPreview
|
|
5305
|
+
})
|
|
5306
|
+
);
|
|
5307
|
+
if (minimal.length === 0 && fns.buildFallbackMessageBlock) {
|
|
5308
|
+
out.push(...fns.buildFallbackMessageBlock(ch.lines, { messages: details.messages }));
|
|
5309
|
+
}
|
|
5310
|
+
const consoleInline = (() => {
|
|
5311
|
+
const plain = ch.lines.map((ln) => stripAnsiSimple(ln));
|
|
5312
|
+
const cand = plain.filter((ln) => /\bconsole\.(error|warn)\s*\(/i.test(ln) || /^\s*Error:/.test(ln)).map((ln) => ln.trim()).filter((ln) => ln.length > 0).sort((a, b) => b.length - a.length).slice(0, 3);
|
|
5313
|
+
return cand;
|
|
5314
|
+
})();
|
|
5315
|
+
if (consoleInline.length > 0) {
|
|
5316
|
+
out.push(ansi.dim(" Console errors:"), ...consoleInline.map((ln) => ` ${ln}`), "");
|
|
5317
|
+
}
|
|
5318
|
+
if (ctx.showStacks && fns.buildStackSection && stackPreview.length === 0) {
|
|
5319
|
+
const collapsed = collapseStacks(ch.lines.slice(0));
|
|
5320
|
+
out.push(...fns.buildStackSection(collapsed, ctx));
|
|
5321
|
+
}
|
|
5322
|
+
out.push(fns.drawFailLine(), "");
|
|
5323
|
+
if (rel) {
|
|
5324
|
+
seenFailures.add(`${rel}|${ch.title}`);
|
|
4807
5325
|
}
|
|
4808
|
-
lineIndex += 1;
|
|
4809
5326
|
continue;
|
|
4810
5327
|
}
|
|
4811
|
-
if (
|
|
4812
|
-
out.push(
|
|
4813
|
-
lineIndex += 1;
|
|
5328
|
+
if (ch.tag === "Summary") {
|
|
5329
|
+
out.push(ch.line);
|
|
4814
5330
|
continue;
|
|
4815
5331
|
}
|
|
4816
|
-
if (
|
|
4817
|
-
if (showStacks) {
|
|
4818
|
-
|
|
4819
|
-
out.push(...kept);
|
|
5332
|
+
if (ch.tag === "Stack") {
|
|
5333
|
+
if (ctx.showStacks) {
|
|
5334
|
+
out.push(ch.line);
|
|
4820
5335
|
}
|
|
4821
|
-
lineIndex += 1;
|
|
4822
5336
|
continue;
|
|
4823
5337
|
}
|
|
4824
|
-
|
|
4825
|
-
|
|
5338
|
+
if (!onlyFailures) {
|
|
5339
|
+
out.push(ch.line);
|
|
5340
|
+
}
|
|
4826
5341
|
}
|
|
4827
|
-
const
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
5342
|
+
const hadParsed = seenFiles.size > 0 || seenFailures.size > 0 || out.some((lineText) => /^(?:\s*)(PASS|FAIL)\b/.test(stripAnsiSimple(lineText)));
|
|
5343
|
+
return { text: out.join("\n"), hadParsed };
|
|
5344
|
+
};
|
|
5345
|
+
|
|
5346
|
+
// src/lib/formatter/context.ts
|
|
5347
|
+
var fs5 = __toESM(require("node:fs"), 1);
|
|
5348
|
+
var makeCtx = (opts, showStacks = false) => {
|
|
5349
|
+
const cwd = (opts?.cwd ?? process.cwd()).replace(/\\/g, "/");
|
|
5350
|
+
const width = Math.max(
|
|
5351
|
+
40,
|
|
5352
|
+
process.stdout && process.stdout.columns || 80
|
|
5353
|
+
);
|
|
5354
|
+
const projectHint = new RegExp(
|
|
5355
|
+
`(${cwd.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})|(/gigworx-node/)`
|
|
5356
|
+
);
|
|
5357
|
+
const readSource2 = (file) => {
|
|
5358
|
+
try {
|
|
5359
|
+
return fs5.readFileSync(file.replace(/\\/g, "/"), "utf8").split(/\r?\n/);
|
|
5360
|
+
} catch {
|
|
5361
|
+
return [];
|
|
5362
|
+
}
|
|
5363
|
+
};
|
|
5364
|
+
return { cwd, width, showStacks, projectHint, editorCmd: opts?.editorCmd, readSource: readSource2 };
|
|
5365
|
+
};
|
|
5366
|
+
|
|
5367
|
+
// src/lib/formatter/bridge.ts
|
|
5368
|
+
var fs6 = __toESM(require("node:fs"), 1);
|
|
5369
|
+
var path10 = __toESM(require("node:path"), 1);
|
|
5370
|
+
var import_json52 = __toESM(require_lib(), 1);
|
|
5371
|
+
var colorTokens2 = {
|
|
5372
|
+
pass: Colors.Success,
|
|
5373
|
+
fail: Colors.Failure,
|
|
5374
|
+
skip: Colors.Skip,
|
|
5375
|
+
todo: Colors.Todo,
|
|
5376
|
+
passPill: (text) => BackgroundColors.Success(ansi.white(` ${text} `)),
|
|
5377
|
+
failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `))
|
|
5378
|
+
};
|
|
5379
|
+
var by = (keySelector) => (left, right) => keySelector(left) - keySelector(right);
|
|
5380
|
+
var isObject = (candidateValue) => !!candidateValue && typeof candidateValue === "object";
|
|
5381
|
+
var asHttpList = (candidateValue) => Array.isArray(candidateValue) ? candidateValue : [];
|
|
5382
|
+
var summarizeUrl = (method, url, route) => {
|
|
5383
|
+
const base = route || url || "";
|
|
5384
|
+
const qs = url && url.includes("?") ? ` ? ${url.split("?")[1]}` : "";
|
|
5385
|
+
return [method || "", base, qs].filter(Boolean).join(" ").trim();
|
|
5386
|
+
};
|
|
5387
|
+
var stripBridgeEventsFromConsole = (maybeConsole) => {
|
|
5388
|
+
if (!Array.isArray(maybeConsole)) {
|
|
5389
|
+
return maybeConsole;
|
|
5390
|
+
}
|
|
5391
|
+
return maybeConsole.filter((entry) => {
|
|
5392
|
+
try {
|
|
5393
|
+
const raw = Array.isArray(entry.message) ? entry.message.map(String).join(" ") : String(entry.message ?? "");
|
|
5394
|
+
return !raw.includes("[JEST-BRIDGE-EVENT]");
|
|
5395
|
+
} catch {
|
|
5396
|
+
return true;
|
|
4841
5397
|
}
|
|
5398
|
+
});
|
|
5399
|
+
};
|
|
5400
|
+
var extractBridgePath2 = (raw, cwd) => {
|
|
5401
|
+
const matches = Array.from(
|
|
5402
|
+
raw.matchAll(/Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g)
|
|
5403
|
+
);
|
|
5404
|
+
if (!matches.length) {
|
|
5405
|
+
return null;
|
|
4842
5406
|
}
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5407
|
+
const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["'`]|["'`]$/g, "");
|
|
5408
|
+
return path10.isAbsolute(jsonPath) ? jsonPath : path10.resolve(cwd, jsonPath).replace(/\\/g, "/");
|
|
5409
|
+
};
|
|
5410
|
+
var isTransportError = (msg) => {
|
|
5411
|
+
const lowercaseMessage = (msg ?? "").toLowerCase();
|
|
5412
|
+
return /\bsocket hang up\b|\beconnreset\b|\betimedout\b|\beconnrefused\b|\bwrite epipe\b/.test(
|
|
5413
|
+
lowercaseMessage
|
|
5414
|
+
);
|
|
5415
|
+
};
|
|
5416
|
+
var envNumber = (name, fallback) => {
|
|
5417
|
+
const parsed = Number(process.env[name]);
|
|
5418
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
5419
|
+
};
|
|
5420
|
+
var HEADLAMP_HTTP_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_WINDOW_MS", 3e3);
|
|
5421
|
+
var HEADLAMP_HTTP_STRICT_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_STRICT_WINDOW_MS", 600);
|
|
5422
|
+
var HEADLAMP_HTTP_MIN_SCORE = () => envNumber("HEADLAMP_HTTP_MIN_SCORE", 1200);
|
|
5423
|
+
var HEADLAMP_HTTP_DIFF_LIMIT = () => envNumber("HEADLAMP_HTTP_DIFF_LIMIT", 6);
|
|
5424
|
+
var HEADLAMP_HTTP_SHOW_MISS = () => process.env.HEADLAMP_HTTP_MISS === "1";
|
|
5425
|
+
var eventsNear = (http, ts, testPath, windowMs = HEADLAMP_HTTP_WINDOW_MS()) => {
|
|
5426
|
+
if (typeof ts !== "number" || !Number.isFinite(ts)) {
|
|
5427
|
+
return [];
|
|
5428
|
+
}
|
|
5429
|
+
return http.filter((e) => {
|
|
5430
|
+
const timeOk = typeof e.timestampMs === "number" && Math.abs(e.timestampMs - ts) <= windowMs;
|
|
5431
|
+
const pathOk = !testPath || e.testPath === testPath;
|
|
5432
|
+
return timeOk && pathOk;
|
|
5433
|
+
});
|
|
5434
|
+
};
|
|
5435
|
+
var parseMethodPathFromTitle = (title) => {
|
|
5436
|
+
if (!title) {
|
|
5437
|
+
return {};
|
|
5438
|
+
}
|
|
5439
|
+
const matchResult = title.match(/\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+([^\s)]+)/i);
|
|
5440
|
+
return matchResult ? { method: matchResult[1]?.toUpperCase(), path: matchResult[2] } : {};
|
|
5441
|
+
};
|
|
5442
|
+
var isHttpStatusNumber = (statusNumber) => typeof statusNumber === "number" && statusNumber >= 100 && statusNumber <= 599;
|
|
5443
|
+
var hasStatusSemantics = (assertionLike) => {
|
|
5444
|
+
if (!assertionLike) {
|
|
5445
|
+
return false;
|
|
5446
|
+
}
|
|
5447
|
+
if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
|
|
5448
|
+
return true;
|
|
4848
5449
|
}
|
|
4849
|
-
|
|
5450
|
+
const combinedRaw = `${assertionLike.matcher ?? ""} ${assertionLike.message ?? ""}`;
|
|
5451
|
+
const combinedMessage = combinedRaw.toLowerCase();
|
|
5452
|
+
return /\bstatus(code)?\b|\btohaves(tatus|tatuscode)\b/.test(combinedMessage);
|
|
4850
5453
|
};
|
|
4851
|
-
var
|
|
4852
|
-
|
|
4853
|
-
|
|
5454
|
+
var fileSuggestsHttp = (relPath2) => /(?:^|\/)(routes?|api|controllers?|e2e|integration)(?:\/|\.test\.)/i.test(relPath2);
|
|
5455
|
+
var inferHttpNumbersFromText = (lines) => {
|
|
5456
|
+
const text = lines.join("\n");
|
|
5457
|
+
const match = text.match(/Expected:\s*(\d{3})[\s\S]*?Received:\s*(\d{3})/i);
|
|
5458
|
+
if (match) {
|
|
5459
|
+
return { expectedNumber: Number(match[1]), receivedNumber: Number(match[2]) };
|
|
5460
|
+
}
|
|
5461
|
+
return {};
|
|
5462
|
+
};
|
|
5463
|
+
var titleSuggestsHttp = (title) => {
|
|
5464
|
+
const { method, path: parsedPath } = parseMethodPathFromTitle(title);
|
|
5465
|
+
return Boolean(method || parsedPath && parsedPath.startsWith("/"));
|
|
5466
|
+
};
|
|
5467
|
+
var isHttpRelevant = (ctx) => {
|
|
5468
|
+
const assertionCtx = ctx.assertion;
|
|
5469
|
+
return ctx.hasTransportSignal || ctx.httpCountInSameTest > 0 || titleSuggestsHttp(ctx.title) || hasStatusSemantics(assertionCtx) || fileSuggestsHttp(ctx.relPath);
|
|
5470
|
+
};
|
|
5471
|
+
var routeSimilarityScore = (hint, evt) => {
|
|
5472
|
+
if (!hint.path && !hint.method) {
|
|
5473
|
+
return 0;
|
|
5474
|
+
}
|
|
5475
|
+
const methodOk = hint.method && evt.method ? Number(hint.method === evt.method) : 0;
|
|
5476
|
+
const route = evt.route || evt.url || "";
|
|
5477
|
+
if (!route) {
|
|
5478
|
+
return methodOk * 10;
|
|
5479
|
+
}
|
|
5480
|
+
if (hint.path && route === hint.path) {
|
|
5481
|
+
return 500 + methodOk * 50;
|
|
5482
|
+
}
|
|
5483
|
+
if (hint.path && route.endsWith(hint.path)) {
|
|
5484
|
+
return 300 + methodOk * 50;
|
|
5485
|
+
}
|
|
5486
|
+
if (hint.path && route.includes(hint.path)) {
|
|
5487
|
+
return 200 + methodOk * 50;
|
|
5488
|
+
}
|
|
5489
|
+
return methodOk * 10;
|
|
5490
|
+
};
|
|
5491
|
+
var scoreHttpForAssertion = (assertion, titleHint) => (candidateEvent) => {
|
|
5492
|
+
const tsA = assertion.timestampMs;
|
|
5493
|
+
const tsH = candidateEvent.timestampMs;
|
|
5494
|
+
const window = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
|
|
5495
|
+
const timeScore = typeof tsA === "number" && typeof tsH === "number" ? Math.max(0, window - Math.abs(tsA - tsH)) : 0;
|
|
5496
|
+
const statusScore = typeof assertion.receivedNumber === "number" && candidateEvent.statusCode === assertion.receivedNumber ? 1500 : typeof assertion.expectedNumber === "number" && candidateEvent.statusCode === assertion.expectedNumber ? 1200 : (candidateEvent.statusCode ?? 0) >= 400 ? 800 : 0;
|
|
5497
|
+
const routeScore = routeSimilarityScore(titleHint, candidateEvent);
|
|
5498
|
+
const specificity = candidateEvent.route ? 80 : candidateEvent.url ? 40 : 0;
|
|
5499
|
+
return timeScore + statusScore + routeScore + specificity;
|
|
5500
|
+
};
|
|
5501
|
+
var pickRelevantHttp = (assertion, http, ctx) => {
|
|
5502
|
+
const hint = parseMethodPathFromTitle(ctx.title);
|
|
5503
|
+
const nameMatches = (leftName, rightName) => !!leftName && !!rightName && (leftName === rightName || leftName.includes(rightName) || rightName.includes(leftName));
|
|
5504
|
+
const sameTest = (leftCtx, rightCtx) => !!leftCtx && !!rightCtx && leftCtx.testPath === rightCtx.testPath && nameMatches(leftCtx.currentTestName, rightCtx.currentTestName);
|
|
5505
|
+
const strictPool = http.filter(
|
|
5506
|
+
(httpEvent) => sameTest(assertion, httpEvent) || sameTest(ctx, httpEvent)
|
|
5507
|
+
);
|
|
5508
|
+
const windowMs = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
|
|
5509
|
+
let pool = strictPool;
|
|
5510
|
+
if (!pool.length) {
|
|
5511
|
+
pool = http.filter(
|
|
5512
|
+
(e) => e.testPath === ctx.testPath && typeof assertion.timestampMs === "number" && typeof e.timestampMs === "number" && Math.abs(e.timestampMs - assertion.timestampMs) <= windowMs
|
|
5513
|
+
);
|
|
5514
|
+
}
|
|
5515
|
+
if (!pool.length) {
|
|
5516
|
+
pool = http.filter(
|
|
5517
|
+
(e) => typeof assertion.timestampMs === "number" && typeof e.timestampMs === "number" && Math.abs(e.timestampMs - assertion.timestampMs) <= windowMs
|
|
5518
|
+
);
|
|
5519
|
+
}
|
|
5520
|
+
if (!pool.length) {
|
|
5521
|
+
return void 0;
|
|
5522
|
+
}
|
|
5523
|
+
const scored = pool.map((httpEvent) => ({ h: httpEvent, s: scoreHttpForAssertion(assertion, hint)(httpEvent) })).sort((leftScore, rightScore) => rightScore.s - leftScore.s);
|
|
5524
|
+
const [best] = scored;
|
|
5525
|
+
const threshold = isTransportError(assertion.message) ? Math.max(HEADLAMP_HTTP_MIN_SCORE(), 1400) : HEADLAMP_HTTP_MIN_SCORE();
|
|
5526
|
+
return best && best.s >= threshold ? best.h : void 0;
|
|
4854
5527
|
};
|
|
4855
|
-
|
|
5528
|
+
var isBridgeJSONLike = (candidateValue) => !!candidateValue && typeof candidateValue === "object" && "aggregated" in candidateValue;
|
|
5529
|
+
var coerceJestJsonToBridge = (raw) => {
|
|
4856
5530
|
if (isBridgeJSONLike(raw)) {
|
|
4857
5531
|
return raw;
|
|
4858
5532
|
}
|
|
@@ -4862,18 +5536,21 @@ function coerceJestJsonToBridge(raw) {
|
|
|
4862
5536
|
}
|
|
4863
5537
|
return {
|
|
4864
5538
|
startTime: Number(j.startTime ?? Date.now()),
|
|
4865
|
-
testResults: j.testResults.map((
|
|
4866
|
-
testFilePath:
|
|
4867
|
-
status:
|
|
4868
|
-
failureMessage:
|
|
4869
|
-
failureDetails:
|
|
4870
|
-
|
|
5539
|
+
testResults: j.testResults.map((tr) => ({
|
|
5540
|
+
testFilePath: tr.testFilePath || tr.name || "",
|
|
5541
|
+
status: tr.status,
|
|
5542
|
+
failureMessage: tr.failureMessage || "",
|
|
5543
|
+
failureDetails: tr.failureDetails ?? [],
|
|
5544
|
+
testExecError: tr.testExecError ?? null,
|
|
5545
|
+
console: tr.console ?? null,
|
|
5546
|
+
testResults: (tr.assertionResults || []).map((assertion) => ({
|
|
4871
5547
|
title: assertion.title,
|
|
4872
5548
|
fullName: assertion.fullName || [...assertion.ancestorTitles || [], assertion.title].join(" "),
|
|
4873
5549
|
status: assertion.status,
|
|
4874
5550
|
duration: assertion.duration || 0,
|
|
4875
5551
|
location: assertion.location ?? null,
|
|
4876
|
-
failureMessages: assertion.failureMessages || []
|
|
5552
|
+
failureMessages: assertion.failureMessages || [],
|
|
5553
|
+
failureDetails: assertion.failureDetails || []
|
|
4877
5554
|
}))
|
|
4878
5555
|
})),
|
|
4879
5556
|
aggregated: {
|
|
@@ -4889,21 +5566,20 @@ function coerceJestJsonToBridge(raw) {
|
|
|
4889
5566
|
success: j.success
|
|
4890
5567
|
}
|
|
4891
5568
|
};
|
|
4892
|
-
}
|
|
4893
|
-
var vitestFooter = (agg,
|
|
5569
|
+
};
|
|
5570
|
+
var vitestFooter = (agg, durationMs) => {
|
|
4894
5571
|
const files = [
|
|
4895
|
-
agg.numFailedTestSuites ?
|
|
4896
|
-
agg.numPassedTestSuites ?
|
|
4897
|
-
agg.numPendingTests ?
|
|
5572
|
+
agg.numFailedTestSuites ? colorTokens2.fail(`${agg.numFailedTestSuites} failed`) : "",
|
|
5573
|
+
agg.numPassedTestSuites ? colorTokens2.pass(`${agg.numPassedTestSuites} passed`) : "",
|
|
5574
|
+
agg.numPendingTests ? colorTokens2.skip(`${agg.numPendingTests} skipped`) : ""
|
|
4898
5575
|
].filter(Boolean).join(ansi.dim(" | "));
|
|
4899
5576
|
const tests = [
|
|
4900
|
-
agg.numFailedTests ?
|
|
4901
|
-
agg.numPassedTests ?
|
|
4902
|
-
agg.numPendingTests ?
|
|
4903
|
-
agg.numTodoTests ?
|
|
5577
|
+
agg.numFailedTests ? colorTokens2.fail(`${agg.numFailedTests} failed`) : "",
|
|
5578
|
+
agg.numPassedTests ? colorTokens2.pass(`${agg.numPassedTests} passed`) : "",
|
|
5579
|
+
agg.numPendingTests ? colorTokens2.skip(`${agg.numPendingTests} skipped`) : "",
|
|
5580
|
+
agg.numTodoTests ? colorTokens2.todo(`${agg.numTodoTests} todo`) : ""
|
|
4904
5581
|
].filter(Boolean).join(ansi.dim(" | "));
|
|
4905
|
-
const
|
|
4906
|
-
const time = durMs != null ? `${Math.max(0, Math.round(durMs))}ms` : "";
|
|
5582
|
+
const time = durationMs != null ? `${Math.max(0, Math.round(durationMs))}ms` : typeof agg.runTimeMs === "number" ? `${Math.max(0, Math.round(agg.runTimeMs))}ms` : "";
|
|
4907
5583
|
const thread = ansi.dim("(in thread 0ms, 0.00%)");
|
|
4908
5584
|
return [
|
|
4909
5585
|
`${ansi.bold("Test Files")} ${files} ${ansi.dim(`(${agg.numTotalTestSuites})`)}`,
|
|
@@ -4911,20 +5587,14 @@ var vitestFooter = (agg, _startedAt, durationMs) => {
|
|
|
4911
5587
|
`${ansi.bold("Time")} ${time} ${thread}`
|
|
4912
5588
|
].join("\n");
|
|
4913
5589
|
};
|
|
4914
|
-
|
|
4915
|
-
const cwd = (opts?.cwd ?? process.cwd()).replace(/\\/g, "/");
|
|
4916
|
-
const projectHint = new RegExp(
|
|
4917
|
-
`(${cwd.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})|(/gigworx-node/)`
|
|
4918
|
-
);
|
|
4919
|
-
const ctx = { projectHint, editorCmd: opts?.editorCmd, showStacks: true };
|
|
4920
|
-
const onlyFailures = Boolean(opts?.onlyFailures);
|
|
5590
|
+
var renderVitestFromJestJSON = (data, ctx, opts) => {
|
|
4921
5591
|
const out = [];
|
|
5592
|
+
const onlyFailures = Boolean(opts?.onlyFailures);
|
|
4922
5593
|
if (!onlyFailures) {
|
|
4923
|
-
out.push(
|
|
4924
|
-
out.push("");
|
|
5594
|
+
out.push(`${BackgroundColors.Run(ansi.white(" RUN "))} ${ansi.dim(ctx.cwd)}`, "");
|
|
4925
5595
|
}
|
|
4926
5596
|
for (const file of data.testResults) {
|
|
4927
|
-
const rel = file.testFilePath.replace(/\\/g, "/").replace(`${cwd}/`, "");
|
|
5597
|
+
const rel = file.testFilePath.replace(/\\/g, "/").replace(`${ctx.cwd}/`, "");
|
|
4928
5598
|
const failed = file.testResults.filter((assertion) => assertion.status === "failed");
|
|
4929
5599
|
if (!onlyFailures) {
|
|
4930
5600
|
out.push(...buildPerFileOverview(rel, file.testResults));
|
|
@@ -4932,79 +5602,490 @@ function renderVitestFromJestJSON(data, opts) {
|
|
|
4932
5602
|
if (!(onlyFailures && failed.length === 0)) {
|
|
4933
5603
|
out.push(buildFileBadgeLine(rel, failed.length));
|
|
4934
5604
|
}
|
|
4935
|
-
|
|
5605
|
+
let httpSorted = [];
|
|
5606
|
+
let assertionEvents = [];
|
|
5607
|
+
{
|
|
5608
|
+
const parseBridge = (consoleEntries) => {
|
|
5609
|
+
const http = [];
|
|
5610
|
+
const assertions = [];
|
|
5611
|
+
if (!Array.isArray(consoleEntries)) {
|
|
5612
|
+
return { http, assertions };
|
|
5613
|
+
}
|
|
5614
|
+
for (const entry of consoleEntries) {
|
|
5615
|
+
const rec = entry;
|
|
5616
|
+
const rawMsgVal = rec && typeof rec.message !== "undefined" ? rec.message : "";
|
|
5617
|
+
const raw = Array.isArray(rawMsgVal) ? rawMsgVal.map(String).join(" ") : String(rawMsgVal ?? "");
|
|
5618
|
+
if (!raw.includes("[JEST-BRIDGE-EVENT]")) {
|
|
5619
|
+
continue;
|
|
5620
|
+
}
|
|
5621
|
+
const jsonText = raw.split("[JEST-BRIDGE-EVENT]").pop()?.trim() ?? "";
|
|
5622
|
+
try {
|
|
5623
|
+
const evt = import_json52.default.parse(jsonText);
|
|
5624
|
+
const type = evt?.type;
|
|
5625
|
+
if (type === "httpResponse") {
|
|
5626
|
+
const timestampMs = Number(evt.timestampMs ?? Date.now());
|
|
5627
|
+
http.push({
|
|
5628
|
+
kind: "response",
|
|
5629
|
+
timestampMs,
|
|
5630
|
+
method: evt.method,
|
|
5631
|
+
url: evt.url,
|
|
5632
|
+
route: evt.route,
|
|
5633
|
+
statusCode: evt.statusCode,
|
|
5634
|
+
durationMs: evt.durationMs,
|
|
5635
|
+
contentType: evt.contentType,
|
|
5636
|
+
requestId: evt.requestId,
|
|
5637
|
+
json: evt.json,
|
|
5638
|
+
bodyPreview: evt.bodyPreview,
|
|
5639
|
+
testPath: evt.testPath,
|
|
5640
|
+
currentTestName: evt.currentTestName
|
|
5641
|
+
});
|
|
5642
|
+
} else if (type === "httpAbort") {
|
|
5643
|
+
http.push({
|
|
5644
|
+
kind: "abort",
|
|
5645
|
+
timestampMs: Number(evt.timestampMs ?? Date.now()),
|
|
5646
|
+
method: evt.method,
|
|
5647
|
+
url: evt.url,
|
|
5648
|
+
route: evt.route,
|
|
5649
|
+
durationMs: evt.durationMs,
|
|
5650
|
+
testPath: evt.testPath,
|
|
5651
|
+
currentTestName: evt.currentTestName
|
|
5652
|
+
});
|
|
5653
|
+
} else if (type === "httpResponseBatch") {
|
|
5654
|
+
const list = asHttpList(evt?.events);
|
|
5655
|
+
for (const item of list) {
|
|
5656
|
+
const anyItem = item;
|
|
5657
|
+
http.push({
|
|
5658
|
+
timestampMs: Number(anyItem.timestampMs ?? Date.now()),
|
|
5659
|
+
method: anyItem.method,
|
|
5660
|
+
url: anyItem.url,
|
|
5661
|
+
route: anyItem.route,
|
|
5662
|
+
statusCode: anyItem.statusCode,
|
|
5663
|
+
durationMs: anyItem.durationMs,
|
|
5664
|
+
contentType: anyItem.contentType,
|
|
5665
|
+
requestId: anyItem.requestId,
|
|
5666
|
+
json: anyItem.json,
|
|
5667
|
+
bodyPreview: anyItem.bodyPreview,
|
|
5668
|
+
testPath: evt.testPath,
|
|
5669
|
+
currentTestName: evt.currentTestName
|
|
5670
|
+
});
|
|
5671
|
+
}
|
|
5672
|
+
} else if (type === "assertionFailure") {
|
|
5673
|
+
assertions.push({
|
|
5674
|
+
timestampMs: typeof evt.timestampMs === "number" ? evt.timestampMs : void 0,
|
|
5675
|
+
matcher: evt.matcher,
|
|
5676
|
+
expectedNumber: typeof evt.expectedNumber === "number" ? evt.expectedNumber : void 0,
|
|
5677
|
+
receivedNumber: typeof evt.receivedNumber === "number" ? evt.receivedNumber : void 0,
|
|
5678
|
+
message: typeof evt.message === "string" ? evt.message : void 0,
|
|
5679
|
+
stack: typeof evt.stack === "string" ? evt.stack : void 0,
|
|
5680
|
+
testPath: evt.testPath,
|
|
5681
|
+
currentTestName: evt.currentTestName,
|
|
5682
|
+
expectedPreview: typeof evt.expectedPreview === "string" ? evt.expectedPreview : void 0,
|
|
5683
|
+
actualPreview: typeof evt.actualPreview === "string" ? evt.actualPreview : void 0
|
|
5684
|
+
});
|
|
5685
|
+
}
|
|
5686
|
+
} catch {
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
return { http, assertions };
|
|
5690
|
+
};
|
|
5691
|
+
const parsed = parseBridge(file.console);
|
|
5692
|
+
httpSorted = [...parsed.http].sort(by((event) => event.timestampMs));
|
|
5693
|
+
assertionEvents = parsed.assertions;
|
|
5694
|
+
}
|
|
5695
|
+
const inSameCtx = (testPath, testName) => httpSorted.filter(
|
|
5696
|
+
(event) => event.testPath === testPath && event.currentTestName === testName
|
|
5697
|
+
);
|
|
5698
|
+
if (file.failureMessage || file.testExecError) {
|
|
4936
5699
|
const lines = file.failureMessage.split(/\r?\n/);
|
|
4937
|
-
const
|
|
4938
|
-
|
|
4939
|
-
|
|
5700
|
+
const combinedDetails = (() => {
|
|
5701
|
+
const base = linesFromDetails(file.failureDetails);
|
|
5702
|
+
const exec = linesFromDetails(
|
|
5703
|
+
Array.isArray(file.testExecError) ? file.testExecError : [file.testExecError]
|
|
5704
|
+
);
|
|
5705
|
+
return {
|
|
5706
|
+
stacks: [...base.stacks, ...exec.stacks],
|
|
5707
|
+
messages: [...base.messages, ...exec.messages]
|
|
5708
|
+
};
|
|
5709
|
+
})();
|
|
5710
|
+
const mergedForStack = collapseStacks([...lines, ...combinedDetails.stacks]);
|
|
5711
|
+
const synthLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
4940
5712
|
out.push(...buildCodeFrameSection(lines, ctx, synthLoc));
|
|
4941
|
-
const
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
const stackPreview = ctx.showStacks ?
|
|
5713
|
+
const payloadPretty = buildPrettyDiffSection(file.failureDetails, lines);
|
|
5714
|
+
out.push(...payloadPretty);
|
|
5715
|
+
const hasPretty = payloadPretty.length > 0;
|
|
5716
|
+
const stackPreview = ctx.showStacks ? mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).filter((ln) => ctx.projectHint.test(stripAnsiSimple(ln))).slice(0, 2).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`) : [];
|
|
4945
5717
|
out.push(
|
|
4946
|
-
...buildMessageSection(lines,
|
|
5718
|
+
...buildMessageSection(lines, combinedDetails, ctx, {
|
|
4947
5719
|
suppressDiff: hasPretty,
|
|
4948
5720
|
stackPreview
|
|
4949
5721
|
})
|
|
4950
5722
|
);
|
|
4951
|
-
out.push(...buildConsoleSection(file.console ?? null));
|
|
5723
|
+
out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
|
|
4952
5724
|
if (ctx.showStacks && stackPreview.length === 0) {
|
|
4953
|
-
|
|
5725
|
+
const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
|
|
5726
|
+
if (tail.length) {
|
|
5727
|
+
out.push(ansi.dim(" Stack:"), ...tail, "");
|
|
5728
|
+
}
|
|
4954
5729
|
}
|
|
4955
5730
|
}
|
|
4956
|
-
for (const
|
|
5731
|
+
for (const assertion of failed) {
|
|
4957
5732
|
out.push(drawFailLine());
|
|
4958
|
-
const header = `${rel} > ${
|
|
4959
|
-
const messagesArray =
|
|
4960
|
-
|
|
5733
|
+
const header = `${rel} > ${assertion.fullName}`;
|
|
5734
|
+
const messagesArray = (() => {
|
|
5735
|
+
if (assertion.failureMessages && assertion.failureMessages.length > 0) {
|
|
5736
|
+
return assertion.failureMessages;
|
|
5737
|
+
}
|
|
5738
|
+
if (file.failureMessage && file.failureMessage.trim().length > 0) {
|
|
5739
|
+
return file.failureMessage.split(/\r?\n/);
|
|
5740
|
+
}
|
|
5741
|
+
const linesFromMatcher = linesFromDetails(
|
|
5742
|
+
assertion.failureDetails || file.failureDetails
|
|
5743
|
+
).messages;
|
|
5744
|
+
if (Array.isArray(linesFromMatcher) && linesFromMatcher.length > 0) {
|
|
5745
|
+
return linesFromMatcher;
|
|
5746
|
+
}
|
|
5747
|
+
return [""];
|
|
5748
|
+
})();
|
|
5749
|
+
const details = linesFromDetails(assertion.failureDetails || file.failureDetails);
|
|
5750
|
+
const matcherMsg = (() => {
|
|
5751
|
+
try {
|
|
5752
|
+
const arr = assertion.failureDetails || file.failureDetails;
|
|
5753
|
+
if (!arr) {
|
|
5754
|
+
return [];
|
|
5755
|
+
}
|
|
5756
|
+
for (const detailEntry of arr) {
|
|
5757
|
+
const obj = detailEntry && typeof detailEntry === "object" ? detailEntry : null;
|
|
5758
|
+
const mr = obj && obj.matcherResult && typeof obj.matcherResult === "object" ? obj.matcherResult : null;
|
|
5759
|
+
if (mr && typeof mr.message === "string" && mr.message.trim()) {
|
|
5760
|
+
const name = typeof mr.matcherName === "string" ? mr.matcherName : "";
|
|
5761
|
+
const matcherHeader = name ? ` ${ansi.bold("Matcher:")} ${ansi.yellow(name)}` : "";
|
|
5762
|
+
const bodyHeader = ` ${ansi.bold("Message:")}`;
|
|
5763
|
+
const body = String(mr.message).split(/\r?\n/).slice(0, 6).map((ln) => ` ${ansi.yellow(ln)}`);
|
|
5764
|
+
return [matcherHeader, bodyHeader, ...body, ""].filter(Boolean);
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
} catch {
|
|
5768
|
+
}
|
|
5769
|
+
return [];
|
|
5770
|
+
})();
|
|
4961
5771
|
const mergedForStack = collapseStacks([...messagesArray, ...details.stacks]);
|
|
4962
|
-
const deepestLoc = deepestProjectLoc(mergedForStack, projectHint);
|
|
4963
|
-
const locLink = deepestLoc
|
|
4964
|
-
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line,
|
|
4965
|
-
const base = `${
|
|
5772
|
+
const deepestLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
5773
|
+
const locLink = deepestLoc ? (() => {
|
|
5774
|
+
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, ctx.editorCmd);
|
|
5775
|
+
const base = `${deepestLoc.file.split("/").pop()}:${deepestLoc.line}`;
|
|
4966
5776
|
return osc8(base, href);
|
|
4967
|
-
})();
|
|
5777
|
+
})() : void 0;
|
|
5778
|
+
const bullet = (text) => `${Colors.Failure("\xD7")} ${ansi.white(text)}`;
|
|
4968
5779
|
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
4969
|
-
const bullet = (text) => `${colorTokens.fail("\xD7")} ${ansi.white(text)}`;
|
|
4970
5780
|
out.push(bullet(headerLine));
|
|
4971
5781
|
const msgLines = messagesArray.join("\n").split("\n");
|
|
4972
|
-
const assertFallback = deepestLoc ||
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
const stackPreview = ctx.showStacks ?
|
|
5782
|
+
const assertFallback = deepestLoc || assertion.location && { file: file.testFilePath, line: assertion.location.line };
|
|
5783
|
+
out.push("", ...buildCodeFrameSection(msgLines, ctx, assertFallback || void 0), "");
|
|
5784
|
+
const pretty = buildPrettyDiffSection(
|
|
5785
|
+
assertion.failureDetails || file.failureDetails,
|
|
5786
|
+
msgLines
|
|
5787
|
+
);
|
|
5788
|
+
out.push(...pretty);
|
|
5789
|
+
const hasPretty = pretty.length > 0;
|
|
5790
|
+
const stackPreview = ctx.showStacks ? mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).filter((ln) => ctx.projectHint.test(stripAnsiSimple(ln))).slice(0, 2).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`) : [];
|
|
5791
|
+
if (matcherMsg.length) {
|
|
5792
|
+
out.push(...matcherMsg);
|
|
5793
|
+
}
|
|
4981
5794
|
out.push(
|
|
4982
5795
|
...buildMessageSection(msgLines, details, ctx, { suppressDiff: hasPretty, stackPreview })
|
|
4983
5796
|
);
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
5797
|
+
{
|
|
5798
|
+
const HEADLAMP_HTTP_DIFF_LIMIT_LOCAL = () => HEADLAMP_HTTP_DIFF_LIMIT();
|
|
5799
|
+
const safeParseJSON = (text) => {
|
|
5800
|
+
try {
|
|
5801
|
+
return text ? import_json52.default.parse(text) : void 0;
|
|
5802
|
+
} catch {
|
|
5803
|
+
return void 0;
|
|
5804
|
+
}
|
|
5805
|
+
};
|
|
5806
|
+
const jsonDiff = (expected, actual, limit = HEADLAMP_HTTP_DIFF_LIMIT_LOCAL()) => {
|
|
5807
|
+
const outChanges = [];
|
|
5808
|
+
const queue = [];
|
|
5809
|
+
queue.push({
|
|
5810
|
+
pathSoFar: "$",
|
|
5811
|
+
expectedValue: expected,
|
|
5812
|
+
actualValue: actual
|
|
5813
|
+
});
|
|
5814
|
+
while (queue.length && outChanges.length < limit) {
|
|
5815
|
+
const { pathSoFar, expectedValue, actualValue } = queue.shift();
|
|
5816
|
+
const expectedIsObj = expectedValue && typeof expectedValue === "object";
|
|
5817
|
+
const actualIsObj = actualValue && typeof actualValue === "object";
|
|
5818
|
+
if (!expectedIsObj && !actualIsObj) {
|
|
5819
|
+
if (JSON.stringify(expectedValue) !== JSON.stringify(actualValue)) {
|
|
5820
|
+
outChanges.push({
|
|
5821
|
+
kind: "changed",
|
|
5822
|
+
path: pathSoFar,
|
|
5823
|
+
preview: `${String(expectedValue)} \u2192 ${String(actualValue)}`
|
|
5824
|
+
});
|
|
5825
|
+
}
|
|
5826
|
+
} else if (expectedIsObj && !actualIsObj) {
|
|
5827
|
+
outChanges.push({
|
|
5828
|
+
kind: "changed",
|
|
5829
|
+
path: pathSoFar,
|
|
5830
|
+
preview: "[object] \u2192 primitive"
|
|
5831
|
+
});
|
|
5832
|
+
} else if (!expectedIsObj && actualIsObj) {
|
|
5833
|
+
outChanges.push({
|
|
5834
|
+
kind: "changed",
|
|
5835
|
+
path: pathSoFar,
|
|
5836
|
+
preview: "primitive \u2192 [object]"
|
|
5837
|
+
});
|
|
5838
|
+
} else {
|
|
5839
|
+
const expectedKeys = new Set(Object.keys(expectedValue));
|
|
5840
|
+
const actualKeys = new Set(Object.keys(actualValue));
|
|
5841
|
+
for (const key of expectedKeys) {
|
|
5842
|
+
if (!actualKeys.has(key) && outChanges.length < limit) {
|
|
5843
|
+
outChanges.push({ kind: "removed", path: `${pathSoFar}.${key}` });
|
|
5844
|
+
}
|
|
5845
|
+
}
|
|
5846
|
+
for (const key of actualKeys) {
|
|
5847
|
+
if (!expectedKeys.has(key) && outChanges.length < limit) {
|
|
5848
|
+
outChanges.push({ kind: "added", path: `${pathSoFar}.${key}` });
|
|
5849
|
+
}
|
|
5850
|
+
}
|
|
5851
|
+
for (const key of expectedKeys) {
|
|
5852
|
+
if (actualKeys.has(key) && outChanges.length < limit) {
|
|
5853
|
+
queue.push({
|
|
5854
|
+
pathSoFar: `${pathSoFar}.${key}`,
|
|
5855
|
+
expectedValue: expectedValue[key],
|
|
5856
|
+
actualValue: actualValue[key]
|
|
5857
|
+
});
|
|
5858
|
+
}
|
|
5859
|
+
}
|
|
5860
|
+
}
|
|
5861
|
+
}
|
|
5862
|
+
return outChanges;
|
|
5863
|
+
};
|
|
5864
|
+
const importantMessages = (json) => {
|
|
5865
|
+
const msgs = [];
|
|
5866
|
+
try {
|
|
5867
|
+
const obj = isObject(json) ? json : {};
|
|
5868
|
+
const pushMaybe = (candidate) => {
|
|
5869
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
5870
|
+
msgs.push(candidate);
|
|
5871
|
+
}
|
|
5872
|
+
};
|
|
5873
|
+
pushMaybe(obj.displayMessage);
|
|
5874
|
+
pushMaybe(obj.message);
|
|
5875
|
+
if (Array.isArray(obj.errors)) {
|
|
5876
|
+
for (const element of obj.errors) {
|
|
5877
|
+
pushMaybe(isObject(element) ? element.message : void 0);
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
if (Array.isArray(obj.data)) {
|
|
5881
|
+
for (const element of obj.data) {
|
|
5882
|
+
pushMaybe(isObject(element) ? element.message : void 0);
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
} catch {
|
|
5886
|
+
}
|
|
5887
|
+
return msgs.slice(0, 2);
|
|
5888
|
+
};
|
|
5889
|
+
const nameMatches = (leftName, rightName) => !!leftName && !!rightName && (leftName === rightName || leftName.includes(rightName) || rightName.includes(leftName));
|
|
5890
|
+
const corresponding = assertionEvents.find(
|
|
5891
|
+
(aevt) => aevt.testPath === file.testFilePath && nameMatches(aevt.currentTestName, assertion.title)
|
|
5892
|
+
) ?? assertion;
|
|
5893
|
+
const perTestSlice = inSameCtx(file.testFilePath, assertion.title);
|
|
5894
|
+
const nearByTime = eventsNear(
|
|
5895
|
+
httpSorted,
|
|
5896
|
+
corresponding?.timestampMs,
|
|
5897
|
+
file.testFilePath
|
|
4991
5898
|
);
|
|
5899
|
+
const hasAbort = perTestSlice.some((event) => event.kind === "abort");
|
|
5900
|
+
const hasTransport = isTransportError(corresponding?.message) || hasAbort;
|
|
5901
|
+
const httpLikely = isHttpRelevant({
|
|
5902
|
+
assertion: corresponding,
|
|
5903
|
+
title: assertion.fullName,
|
|
5904
|
+
relPath: rel,
|
|
5905
|
+
httpCountInSameTest: perTestSlice.length || nearByTime.length,
|
|
5906
|
+
hasTransportSignal: hasTransport
|
|
5907
|
+
});
|
|
5908
|
+
if (!httpLikely) {
|
|
5909
|
+
} else {
|
|
5910
|
+
const expPreview = corresponding?.expectedPreview;
|
|
5911
|
+
const actPreview = corresponding?.actualPreview;
|
|
5912
|
+
const parsedExpected = safeParseJSON(expPreview);
|
|
5913
|
+
const parsedActual = safeParseJSON(actPreview);
|
|
5914
|
+
let corr = corresponding;
|
|
5915
|
+
if (!isHttpStatusNumber(corr.expectedNumber) && !isHttpStatusNumber(corr.receivedNumber)) {
|
|
5916
|
+
const inferred = inferHttpNumbersFromText(msgLines);
|
|
5917
|
+
if (isHttpStatusNumber(inferred.expectedNumber) || isHttpStatusNumber(inferred.receivedNumber)) {
|
|
5918
|
+
corr = { ...corr, ...inferred };
|
|
5919
|
+
}
|
|
5920
|
+
}
|
|
5921
|
+
const relevant = pickRelevantHttp(
|
|
5922
|
+
{
|
|
5923
|
+
timestampMs: corr?.timestampMs,
|
|
5924
|
+
expectedNumber: corr?.expectedNumber,
|
|
5925
|
+
receivedNumber: corr?.receivedNumber,
|
|
5926
|
+
matcher: corr?.matcher,
|
|
5927
|
+
message: corr?.message,
|
|
5928
|
+
stack: corr?.stack,
|
|
5929
|
+
testPath: file.testFilePath,
|
|
5930
|
+
currentTestName: assertion.title
|
|
5931
|
+
},
|
|
5932
|
+
httpSorted,
|
|
5933
|
+
{
|
|
5934
|
+
testPath: file.testFilePath,
|
|
5935
|
+
currentTestName: assertion.title,
|
|
5936
|
+
title: assertion.fullName
|
|
5937
|
+
}
|
|
5938
|
+
);
|
|
5939
|
+
if (hasTransport) {
|
|
5940
|
+
const tsBase = corresponding?.timestampMs ?? 0;
|
|
5941
|
+
const abortCandidates = perTestSlice.filter((event) => event.kind === "abort").sort((leftEvent, rightEvent) => {
|
|
5942
|
+
const deltaLeft = Math.abs(tsBase - (leftEvent.timestampMs ?? 0));
|
|
5943
|
+
const deltaRight = Math.abs(tsBase - (rightEvent.timestampMs ?? 0));
|
|
5944
|
+
return deltaLeft - deltaRight;
|
|
5945
|
+
});
|
|
5946
|
+
const [nearestAbort] = abortCandidates;
|
|
5947
|
+
if (nearestAbort) {
|
|
5948
|
+
out.push(
|
|
5949
|
+
" HTTP:",
|
|
5950
|
+
`
|
|
5951
|
+
${summarizeUrl(nearestAbort.method, nearestAbort.url, nearestAbort.route)} ${ansi.dim("->")} ${ansi.yellow("connection aborted")}`,
|
|
5952
|
+
(() => {
|
|
5953
|
+
const ms = nearestAbort.durationMs;
|
|
5954
|
+
return ms != null ? ` ${ansi.dim(`(${ms}ms)`)} ` : "";
|
|
5955
|
+
})(),
|
|
5956
|
+
"\n"
|
|
5957
|
+
);
|
|
5958
|
+
} else if (relevant) {
|
|
5959
|
+
} else if (HEADLAMP_HTTP_SHOW_MISS()) {
|
|
5960
|
+
out.push(
|
|
5961
|
+
" HTTP:",
|
|
5962
|
+
`
|
|
5963
|
+
${ansi.dim("Transport error; no matching HTTP exchange in window.")}`,
|
|
5964
|
+
"\n"
|
|
5965
|
+
);
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
if (!hasTransport && relevant) {
|
|
5969
|
+
const parts = [];
|
|
5970
|
+
const where = summarizeUrl(relevant.method, relevant.url, relevant.route);
|
|
5971
|
+
const line1 = [
|
|
5972
|
+
" HTTP:",
|
|
5973
|
+
`
|
|
5974
|
+
${where} ${ansi.dim("->")} ${relevant.statusCode ?? "?"}`,
|
|
5975
|
+
(() => {
|
|
5976
|
+
const ms = relevant.durationMs;
|
|
5977
|
+
return typeof ms === "number" ? ` ${ansi.dim(`(${ms}ms)`)} ` : " ";
|
|
5978
|
+
})(),
|
|
5979
|
+
relevant.contentType ? ansi.dim(`(${relevant.contentType})`) : "",
|
|
5980
|
+
relevant.requestId ? ansi.dim(` reqId=${relevant.requestId}`) : ""
|
|
5981
|
+
].join("");
|
|
5982
|
+
const expVsAct = (() => {
|
|
5983
|
+
if (typeof corresponding?.expectedNumber === "number" || typeof corresponding?.receivedNumber === "number") {
|
|
5984
|
+
const exp = corresponding?.expectedNumber != null ? String(corresponding.expectedNumber) : "?";
|
|
5985
|
+
const got = corresponding?.receivedNumber != null ? String(corresponding.receivedNumber) : String(relevant.statusCode ?? "?");
|
|
5986
|
+
return `
|
|
5987
|
+
Expected: ${ansi.yellow(exp)} Received: ${ansi.yellow(got)}`;
|
|
5988
|
+
}
|
|
5989
|
+
return "";
|
|
5990
|
+
})();
|
|
5991
|
+
const whyLines = importantMessages(relevant.json).map((msg) => `
|
|
5992
|
+
Why: ${ansi.white(msg)}`).slice(0, 1).join("");
|
|
5993
|
+
const diffLines = (() => {
|
|
5994
|
+
const rightActual = parsedActual ?? relevant.json;
|
|
5995
|
+
if (!parsedExpected || !rightActual) {
|
|
5996
|
+
return "";
|
|
5997
|
+
}
|
|
5998
|
+
const changes = jsonDiff(parsedExpected, rightActual);
|
|
5999
|
+
if (!changes.length) {
|
|
6000
|
+
return "";
|
|
6001
|
+
}
|
|
6002
|
+
const head = "\n Diff:";
|
|
6003
|
+
const body = changes.map((change) => {
|
|
6004
|
+
const marker = change.kind === "added" ? "+" : change.kind === "removed" ? "-" : "~";
|
|
6005
|
+
const previewText = change.preview ? `: ${ansi.dim(change.preview)}` : "";
|
|
6006
|
+
return `
|
|
6007
|
+
${marker} ${change.path}${previewText}`;
|
|
6008
|
+
}).join("");
|
|
6009
|
+
return head + body;
|
|
6010
|
+
})();
|
|
6011
|
+
parts.push(line1, expVsAct, whyLines, diffLines, "\n");
|
|
6012
|
+
out.push(...parts.filter(Boolean));
|
|
6013
|
+
} else if (!hasTransport && !relevant && HEADLAMP_HTTP_SHOW_MISS()) {
|
|
6014
|
+
out.push(
|
|
6015
|
+
" HTTP:",
|
|
6016
|
+
`
|
|
6017
|
+
${ansi.dim("No relevant HTTP exchange found. (HEADLAMP_HTTP_MISS=0 to hide)")}`,
|
|
6018
|
+
"\n"
|
|
6019
|
+
);
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
4992
6022
|
}
|
|
4993
|
-
|
|
4994
|
-
|
|
6023
|
+
const minimalInfo = msgLines.every((ln) => !ln.trim());
|
|
6024
|
+
if (minimalInfo) {
|
|
6025
|
+
try {
|
|
6026
|
+
out.push(...buildThrownSection(assertion.failureDetails || []));
|
|
6027
|
+
} catch {
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
|
|
6031
|
+
if (ctx.showStacks && stackPreview.length === 0) {
|
|
6032
|
+
const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
|
|
6033
|
+
if (tail.length) {
|
|
6034
|
+
out.push(ansi.dim(" Stack:"), ...tail, "");
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
out.push(drawFailLine(), "");
|
|
4995
6038
|
}
|
|
4996
6039
|
}
|
|
4997
6040
|
const failedCount = data.aggregated.numFailedTests;
|
|
4998
|
-
out.push(drawRule(
|
|
6041
|
+
out.push(drawRule(BackgroundColors.Failure(ansi.white(` Failed Tests ${failedCount} `))));
|
|
4999
6042
|
out.push("");
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
);
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
}
|
|
6043
|
+
out.push(vitestFooter(data.aggregated));
|
|
6044
|
+
return out.join("\n");
|
|
6045
|
+
};
|
|
6046
|
+
var tryBridgeFallback = (raw, ctx, opts) => {
|
|
6047
|
+
const bridgeJsonPath = extractBridgePath2(raw, ctx.cwd);
|
|
6048
|
+
if (!bridgeJsonPath || !fs6.existsSync(bridgeJsonPath)) {
|
|
6049
|
+
return null;
|
|
6050
|
+
}
|
|
6051
|
+
try {
|
|
6052
|
+
const json = import_json52.default.parse(fs6.readFileSync(bridgeJsonPath, "utf8"));
|
|
6053
|
+
const bridge = coerceJestJsonToBridge(json);
|
|
6054
|
+
return renderVitestFromJestJSON(bridge, ctx, opts);
|
|
6055
|
+
} catch {
|
|
6056
|
+
return null;
|
|
6057
|
+
}
|
|
6058
|
+
};
|
|
6059
|
+
|
|
6060
|
+
// src/lib/formatJestOutputVitest.ts
|
|
6061
|
+
var formatJestOutputVitest = (raw, opts) => pipe(
|
|
6062
|
+
{ raw, opts },
|
|
6063
|
+
(state) => ({
|
|
6064
|
+
...state,
|
|
6065
|
+
ctx: makeCtx(state.opts, /\bFAIL\b/.test(stripAnsiSimple(state.raw)))
|
|
6066
|
+
}),
|
|
6067
|
+
(state) => ({ ...state, chunks: parseChunks(state.raw) }),
|
|
6068
|
+
(state) => ({
|
|
6069
|
+
...state,
|
|
6070
|
+
rendered: renderChunks(state.chunks, state.ctx, mkPrettyFns(), {
|
|
6071
|
+
onlyFailures: Boolean(state.opts?.onlyFailures)
|
|
6072
|
+
})
|
|
6073
|
+
}),
|
|
6074
|
+
(state) => {
|
|
6075
|
+
if (state.rendered.hadParsed) {
|
|
6076
|
+
return state.rendered.text;
|
|
6077
|
+
}
|
|
6078
|
+
const fallback = tryBridgeFallback(state.raw, state.ctx, {
|
|
6079
|
+
onlyFailures: Boolean(state.opts?.onlyFailures)
|
|
6080
|
+
});
|
|
6081
|
+
if (!fallback) {
|
|
6082
|
+
return state.rendered.text;
|
|
6083
|
+
}
|
|
6084
|
+
const prefix = state.rendered.text;
|
|
6085
|
+
return prefix ? `${prefix}
|
|
6086
|
+
${fallback}` : fallback;
|
|
6087
|
+
}
|
|
6088
|
+
);
|
|
5008
6089
|
|
|
5009
6090
|
// src/lib/program.ts
|
|
5010
6091
|
var jestBin = "./node_modules/.bin/jest";
|
|
@@ -5049,7 +6130,7 @@ var mergeLcov = async () => {
|
|
|
5049
6130
|
try {
|
|
5050
6131
|
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
5051
6132
|
for (const entry of entries) {
|
|
5052
|
-
const full =
|
|
6133
|
+
const full = path11.join(dir, entry.name);
|
|
5053
6134
|
if (entry.isDirectory()) {
|
|
5054
6135
|
out.push(...collectLcovs(full));
|
|
5055
6136
|
} else if (entry.isFile() && entry.name === "lcov.info") {
|
|
@@ -5061,8 +6142,8 @@ var mergeLcov = async () => {
|
|
|
5061
6142
|
return out;
|
|
5062
6143
|
};
|
|
5063
6144
|
try {
|
|
5064
|
-
const jestRoot =
|
|
5065
|
-
const candidates = [
|
|
6145
|
+
const jestRoot = path11.join("coverage", "jest");
|
|
6146
|
+
const candidates = [path11.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path11.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
|
|
5066
6147
|
for (const filePath of candidates) {
|
|
5067
6148
|
try {
|
|
5068
6149
|
const content = await readOrEmpty(filePath);
|
|
@@ -5102,7 +6183,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5102
6183
|
try {
|
|
5103
6184
|
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
5104
6185
|
for (const entry of entries) {
|
|
5105
|
-
const full =
|
|
6186
|
+
const full = path11.join(dir, entry.name);
|
|
5106
6187
|
if (entry.isDirectory()) {
|
|
5107
6188
|
out.push(...listJsons(full));
|
|
5108
6189
|
} else if (entry.isFile() && entry.name === "coverage-final.json") {
|
|
@@ -5113,11 +6194,11 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5113
6194
|
}
|
|
5114
6195
|
return out;
|
|
5115
6196
|
};
|
|
5116
|
-
const coverageRoot =
|
|
6197
|
+
const coverageRoot = path11.join("coverage", "jest");
|
|
5117
6198
|
const jsonCandidates = [
|
|
5118
|
-
|
|
6199
|
+
path11.join(coverageRoot, "coverage-final.json"),
|
|
5119
6200
|
...listJsons(coverageRoot)
|
|
5120
|
-
].map((candidatePath) =>
|
|
6201
|
+
].map((candidatePath) => path11.resolve(candidatePath)).filter((absolutePath, index, arr) => {
|
|
5121
6202
|
const isFirst = arr.indexOf(absolutePath) === index;
|
|
5122
6203
|
const exists = fsSync3.existsSync(absolutePath);
|
|
5123
6204
|
return isFirst && exists;
|
|
@@ -5179,7 +6260,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5179
6260
|
executedTests: opts.executedTests ?? []
|
|
5180
6261
|
});
|
|
5181
6262
|
const context = LibReport.createContext({
|
|
5182
|
-
dir:
|
|
6263
|
+
dir: path11.resolve("coverage", "merged"),
|
|
5183
6264
|
coverageMap: filteredMap,
|
|
5184
6265
|
defaultSummarizer: "nested"
|
|
5185
6266
|
});
|
|
@@ -5247,8 +6328,8 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5247
6328
|
for (const reporter of reporters) {
|
|
5248
6329
|
reporter.execute(context);
|
|
5249
6330
|
}
|
|
5250
|
-
const textPath =
|
|
5251
|
-
const summaryPath =
|
|
6331
|
+
const textPath = path11.resolve("coverage", "merged", "coverage.txt");
|
|
6332
|
+
const summaryPath = path11.resolve("coverage", "merged", "coverage-summary.txt");
|
|
5252
6333
|
const filesToPrint = [];
|
|
5253
6334
|
if (fsSync3.existsSync(textPath)) {
|
|
5254
6335
|
filesToPrint.push(textPath);
|
|
@@ -5347,11 +6428,57 @@ var program = async () => {
|
|
|
5347
6428
|
return [];
|
|
5348
6429
|
}
|
|
5349
6430
|
};
|
|
6431
|
+
if (mode === "branch") {
|
|
6432
|
+
const resolveDefaultBranch = async () => {
|
|
6433
|
+
const candidates = [];
|
|
6434
|
+
try {
|
|
6435
|
+
const sym = await collect("git", ["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
6436
|
+
const headRef = sym.find((ln) => ln.includes("refs/remotes/origin/"));
|
|
6437
|
+
if (headRef) {
|
|
6438
|
+
const m = /refs\/remotes\/(.+)/.exec(headRef);
|
|
6439
|
+
if (m && m[1]) {
|
|
6440
|
+
candidates.push(m[1]);
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
} catch {
|
|
6444
|
+
}
|
|
6445
|
+
candidates.push("origin/main", "origin/master");
|
|
6446
|
+
for (const cand of candidates) {
|
|
6447
|
+
const exists = await collect("git", ["rev-parse", "--verify", cand]);
|
|
6448
|
+
if (exists.length > 0) {
|
|
6449
|
+
return cand;
|
|
6450
|
+
}
|
|
6451
|
+
}
|
|
6452
|
+
return void 0;
|
|
6453
|
+
};
|
|
6454
|
+
const defaultBranch = await resolveDefaultBranch();
|
|
6455
|
+
const mergeBase = defaultBranch ? (await collect("git", ["merge-base", "HEAD", defaultBranch]))[0] : void 0;
|
|
6456
|
+
const diffBase = mergeBase ?? "HEAD^";
|
|
6457
|
+
const branchDiff = await collect("git", [
|
|
6458
|
+
"diff",
|
|
6459
|
+
"--name-only",
|
|
6460
|
+
"--diff-filter=ACMRTUXB",
|
|
6461
|
+
diffBase,
|
|
6462
|
+
"HEAD"
|
|
6463
|
+
]);
|
|
6464
|
+
const stagedNow = await collect("git", [
|
|
6465
|
+
"diff",
|
|
6466
|
+
"--name-only",
|
|
6467
|
+
"--diff-filter=ACMRTUXB",
|
|
6468
|
+
"--cached"
|
|
6469
|
+
]);
|
|
6470
|
+
const unstagedNow = await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]);
|
|
6471
|
+
const untrackedNow = await collect("git", ["ls-files", "--others", "--exclude-standard"]);
|
|
6472
|
+
const rels2 = Array.from(
|
|
6473
|
+
/* @__PURE__ */ new Set([...branchDiff, ...stagedNow, ...unstagedNow, ...untrackedNow])
|
|
6474
|
+
);
|
|
6475
|
+
return rels2.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
6476
|
+
}
|
|
5350
6477
|
const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
|
|
5351
6478
|
const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
|
|
5352
6479
|
const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
|
|
5353
6480
|
const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
|
|
5354
|
-
return rels.map((rel) =>
|
|
6481
|
+
return rels.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
5355
6482
|
};
|
|
5356
6483
|
const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
|
|
5357
6484
|
const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
|
|
@@ -5376,18 +6503,18 @@ var program = async () => {
|
|
|
5376
6503
|
if (!token) {
|
|
5377
6504
|
continue;
|
|
5378
6505
|
}
|
|
5379
|
-
const isAbs =
|
|
6506
|
+
const isAbs = path11.isAbsolute(token);
|
|
5380
6507
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
5381
6508
|
let candidateFromRoot;
|
|
5382
6509
|
if (token.startsWith("/")) {
|
|
5383
|
-
candidateFromRoot =
|
|
6510
|
+
candidateFromRoot = path11.join(repoRoot, token.slice(1));
|
|
5384
6511
|
} else if (looksLikeRelPath) {
|
|
5385
|
-
candidateFromRoot =
|
|
6512
|
+
candidateFromRoot = path11.join(repoRoot, token);
|
|
5386
6513
|
} else {
|
|
5387
6514
|
candidateFromRoot = void 0;
|
|
5388
6515
|
}
|
|
5389
6516
|
const tryPushIfProd = (absPath) => {
|
|
5390
|
-
const norm =
|
|
6517
|
+
const norm = path11.resolve(absPath).replace(/\\/g, "/");
|
|
5391
6518
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
5392
6519
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
5393
6520
|
results.add(norm);
|
|
@@ -5409,7 +6536,7 @@ var program = async () => {
|
|
|
5409
6536
|
}),
|
|
5410
6537
|
timeoutMs: 4e3
|
|
5411
6538
|
});
|
|
5412
|
-
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) =>
|
|
6539
|
+
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path11.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
|
|
5413
6540
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5414
6541
|
);
|
|
5415
6542
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -5430,8 +6557,8 @@ var program = async () => {
|
|
|
5430
6557
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
5431
6558
|
const projectConfigs = [];
|
|
5432
6559
|
try {
|
|
5433
|
-
const baseCfg =
|
|
5434
|
-
const tsCfg =
|
|
6560
|
+
const baseCfg = path11.resolve("jest.config.js");
|
|
6561
|
+
const tsCfg = path11.resolve("jest.ts.config.js");
|
|
5435
6562
|
if (fsSync3.existsSync(baseCfg)) {
|
|
5436
6563
|
projectConfigs.push(baseCfg);
|
|
5437
6564
|
}
|
|
@@ -5448,7 +6575,7 @@ var program = async () => {
|
|
|
5448
6575
|
);
|
|
5449
6576
|
const prodSelections2 = expandedProdSelections;
|
|
5450
6577
|
for (const cfg of projectConfigs) {
|
|
5451
|
-
const cfgCwd =
|
|
6578
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5452
6579
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5453
6580
|
cwd: cfgCwd
|
|
5454
6581
|
});
|
|
@@ -5461,7 +6588,7 @@ var program = async () => {
|
|
|
5461
6588
|
});
|
|
5462
6589
|
} catch (err) {
|
|
5463
6590
|
if (isDebug()) {
|
|
5464
|
-
console.warn(`direct selection failed for project ${
|
|
6591
|
+
console.warn(`direct selection failed for project ${path11.basename(cfg)}: ${String(err)}`);
|
|
5465
6592
|
}
|
|
5466
6593
|
}
|
|
5467
6594
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -5473,7 +6600,7 @@ var program = async () => {
|
|
|
5473
6600
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
5474
6601
|
);
|
|
5475
6602
|
for (const cfg of projectConfigs) {
|
|
5476
|
-
const cfgCwd =
|
|
6603
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5477
6604
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5478
6605
|
cwd: cfgCwd
|
|
5479
6606
|
});
|
|
@@ -5488,13 +6615,13 @@ var program = async () => {
|
|
|
5488
6615
|
);
|
|
5489
6616
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
5490
6617
|
const absFiles = candidates.map(
|
|
5491
|
-
(candidatePath) =>
|
|
6618
|
+
(candidatePath) => path11.isAbsolute(candidatePath) ? candidatePath : path11.join(repoRootForDiscovery, candidatePath)
|
|
5492
6619
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
5493
6620
|
const onlyOwned = await filterCandidatesForProject(
|
|
5494
6621
|
cfg,
|
|
5495
6622
|
jestDiscoveryArgs,
|
|
5496
6623
|
absFiles,
|
|
5497
|
-
|
|
6624
|
+
path11.dirname(cfg)
|
|
5498
6625
|
);
|
|
5499
6626
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
5500
6627
|
}
|
|
@@ -5506,7 +6633,7 @@ var program = async () => {
|
|
|
5506
6633
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
5507
6634
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
5508
6635
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
5509
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
6636
|
+
const selectionKey = prodSelections.map((absPath) => path11.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
5510
6637
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
5511
6638
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
5512
6639
|
const rgMatches = await cachedRelated2({
|
|
@@ -5536,7 +6663,7 @@ var program = async () => {
|
|
|
5536
6663
|
cfg,
|
|
5537
6664
|
jestDiscoveryArgs,
|
|
5538
6665
|
rgCandidates,
|
|
5539
|
-
|
|
6666
|
+
path11.dirname(cfg)
|
|
5540
6667
|
);
|
|
5541
6668
|
perProjectFromRg.set(cfg, owned);
|
|
5542
6669
|
}
|
|
@@ -5551,9 +6678,9 @@ var program = async () => {
|
|
|
5551
6678
|
} else {
|
|
5552
6679
|
const repoRootForScan = repoRootForDiscovery;
|
|
5553
6680
|
const toSeeds = (abs) => {
|
|
5554
|
-
const rel =
|
|
6681
|
+
const rel = path11.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
5555
6682
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
5556
|
-
const base =
|
|
6683
|
+
const base = path11.basename(withoutExt);
|
|
5557
6684
|
const segs = withoutExt.split("/");
|
|
5558
6685
|
const tail2 = segs.slice(-2).join("/");
|
|
5559
6686
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -5568,8 +6695,8 @@ var program = async () => {
|
|
|
5568
6695
|
}
|
|
5569
6696
|
};
|
|
5570
6697
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5571
|
-
const baseDir =
|
|
5572
|
-
const cand =
|
|
6698
|
+
const baseDir = path11.dirname(fromFile);
|
|
6699
|
+
const cand = path11.resolve(baseDir, spec);
|
|
5573
6700
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5574
6701
|
for (const ext of exts) {
|
|
5575
6702
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -5578,7 +6705,7 @@ var program = async () => {
|
|
|
5578
6705
|
}
|
|
5579
6706
|
}
|
|
5580
6707
|
for (const ext of exts) {
|
|
5581
|
-
const full =
|
|
6708
|
+
const full = path11.join(cand, `index${ext}`);
|
|
5582
6709
|
if (fsSync3.existsSync(full)) {
|
|
5583
6710
|
return full;
|
|
5584
6711
|
}
|
|
@@ -5632,7 +6759,7 @@ var program = async () => {
|
|
|
5632
6759
|
cfg,
|
|
5633
6760
|
jestDiscoveryArgs,
|
|
5634
6761
|
keptCandidates,
|
|
5635
|
-
|
|
6762
|
+
path11.dirname(cfg)
|
|
5636
6763
|
);
|
|
5637
6764
|
perProjectFromScan.set(cfg, owned);
|
|
5638
6765
|
}
|
|
@@ -5658,24 +6785,41 @@ var program = async () => {
|
|
|
5658
6785
|
}
|
|
5659
6786
|
if (effectiveJestFiles.length === 0) {
|
|
5660
6787
|
const repoRoot = repoRootForRefinement;
|
|
6788
|
+
if (jestFiles.length === 0) {
|
|
6789
|
+
try {
|
|
6790
|
+
const allAcross = [];
|
|
6791
|
+
for (const cfg of projectConfigs) {
|
|
6792
|
+
const cfgCwd = path11.dirname(cfg);
|
|
6793
|
+
const listed = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
6794
|
+
cwd: cfgCwd
|
|
6795
|
+
});
|
|
6796
|
+
allAcross.push(...listed);
|
|
6797
|
+
}
|
|
6798
|
+
const uniqAll = Array.from(new Set(allAcross.map((p) => p.replace(/\\/g, "/"))));
|
|
6799
|
+
if (uniqAll.length > 0) {
|
|
6800
|
+
jestFiles = uniqAll;
|
|
6801
|
+
}
|
|
6802
|
+
} catch {
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
5661
6805
|
const seeds = prodSelections.map(
|
|
5662
|
-
(abs) =>
|
|
6806
|
+
(abs) => path11.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
5663
6807
|
).flatMap((rel) => {
|
|
5664
|
-
const base =
|
|
6808
|
+
const base = path11.basename(rel);
|
|
5665
6809
|
const segments = rel.split("/");
|
|
5666
6810
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
5667
6811
|
});
|
|
5668
6812
|
const includesSeed = (text) => seeds.some((seed) => text.includes(seed));
|
|
5669
6813
|
const tryReadFile = async (absPath) => {
|
|
5670
6814
|
try {
|
|
5671
|
-
return await
|
|
6815
|
+
return await fs7.readFile(absPath, "utf8");
|
|
5672
6816
|
} catch {
|
|
5673
6817
|
return "";
|
|
5674
6818
|
}
|
|
5675
6819
|
};
|
|
5676
6820
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5677
|
-
const baseDir =
|
|
5678
|
-
const candidate =
|
|
6821
|
+
const baseDir = path11.dirname(fromFile);
|
|
6822
|
+
const candidate = path11.resolve(baseDir, spec);
|
|
5679
6823
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
5680
6824
|
for (const ext of extensions) {
|
|
5681
6825
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -5684,7 +6828,7 @@ var program = async () => {
|
|
|
5684
6828
|
}
|
|
5685
6829
|
}
|
|
5686
6830
|
for (const ext of extensions) {
|
|
5687
|
-
const fullPath =
|
|
6831
|
+
const fullPath = path11.join(candidate, `index${ext}`);
|
|
5688
6832
|
if (fsSync3.existsSync(fullPath)) {
|
|
5689
6833
|
return fullPath;
|
|
5690
6834
|
}
|
|
@@ -5841,10 +6985,10 @@ var program = async () => {
|
|
|
5841
6985
|
};
|
|
5842
6986
|
const prodSeedsForRun = (() => {
|
|
5843
6987
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
5844
|
-
(absPath) =>
|
|
6988
|
+
(absPath) => path11.resolve(absPath).replace(/\\/g, "/")
|
|
5845
6989
|
);
|
|
5846
6990
|
const selAbs = selectionPathsAugmented.map(
|
|
5847
|
-
(pathToken) =>
|
|
6991
|
+
(pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
|
|
5848
6992
|
);
|
|
5849
6993
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
5850
6994
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -5859,29 +7003,50 @@ var program = async () => {
|
|
|
5859
7003
|
const cfg = projectsToRun[projIndex];
|
|
5860
7004
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
5861
7005
|
if (files.length === 0) {
|
|
5862
|
-
console.info(`Project ${
|
|
7006
|
+
console.info(`Project ${path11.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
5863
7007
|
continue;
|
|
5864
7008
|
}
|
|
5865
7009
|
files.forEach(
|
|
5866
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
7010
|
+
(absTestPath) => executedTestFilesSet.add(path11.resolve(absTestPath).replace(/\\/g, "/"))
|
|
5867
7011
|
);
|
|
5868
|
-
const outJson =
|
|
7012
|
+
const outJson = path11.join(
|
|
5869
7013
|
os2.tmpdir(),
|
|
5870
7014
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
5871
7015
|
);
|
|
5872
|
-
const reporterPath =
|
|
7016
|
+
const reporterPath = path11.resolve("scripts/jest-vitest-bridge.cjs");
|
|
5873
7017
|
try {
|
|
5874
|
-
|
|
5875
|
-
|
|
7018
|
+
const needsWrite = (() => {
|
|
7019
|
+
try {
|
|
7020
|
+
const existing = fsSync3.readFileSync(reporterPath, "utf8");
|
|
7021
|
+
return existing !== JEST_BRIDGE_REPORTER_SOURCE;
|
|
7022
|
+
} catch {
|
|
7023
|
+
return true;
|
|
7024
|
+
}
|
|
7025
|
+
})();
|
|
7026
|
+
if (needsWrite) {
|
|
7027
|
+
fsSync3.mkdirSync(path11.dirname(reporterPath), { recursive: true });
|
|
5876
7028
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
5877
7029
|
}
|
|
7030
|
+
const envPath = path11.resolve("scripts/jest-bridge-env.cjs");
|
|
7031
|
+
try {
|
|
7032
|
+
const existingEnv = fsSync3.readFileSync(envPath, "utf8");
|
|
7033
|
+
if (existingEnv !== JEST_BRIDGE_ENV_SOURCE) {
|
|
7034
|
+
fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
|
|
7035
|
+
}
|
|
7036
|
+
} catch {
|
|
7037
|
+
try {
|
|
7038
|
+
fsSync3.mkdirSync(path11.dirname(envPath), { recursive: true });
|
|
7039
|
+
} catch {
|
|
7040
|
+
}
|
|
7041
|
+
fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
|
|
7042
|
+
}
|
|
5878
7043
|
} catch (ensureReporterError) {
|
|
5879
7044
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
5880
7045
|
}
|
|
5881
|
-
const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) =>
|
|
7046
|
+
const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path11.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
|
|
5882
7047
|
const coverageFromArgs = [];
|
|
5883
|
-
for (const
|
|
5884
|
-
coverageFromArgs.push("--collectCoverageFrom",
|
|
7048
|
+
for (const relPath2 of selectedFilesForCoverage) {
|
|
7049
|
+
coverageFromArgs.push("--collectCoverageFrom", relPath2);
|
|
5885
7050
|
}
|
|
5886
7051
|
const { code, output } = await runWithCapture(
|
|
5887
7052
|
babelNodeBin,
|
|
@@ -5891,17 +7056,16 @@ var program = async () => {
|
|
|
5891
7056
|
jestBin,
|
|
5892
7057
|
"--config",
|
|
5893
7058
|
cfg,
|
|
7059
|
+
"--testLocationInResults",
|
|
5894
7060
|
"--runTestsByPath",
|
|
5895
7061
|
`--reporters=${reporterPath}`,
|
|
5896
|
-
"--silent",
|
|
5897
7062
|
"--colors",
|
|
5898
|
-
"--
|
|
5899
|
-
"
|
|
5900
|
-
outJson,
|
|
7063
|
+
"--env",
|
|
7064
|
+
path11.resolve("scripts/jest-bridge-env.cjs"),
|
|
5901
7065
|
...sanitizedJestRunArgs,
|
|
5902
7066
|
...collectCoverage ? [
|
|
5903
7067
|
"--coverageDirectory",
|
|
5904
|
-
|
|
7068
|
+
path11.join("coverage", "jest", path11.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
5905
7069
|
] : [],
|
|
5906
7070
|
...coverageFromArgs,
|
|
5907
7071
|
"--passWithNoTests",
|
|
@@ -5934,17 +7098,23 @@ var program = async () => {
|
|
|
5934
7098
|
...bridge,
|
|
5935
7099
|
testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
|
|
5936
7100
|
};
|
|
5937
|
-
pretty = renderVitestFromJestJSON(
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
7101
|
+
pretty = renderVitestFromJestJSON(
|
|
7102
|
+
reordered,
|
|
7103
|
+
makeCtx(
|
|
7104
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7105
|
+
/\bFAIL\b/.test(stripAnsiSimple(output))
|
|
7106
|
+
),
|
|
7107
|
+
{ onlyFailures }
|
|
7108
|
+
);
|
|
5942
7109
|
} catch {
|
|
5943
|
-
pretty = renderVitestFromJestJSON(
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
7110
|
+
pretty = renderVitestFromJestJSON(
|
|
7111
|
+
bridge,
|
|
7112
|
+
makeCtx(
|
|
7113
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7114
|
+
/\bFAIL\b/.test(stripAnsiSimple(output))
|
|
7115
|
+
),
|
|
7116
|
+
{ onlyFailures }
|
|
7117
|
+
);
|
|
5948
7118
|
}
|
|
5949
7119
|
if (debug) {
|
|
5950
7120
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
@@ -5958,18 +7128,31 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5958
7128
|
console.info(String(jsonErr));
|
|
5959
7129
|
console.info(`fallback: raw output lines=${output.split(/\r?\n/).length}`);
|
|
5960
7130
|
}
|
|
5961
|
-
|
|
7131
|
+
pretty = formatJestOutputVitest(output, {
|
|
5962
7132
|
cwd: repoRootForDiscovery,
|
|
5963
7133
|
...editorCmd !== void 0 ? { editorCmd } : {},
|
|
5964
7134
|
onlyFailures
|
|
5965
|
-
};
|
|
5966
|
-
pretty = formatJestOutputVitest(output, renderOpts);
|
|
7135
|
+
});
|
|
5967
7136
|
if (debug) {
|
|
5968
7137
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
5969
7138
|
console.info(`pretty preview (text):
|
|
5970
7139
|
${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
5971
7140
|
}
|
|
5972
7141
|
}
|
|
7142
|
+
try {
|
|
7143
|
+
const looksSparse = /\n\s*Error:\s*\n/.test(pretty) && !/(Message:|Thrown:|Events:|Console errors:)/.test(pretty);
|
|
7144
|
+
if (looksSparse) {
|
|
7145
|
+
const rawAlso = formatJestOutputVitest(output, {
|
|
7146
|
+
cwd: repoRootForDiscovery,
|
|
7147
|
+
...editorCmd !== void 0 ? { editorCmd } : {},
|
|
7148
|
+
onlyFailures
|
|
7149
|
+
});
|
|
7150
|
+
const merged = `${stripFooter(pretty)}
|
|
7151
|
+
${stripFooter(rawAlso)}`.trimEnd();
|
|
7152
|
+
pretty = merged;
|
|
7153
|
+
}
|
|
7154
|
+
} catch {
|
|
7155
|
+
}
|
|
5973
7156
|
pretty = stripFooter(pretty);
|
|
5974
7157
|
if (pretty.trim().length > 0) {
|
|
5975
7158
|
process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
|
|
@@ -6008,10 +7191,10 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6008
7191
|
try {
|
|
6009
7192
|
const prodSeeds = (() => {
|
|
6010
7193
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
6011
|
-
(absPath) =>
|
|
7194
|
+
(absPath) => path11.resolve(absPath).replace(/\\/g, "/")
|
|
6012
7195
|
);
|
|
6013
7196
|
const selAbs = selectionPathsAugmented.map(
|
|
6014
|
-
(pathToken) =>
|
|
7197
|
+
(pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
|
|
6015
7198
|
);
|
|
6016
7199
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
6017
7200
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -6025,11 +7208,18 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6025
7208
|
unified.testResults = ordered;
|
|
6026
7209
|
} catch {
|
|
6027
7210
|
}
|
|
6028
|
-
const
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
7211
|
+
const showStacks = Boolean(unified.aggregated?.numFailedTests > 0);
|
|
7212
|
+
let text = renderVitestFromJestJSON(
|
|
7213
|
+
unified,
|
|
7214
|
+
makeCtx(
|
|
7215
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7216
|
+
showStacks
|
|
7217
|
+
),
|
|
7218
|
+
{ onlyFailures }
|
|
7219
|
+
);
|
|
7220
|
+
if (onlyFailures) {
|
|
7221
|
+
text = text.split(/\r?\n/).filter((line) => !/^\s*PASS\b/.test(stripAnsiSimple(line))).join("\n");
|
|
7222
|
+
}
|
|
6033
7223
|
if (text.trim().length > 0) {
|
|
6034
7224
|
process.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
6035
7225
|
`);
|