headlamp 0.1.10 → 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/dist/cli.cjs +1841 -714
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +1900 -803
- 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(
|
|
@@ -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
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
if (
|
|
4743
|
-
|
|
5157
|
+
if (typeof err.message === "string") {
|
|
5158
|
+
candidates.push(`message: ${err.message}`);
|
|
5159
|
+
}
|
|
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));
|
|
5178
|
+
}
|
|
5179
|
+
}
|
|
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);
|
|
5222
|
+
if (seenFiles.has(rel)) {
|
|
4744
5223
|
continue;
|
|
4745
5224
|
}
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
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)}`) : [];
|
|
4771
5301
|
out.push(
|
|
4772
|
-
...buildMessageSection(
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
{ suppressDiff: hasPretty, stackPreview }
|
|
4777
|
-
)
|
|
5302
|
+
...fns.buildMessageSection(minimal.length ? minimal : ch.lines, details, ctx, {
|
|
5303
|
+
suppressDiff: hasPretty,
|
|
5304
|
+
stackPreview
|
|
5305
|
+
})
|
|
4778
5306
|
);
|
|
4779
|
-
if (
|
|
4780
|
-
|
|
4781
|
-
out.push(
|
|
4782
|
-
...buildStackSection(collapsed, {
|
|
4783
|
-
projectHint,
|
|
4784
|
-
editorCmd: opts?.editorCmd,
|
|
4785
|
-
showStacks
|
|
4786
|
-
})
|
|
4787
|
-
);
|
|
5307
|
+
if (minimal.length === 0 && fns.buildFallbackMessageBlock) {
|
|
5308
|
+
out.push(...fns.buildFallbackMessageBlock(ch.lines, { messages: details.messages }));
|
|
4788
5309
|
}
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
const badge = passFail[1];
|
|
4797
|
-
const fileAbs = passFail[2];
|
|
4798
|
-
const rel = fileAbs.replace(/\\/g, "/").replace(`${cwd}/`, "");
|
|
4799
|
-
if (seenFiles.has(rel)) {
|
|
4800
|
-
lineIndex += 1;
|
|
4801
|
-
continue;
|
|
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}`), "");
|
|
4802
5317
|
}
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
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 [];
|
|
4841
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;
|
|
4842
5390
|
}
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
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;
|
|
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;
|
|
5406
|
+
}
|
|
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;
|
|
4848
5446
|
}
|
|
4849
|
-
|
|
5447
|
+
if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
|
|
5448
|
+
return true;
|
|
5449
|
+
}
|
|
5450
|
+
const combinedRaw = `${assertionLike.matcher ?? ""} ${assertionLike.message ?? ""}`;
|
|
5451
|
+
const combinedMessage = combinedRaw.toLowerCase();
|
|
5452
|
+
return /\bstatus(code)?\b|\btohaves(tatus|tatuscode)\b/.test(combinedMessage);
|
|
5453
|
+
};
|
|
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;
|
|
4850
5490
|
};
|
|
4851
|
-
var
|
|
4852
|
-
const
|
|
4853
|
-
|
|
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);
|
|
@@ -5391,13 +6472,13 @@ var program = async () => {
|
|
|
5391
6472
|
const rels2 = Array.from(
|
|
5392
6473
|
/* @__PURE__ */ new Set([...branchDiff, ...stagedNow, ...unstagedNow, ...untrackedNow])
|
|
5393
6474
|
);
|
|
5394
|
-
return rels2.map((rel) =>
|
|
6475
|
+
return rels2.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
5395
6476
|
}
|
|
5396
6477
|
const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
|
|
5397
6478
|
const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
|
|
5398
6479
|
const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
|
|
5399
6480
|
const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
|
|
5400
|
-
return rels.map((rel) =>
|
|
6481
|
+
return rels.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
5401
6482
|
};
|
|
5402
6483
|
const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
|
|
5403
6484
|
const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
|
|
@@ -5422,18 +6503,18 @@ var program = async () => {
|
|
|
5422
6503
|
if (!token) {
|
|
5423
6504
|
continue;
|
|
5424
6505
|
}
|
|
5425
|
-
const isAbs =
|
|
6506
|
+
const isAbs = path11.isAbsolute(token);
|
|
5426
6507
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
5427
6508
|
let candidateFromRoot;
|
|
5428
6509
|
if (token.startsWith("/")) {
|
|
5429
|
-
candidateFromRoot =
|
|
6510
|
+
candidateFromRoot = path11.join(repoRoot, token.slice(1));
|
|
5430
6511
|
} else if (looksLikeRelPath) {
|
|
5431
|
-
candidateFromRoot =
|
|
6512
|
+
candidateFromRoot = path11.join(repoRoot, token);
|
|
5432
6513
|
} else {
|
|
5433
6514
|
candidateFromRoot = void 0;
|
|
5434
6515
|
}
|
|
5435
6516
|
const tryPushIfProd = (absPath) => {
|
|
5436
|
-
const norm =
|
|
6517
|
+
const norm = path11.resolve(absPath).replace(/\\/g, "/");
|
|
5437
6518
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
5438
6519
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
5439
6520
|
results.add(norm);
|
|
@@ -5455,7 +6536,7 @@ var program = async () => {
|
|
|
5455
6536
|
}),
|
|
5456
6537
|
timeoutMs: 4e3
|
|
5457
6538
|
});
|
|
5458
|
-
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(
|
|
5459
6540
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5460
6541
|
);
|
|
5461
6542
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -5476,8 +6557,8 @@ var program = async () => {
|
|
|
5476
6557
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
5477
6558
|
const projectConfigs = [];
|
|
5478
6559
|
try {
|
|
5479
|
-
const baseCfg =
|
|
5480
|
-
const tsCfg =
|
|
6560
|
+
const baseCfg = path11.resolve("jest.config.js");
|
|
6561
|
+
const tsCfg = path11.resolve("jest.ts.config.js");
|
|
5481
6562
|
if (fsSync3.existsSync(baseCfg)) {
|
|
5482
6563
|
projectConfigs.push(baseCfg);
|
|
5483
6564
|
}
|
|
@@ -5494,7 +6575,7 @@ var program = async () => {
|
|
|
5494
6575
|
);
|
|
5495
6576
|
const prodSelections2 = expandedProdSelections;
|
|
5496
6577
|
for (const cfg of projectConfigs) {
|
|
5497
|
-
const cfgCwd =
|
|
6578
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5498
6579
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5499
6580
|
cwd: cfgCwd
|
|
5500
6581
|
});
|
|
@@ -5507,7 +6588,7 @@ var program = async () => {
|
|
|
5507
6588
|
});
|
|
5508
6589
|
} catch (err) {
|
|
5509
6590
|
if (isDebug()) {
|
|
5510
|
-
console.warn(`direct selection failed for project ${
|
|
6591
|
+
console.warn(`direct selection failed for project ${path11.basename(cfg)}: ${String(err)}`);
|
|
5511
6592
|
}
|
|
5512
6593
|
}
|
|
5513
6594
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -5519,7 +6600,7 @@ var program = async () => {
|
|
|
5519
6600
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
5520
6601
|
);
|
|
5521
6602
|
for (const cfg of projectConfigs) {
|
|
5522
|
-
const cfgCwd =
|
|
6603
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5523
6604
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5524
6605
|
cwd: cfgCwd
|
|
5525
6606
|
});
|
|
@@ -5534,13 +6615,13 @@ var program = async () => {
|
|
|
5534
6615
|
);
|
|
5535
6616
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
5536
6617
|
const absFiles = candidates.map(
|
|
5537
|
-
(candidatePath) =>
|
|
6618
|
+
(candidatePath) => path11.isAbsolute(candidatePath) ? candidatePath : path11.join(repoRootForDiscovery, candidatePath)
|
|
5538
6619
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
5539
6620
|
const onlyOwned = await filterCandidatesForProject(
|
|
5540
6621
|
cfg,
|
|
5541
6622
|
jestDiscoveryArgs,
|
|
5542
6623
|
absFiles,
|
|
5543
|
-
|
|
6624
|
+
path11.dirname(cfg)
|
|
5544
6625
|
);
|
|
5545
6626
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
5546
6627
|
}
|
|
@@ -5552,7 +6633,7 @@ var program = async () => {
|
|
|
5552
6633
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
5553
6634
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
5554
6635
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
5555
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
6636
|
+
const selectionKey = prodSelections.map((absPath) => path11.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
5556
6637
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
5557
6638
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
5558
6639
|
const rgMatches = await cachedRelated2({
|
|
@@ -5582,7 +6663,7 @@ var program = async () => {
|
|
|
5582
6663
|
cfg,
|
|
5583
6664
|
jestDiscoveryArgs,
|
|
5584
6665
|
rgCandidates,
|
|
5585
|
-
|
|
6666
|
+
path11.dirname(cfg)
|
|
5586
6667
|
);
|
|
5587
6668
|
perProjectFromRg.set(cfg, owned);
|
|
5588
6669
|
}
|
|
@@ -5597,9 +6678,9 @@ var program = async () => {
|
|
|
5597
6678
|
} else {
|
|
5598
6679
|
const repoRootForScan = repoRootForDiscovery;
|
|
5599
6680
|
const toSeeds = (abs) => {
|
|
5600
|
-
const rel =
|
|
6681
|
+
const rel = path11.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
5601
6682
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
5602
|
-
const base =
|
|
6683
|
+
const base = path11.basename(withoutExt);
|
|
5603
6684
|
const segs = withoutExt.split("/");
|
|
5604
6685
|
const tail2 = segs.slice(-2).join("/");
|
|
5605
6686
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -5614,8 +6695,8 @@ var program = async () => {
|
|
|
5614
6695
|
}
|
|
5615
6696
|
};
|
|
5616
6697
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5617
|
-
const baseDir =
|
|
5618
|
-
const cand =
|
|
6698
|
+
const baseDir = path11.dirname(fromFile);
|
|
6699
|
+
const cand = path11.resolve(baseDir, spec);
|
|
5619
6700
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5620
6701
|
for (const ext of exts) {
|
|
5621
6702
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -5624,7 +6705,7 @@ var program = async () => {
|
|
|
5624
6705
|
}
|
|
5625
6706
|
}
|
|
5626
6707
|
for (const ext of exts) {
|
|
5627
|
-
const full =
|
|
6708
|
+
const full = path11.join(cand, `index${ext}`);
|
|
5628
6709
|
if (fsSync3.existsSync(full)) {
|
|
5629
6710
|
return full;
|
|
5630
6711
|
}
|
|
@@ -5678,7 +6759,7 @@ var program = async () => {
|
|
|
5678
6759
|
cfg,
|
|
5679
6760
|
jestDiscoveryArgs,
|
|
5680
6761
|
keptCandidates,
|
|
5681
|
-
|
|
6762
|
+
path11.dirname(cfg)
|
|
5682
6763
|
);
|
|
5683
6764
|
perProjectFromScan.set(cfg, owned);
|
|
5684
6765
|
}
|
|
@@ -5708,7 +6789,7 @@ var program = async () => {
|
|
|
5708
6789
|
try {
|
|
5709
6790
|
const allAcross = [];
|
|
5710
6791
|
for (const cfg of projectConfigs) {
|
|
5711
|
-
const cfgCwd =
|
|
6792
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5712
6793
|
const listed = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5713
6794
|
cwd: cfgCwd
|
|
5714
6795
|
});
|
|
@@ -5722,23 +6803,23 @@ var program = async () => {
|
|
|
5722
6803
|
}
|
|
5723
6804
|
}
|
|
5724
6805
|
const seeds = prodSelections.map(
|
|
5725
|
-
(abs) =>
|
|
6806
|
+
(abs) => path11.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
5726
6807
|
).flatMap((rel) => {
|
|
5727
|
-
const base =
|
|
6808
|
+
const base = path11.basename(rel);
|
|
5728
6809
|
const segments = rel.split("/");
|
|
5729
6810
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
5730
6811
|
});
|
|
5731
6812
|
const includesSeed = (text) => seeds.some((seed) => text.includes(seed));
|
|
5732
6813
|
const tryReadFile = async (absPath) => {
|
|
5733
6814
|
try {
|
|
5734
|
-
return await
|
|
6815
|
+
return await fs7.readFile(absPath, "utf8");
|
|
5735
6816
|
} catch {
|
|
5736
6817
|
return "";
|
|
5737
6818
|
}
|
|
5738
6819
|
};
|
|
5739
6820
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5740
|
-
const baseDir =
|
|
5741
|
-
const candidate =
|
|
6821
|
+
const baseDir = path11.dirname(fromFile);
|
|
6822
|
+
const candidate = path11.resolve(baseDir, spec);
|
|
5742
6823
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
5743
6824
|
for (const ext of extensions) {
|
|
5744
6825
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -5747,7 +6828,7 @@ var program = async () => {
|
|
|
5747
6828
|
}
|
|
5748
6829
|
}
|
|
5749
6830
|
for (const ext of extensions) {
|
|
5750
|
-
const fullPath =
|
|
6831
|
+
const fullPath = path11.join(candidate, `index${ext}`);
|
|
5751
6832
|
if (fsSync3.existsSync(fullPath)) {
|
|
5752
6833
|
return fullPath;
|
|
5753
6834
|
}
|
|
@@ -5904,10 +6985,10 @@ var program = async () => {
|
|
|
5904
6985
|
};
|
|
5905
6986
|
const prodSeedsForRun = (() => {
|
|
5906
6987
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
5907
|
-
(absPath) =>
|
|
6988
|
+
(absPath) => path11.resolve(absPath).replace(/\\/g, "/")
|
|
5908
6989
|
);
|
|
5909
6990
|
const selAbs = selectionPathsAugmented.map(
|
|
5910
|
-
(pathToken) =>
|
|
6991
|
+
(pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
|
|
5911
6992
|
);
|
|
5912
6993
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
5913
6994
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -5922,29 +7003,50 @@ var program = async () => {
|
|
|
5922
7003
|
const cfg = projectsToRun[projIndex];
|
|
5923
7004
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
5924
7005
|
if (files.length === 0) {
|
|
5925
|
-
console.info(`Project ${
|
|
7006
|
+
console.info(`Project ${path11.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
5926
7007
|
continue;
|
|
5927
7008
|
}
|
|
5928
7009
|
files.forEach(
|
|
5929
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
7010
|
+
(absTestPath) => executedTestFilesSet.add(path11.resolve(absTestPath).replace(/\\/g, "/"))
|
|
5930
7011
|
);
|
|
5931
|
-
const outJson =
|
|
7012
|
+
const outJson = path11.join(
|
|
5932
7013
|
os2.tmpdir(),
|
|
5933
7014
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
5934
7015
|
);
|
|
5935
|
-
const reporterPath =
|
|
7016
|
+
const reporterPath = path11.resolve("scripts/jest-vitest-bridge.cjs");
|
|
5936
7017
|
try {
|
|
5937
|
-
|
|
5938
|
-
|
|
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 });
|
|
5939
7028
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
5940
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
|
+
}
|
|
5941
7043
|
} catch (ensureReporterError) {
|
|
5942
7044
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
5943
7045
|
}
|
|
5944
|
-
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}`);
|
|
5945
7047
|
const coverageFromArgs = [];
|
|
5946
|
-
for (const
|
|
5947
|
-
coverageFromArgs.push("--collectCoverageFrom",
|
|
7048
|
+
for (const relPath2 of selectedFilesForCoverage) {
|
|
7049
|
+
coverageFromArgs.push("--collectCoverageFrom", relPath2);
|
|
5948
7050
|
}
|
|
5949
7051
|
const { code, output } = await runWithCapture(
|
|
5950
7052
|
babelNodeBin,
|
|
@@ -5954,17 +7056,16 @@ var program = async () => {
|
|
|
5954
7056
|
jestBin,
|
|
5955
7057
|
"--config",
|
|
5956
7058
|
cfg,
|
|
7059
|
+
"--testLocationInResults",
|
|
5957
7060
|
"--runTestsByPath",
|
|
5958
7061
|
`--reporters=${reporterPath}`,
|
|
5959
|
-
"--silent",
|
|
5960
7062
|
"--colors",
|
|
5961
|
-
"--
|
|
5962
|
-
"
|
|
5963
|
-
outJson,
|
|
7063
|
+
"--env",
|
|
7064
|
+
path11.resolve("scripts/jest-bridge-env.cjs"),
|
|
5964
7065
|
...sanitizedJestRunArgs,
|
|
5965
7066
|
...collectCoverage ? [
|
|
5966
7067
|
"--coverageDirectory",
|
|
5967
|
-
|
|
7068
|
+
path11.join("coverage", "jest", path11.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
5968
7069
|
] : [],
|
|
5969
7070
|
...coverageFromArgs,
|
|
5970
7071
|
"--passWithNoTests",
|
|
@@ -5997,17 +7098,23 @@ var program = async () => {
|
|
|
5997
7098
|
...bridge,
|
|
5998
7099
|
testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
|
|
5999
7100
|
};
|
|
6000
|
-
pretty = renderVitestFromJestJSON(
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
7101
|
+
pretty = renderVitestFromJestJSON(
|
|
7102
|
+
reordered,
|
|
7103
|
+
makeCtx(
|
|
7104
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7105
|
+
/\bFAIL\b/.test(stripAnsiSimple(output))
|
|
7106
|
+
),
|
|
7107
|
+
{ onlyFailures }
|
|
7108
|
+
);
|
|
6005
7109
|
} catch {
|
|
6006
|
-
pretty = renderVitestFromJestJSON(
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
7110
|
+
pretty = renderVitestFromJestJSON(
|
|
7111
|
+
bridge,
|
|
7112
|
+
makeCtx(
|
|
7113
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7114
|
+
/\bFAIL\b/.test(stripAnsiSimple(output))
|
|
7115
|
+
),
|
|
7116
|
+
{ onlyFailures }
|
|
7117
|
+
);
|
|
6011
7118
|
}
|
|
6012
7119
|
if (debug) {
|
|
6013
7120
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
@@ -6021,18 +7128,31 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6021
7128
|
console.info(String(jsonErr));
|
|
6022
7129
|
console.info(`fallback: raw output lines=${output.split(/\r?\n/).length}`);
|
|
6023
7130
|
}
|
|
6024
|
-
|
|
7131
|
+
pretty = formatJestOutputVitest(output, {
|
|
6025
7132
|
cwd: repoRootForDiscovery,
|
|
6026
7133
|
...editorCmd !== void 0 ? { editorCmd } : {},
|
|
6027
7134
|
onlyFailures
|
|
6028
|
-
};
|
|
6029
|
-
pretty = formatJestOutputVitest(output, renderOpts);
|
|
7135
|
+
});
|
|
6030
7136
|
if (debug) {
|
|
6031
7137
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
6032
7138
|
console.info(`pretty preview (text):
|
|
6033
7139
|
${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
6034
7140
|
}
|
|
6035
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
|
+
}
|
|
6036
7156
|
pretty = stripFooter(pretty);
|
|
6037
7157
|
if (pretty.trim().length > 0) {
|
|
6038
7158
|
process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
|
|
@@ -6071,10 +7191,10 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6071
7191
|
try {
|
|
6072
7192
|
const prodSeeds = (() => {
|
|
6073
7193
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
6074
|
-
(absPath) =>
|
|
7194
|
+
(absPath) => path11.resolve(absPath).replace(/\\/g, "/")
|
|
6075
7195
|
);
|
|
6076
7196
|
const selAbs = selectionPathsAugmented.map(
|
|
6077
|
-
(pathToken) =>
|
|
7197
|
+
(pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
|
|
6078
7198
|
);
|
|
6079
7199
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
6080
7200
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -6088,11 +7208,18 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6088
7208
|
unified.testResults = ordered;
|
|
6089
7209
|
} catch {
|
|
6090
7210
|
}
|
|
6091
|
-
const
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
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
|
+
}
|
|
6096
7223
|
if (text.trim().length > 0) {
|
|
6097
7224
|
process.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
6098
7225
|
`);
|