headlamp 0.1.10 → 0.1.12
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 +1855 -735
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +1913 -823
- 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 : (() => {
|
|
@@ -736,12 +736,14 @@ __export(fast_related_exports, {
|
|
|
736
736
|
cachedRelated: () => cachedRelated,
|
|
737
737
|
findRelatedTestsFast: () => findRelatedTestsFast
|
|
738
738
|
});
|
|
739
|
-
var path2, fs, TailSegmentCount, EmptyCount, JsonIndentSpaces, DEFAULT_TEST_GLOBS, findRelatedTestsFast, cachedRelated;
|
|
739
|
+
var path2, os2, fs, import_node_crypto, TailSegmentCount, EmptyCount, JsonIndentSpaces, DEFAULT_TEST_GLOBS, findRelatedTestsFast, cachedRelated;
|
|
740
740
|
var init_fast_related = __esm({
|
|
741
741
|
"src/lib/fast-related.ts"() {
|
|
742
742
|
"use strict";
|
|
743
743
|
path2 = __toESM(require("node:path"), 1);
|
|
744
|
+
os2 = __toESM(require("node:os"), 1);
|
|
744
745
|
fs = __toESM(require("node:fs/promises"), 1);
|
|
746
|
+
import_node_crypto = require("node:crypto");
|
|
745
747
|
init_env_utils();
|
|
746
748
|
init_exec();
|
|
747
749
|
TailSegmentCount = 2;
|
|
@@ -790,9 +792,7 @@ var init_fast_related = __esm({
|
|
|
790
792
|
}
|
|
791
793
|
const args = ["-n", "-l", "-S", "-F"];
|
|
792
794
|
testGlobs.forEach((globPattern) => args.push("-g", globPattern));
|
|
793
|
-
excludeGlobs.forEach(
|
|
794
|
-
(excludeGlobPattern) => args.push("-g", `!${excludeGlobPattern}`)
|
|
795
|
-
);
|
|
795
|
+
excludeGlobs.forEach((excludeGlobPattern) => args.push("-g", `!${excludeGlobPattern}`));
|
|
796
796
|
seeds.forEach((seedToken) => args.push("-e", seedToken));
|
|
797
797
|
let raw = "";
|
|
798
798
|
try {
|
|
@@ -804,9 +804,7 @@ var init_fast_related = __esm({
|
|
|
804
804
|
}
|
|
805
805
|
const lines = raw.split(/\r?\n/).map((lineText) => lineText.trim()).filter(Boolean);
|
|
806
806
|
const looksLikeTest = (pathText) => /\.(test|spec)\.[tj]sx?$/i.test(pathText) || /(^|\/)tests?\//i.test(pathText);
|
|
807
|
-
const absolute = lines.map(
|
|
808
|
-
(relativePath) => path2.resolve(repoRoot, relativePath).replace(/\\/g, "/")
|
|
809
|
-
).filter(looksLikeTest);
|
|
807
|
+
const absolute = lines.map((relativePath) => path2.resolve(repoRoot, relativePath).replace(/\\/g, "/")).filter(looksLikeTest);
|
|
810
808
|
const uniq = Array.from(new Set(absolute));
|
|
811
809
|
const results = [];
|
|
812
810
|
await Promise.all(
|
|
@@ -821,17 +819,15 @@ var init_fast_related = __esm({
|
|
|
821
819
|
return results;
|
|
822
820
|
};
|
|
823
821
|
cachedRelated = async (opts) => {
|
|
824
|
-
const
|
|
822
|
+
const cacheRoot = process.env.HEADLAMP_CACHE_DIR || path2.join(os2.tmpdir(), "headlamp-cache");
|
|
823
|
+
const repoKey = (0, import_node_crypto.createHash)("sha1").update(path2.resolve(opts.repoRoot)).digest("hex").slice(0, 12);
|
|
824
|
+
const cacheDir = path2.join(cacheRoot, repoKey);
|
|
825
825
|
const cacheFile = path2.join(cacheDir, "relevant-tests.json");
|
|
826
826
|
let head = "nogit";
|
|
827
827
|
try {
|
|
828
|
-
const raw = await runText(
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
{
|
|
832
|
-
env: safeEnv(process.env, {})
|
|
833
|
-
}
|
|
834
|
-
);
|
|
828
|
+
const raw = await runText("git", ["-C", opts.repoRoot, "rev-parse", "--short", "HEAD"], {
|
|
829
|
+
env: safeEnv(process.env, {})
|
|
830
|
+
});
|
|
835
831
|
head = raw.trim() || "nogit";
|
|
836
832
|
} catch {
|
|
837
833
|
head = "nogit";
|
|
@@ -863,10 +859,7 @@ var init_fast_related = __esm({
|
|
|
863
859
|
try {
|
|
864
860
|
const next = { ...bag, [key]: Array.from(new Set(recomputed)) };
|
|
865
861
|
await fs.mkdir(cacheDir, { recursive: true });
|
|
866
|
-
await fs.writeFile(
|
|
867
|
-
cacheFile,
|
|
868
|
-
JSON.stringify(next, null, JsonIndentSpaces)
|
|
869
|
-
);
|
|
862
|
+
await fs.writeFile(cacheFile, JSON.stringify(next, null, JsonIndentSpaces));
|
|
870
863
|
} catch {
|
|
871
864
|
}
|
|
872
865
|
return recomputed;
|
|
@@ -1987,19 +1980,19 @@ var require_lib = __commonJS({
|
|
|
1987
1980
|
"node_modules/json5/lib/index.js"(exports2, module2) {
|
|
1988
1981
|
var parse = require_parse();
|
|
1989
1982
|
var stringify = require_stringify();
|
|
1990
|
-
var
|
|
1983
|
+
var JSON53 = {
|
|
1991
1984
|
parse,
|
|
1992
1985
|
stringify
|
|
1993
1986
|
};
|
|
1994
|
-
module2.exports =
|
|
1987
|
+
module2.exports = JSON53;
|
|
1995
1988
|
}
|
|
1996
1989
|
});
|
|
1997
1990
|
|
|
1998
1991
|
// src/lib/program.ts
|
|
1999
|
-
var
|
|
2000
|
-
var
|
|
1992
|
+
var path11 = __toESM(require("node:path"), 1);
|
|
1993
|
+
var os3 = __toESM(require("node:os"), 1);
|
|
2001
1994
|
var fsSync3 = __toESM(require("node:fs"), 1);
|
|
2002
|
-
var
|
|
1995
|
+
var fs7 = __toESM(require("node:fs/promises"), 1);
|
|
2003
1996
|
var LibReport = __toESM(require("istanbul-lib-report"), 1);
|
|
2004
1997
|
var Reports = __toESM(require("istanbul-reports"), 1);
|
|
2005
1998
|
var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
|
|
@@ -3370,7 +3363,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3370
3363
|
);
|
|
3371
3364
|
}
|
|
3372
3365
|
};
|
|
3373
|
-
var shortenPathPreservingFilename = (
|
|
3366
|
+
var shortenPathPreservingFilename = (relPath2, maxWidth, opts) => {
|
|
3374
3367
|
const ellipsis = opts?.ellipsis ?? "\u2026";
|
|
3375
3368
|
const START_HEAD = Math.max(0, opts?.keepHead ?? 1);
|
|
3376
3369
|
const START_TAIL = Math.max(0, opts?.keepTail ?? 1);
|
|
@@ -3542,7 +3535,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3542
3535
|
}
|
|
3543
3536
|
return null;
|
|
3544
3537
|
};
|
|
3545
|
-
const normalized =
|
|
3538
|
+
const normalized = relPath2.replace(/\\/g, "/");
|
|
3546
3539
|
if (visibleWidth(normalized) <= maxWidth) {
|
|
3547
3540
|
return normalized;
|
|
3548
3541
|
}
|
|
@@ -3998,11 +3991,343 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3998
3991
|
}
|
|
3999
3992
|
};
|
|
4000
3993
|
|
|
4001
|
-
// src/lib/jest-
|
|
4002
|
-
var
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
3994
|
+
// src/lib/jest-reporter-source.ts
|
|
3995
|
+
var JEST_BRIDGE_REPORTER_SOURCE = `const fs = require('fs');
|
|
3996
|
+
const path = require('path');
|
|
3997
|
+
|
|
3998
|
+
const isObject = (v) => typeof v === 'object' && v !== null;
|
|
3999
|
+
const sanitizeError = (err) => {
|
|
4000
|
+
if (!isObject(err)) return err;
|
|
4001
|
+
const out = {};
|
|
4002
|
+
const name = err.name || (err.constructor && err.constructor.name) || undefined;
|
|
4003
|
+
if (name) out.name = String(name);
|
|
4004
|
+
if (typeof err.message === 'string') out.message = err.message;
|
|
4005
|
+
if (typeof err.stack === 'string') out.stack = err.stack;
|
|
4006
|
+
if (err.code !== undefined) out.code = err.code;
|
|
4007
|
+
if (err.expected !== undefined) out.expected = err.expected;
|
|
4008
|
+
if (err.received !== undefined) out.received = err.received;
|
|
4009
|
+
if (err.matcherResult && isObject(err.matcherResult)) {
|
|
4010
|
+
const mr = err.matcherResult;
|
|
4011
|
+
let messageText;
|
|
4012
|
+
try {
|
|
4013
|
+
messageText = typeof mr.message === 'function' ? String(mr.message()) : (typeof mr.message === 'string' ? mr.message : undefined);
|
|
4014
|
+
} catch {}
|
|
4015
|
+
out.matcherResult = {
|
|
4016
|
+
matcherName: typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
|
|
4017
|
+
message: messageText,
|
|
4018
|
+
stack: typeof mr.stack === 'string' ? mr.stack : undefined,
|
|
4019
|
+
expected: mr.expected,
|
|
4020
|
+
received: mr.received,
|
|
4021
|
+
actual: mr.actual,
|
|
4022
|
+
pass: typeof mr.pass === 'boolean' ? mr.pass : undefined,
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
if (err.cause) {
|
|
4026
|
+
out.cause = sanitizeError(err.cause);
|
|
4027
|
+
}
|
|
4028
|
+
// Copy own enumerable props to preserve custom data
|
|
4029
|
+
try {
|
|
4030
|
+
for (const key of Object.keys(err)) {
|
|
4031
|
+
if (!(key in out)) out[key] = err[key];
|
|
4032
|
+
}
|
|
4033
|
+
} catch {}
|
|
4034
|
+
return out;
|
|
4035
|
+
};
|
|
4036
|
+
const sanitizeDetail = (d) => {
|
|
4037
|
+
if (typeof d === 'string') return d;
|
|
4038
|
+
if (!isObject(d)) return d;
|
|
4039
|
+
// Common Jest detail shapes
|
|
4040
|
+
const out = {};
|
|
4041
|
+
if (d.message) out.message = d.message;
|
|
4042
|
+
if (d.stack) out.stack = d.stack;
|
|
4043
|
+
if (d.error) out.error = sanitizeError(d.error);
|
|
4044
|
+
if (d.matcherResult) out.matcherResult = sanitizeError({ matcherResult: d.matcherResult }).matcherResult;
|
|
4045
|
+
if (d.expected !== undefined) out.expected = d.expected;
|
|
4046
|
+
if (d.received !== undefined) out.received = d.received;
|
|
4047
|
+
// Copy the rest
|
|
4048
|
+
try {
|
|
4049
|
+
for (const key of Object.keys(d)) {
|
|
4050
|
+
if (!(key in out)) out[key] = d[key];
|
|
4051
|
+
}
|
|
4052
|
+
} catch {}
|
|
4053
|
+
return out;
|
|
4054
|
+
};
|
|
4055
|
+
|
|
4056
|
+
class BridgeReporter {
|
|
4057
|
+
constructor(globalConfig, options) {
|
|
4058
|
+
this.out = process.env.JEST_BRIDGE_OUT || (options && options.outFile) || path.join(process.cwd(), 'coverage', 'jest-run.json');
|
|
4059
|
+
this.buf = { startTime: Date.now(), testResults: [], aggregated: null };
|
|
4060
|
+
}
|
|
4061
|
+
onRunStart() { this.buf.startTime = Date.now(); }
|
|
4062
|
+
onTestResult(_test, tr) {
|
|
4063
|
+
const mapAssertion = (a) => ({
|
|
4064
|
+
title: a.title,
|
|
4065
|
+
fullName: a.fullName || [...(a.ancestorTitles || []), a.title].join(' '),
|
|
4066
|
+
status: a.status,
|
|
4067
|
+
duration: a.duration || 0,
|
|
4068
|
+
location: a.location || null,
|
|
4069
|
+
failureMessages: (a.failureMessages || []).map(String),
|
|
4070
|
+
failureDetails: (a.failureDetails || []).map(sanitizeDetail),
|
|
4071
|
+
});
|
|
4072
|
+
this.buf.testResults.push({
|
|
4073
|
+
testFilePath: tr.testFilePath,
|
|
4074
|
+
status: tr.numFailingTests ? 'failed' : 'passed',
|
|
4075
|
+
failureMessage: tr.failureMessage || '',
|
|
4076
|
+
failureDetails: (tr.failureDetails || []).map(sanitizeDetail),
|
|
4077
|
+
testExecError: tr.testExecError ? sanitizeError(tr.testExecError) : null,
|
|
4078
|
+
console: tr.console || null,
|
|
4079
|
+
perfStats: tr.perfStats || {},
|
|
4080
|
+
testResults: (tr.testResults || []).map(mapAssertion),
|
|
4081
|
+
});
|
|
4082
|
+
}
|
|
4083
|
+
onRunComplete(_contexts, agg) {
|
|
4084
|
+
this.buf.aggregated = {
|
|
4085
|
+
numTotalTestSuites: agg.numTotalTestSuites,
|
|
4086
|
+
numPassedTestSuites: agg.numPassedTestSuites,
|
|
4087
|
+
numFailedTestSuites: agg.numFailedTestSuites,
|
|
4088
|
+
numTotalTests: agg.numTotalTests,
|
|
4089
|
+
numPassedTests: agg.numPassedTests,
|
|
4090
|
+
numFailedTests: agg.numFailedTests,
|
|
4091
|
+
numPendingTests: agg.numPendingTests,
|
|
4092
|
+
numTodoTests: agg.numTodoTests,
|
|
4093
|
+
startTime: agg.startTime,
|
|
4094
|
+
success: agg.success,
|
|
4095
|
+
runTimeMs: agg.testResults.reduce((t, r) => t + Math.max(0, (r.perfStats?.end || 0) - (r.perfStats?.start || 0)), 0),
|
|
4096
|
+
};
|
|
4097
|
+
fs.mkdirSync(path.dirname(this.out), { recursive: true });
|
|
4098
|
+
fs.writeFileSync(this.out, JSON.stringify(this.buf), 'utf8');
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
module.exports = BridgeReporter;`;
|
|
4102
|
+
|
|
4103
|
+
// src/lib/jest-environment-source.ts
|
|
4104
|
+
var JEST_BRIDGE_ENV_SOURCE = `
|
|
4105
|
+
'use strict';
|
|
4106
|
+
|
|
4107
|
+
const NodeEnvironment = require('jest-environment-node').TestEnvironment || require('jest-environment-node');
|
|
4108
|
+
|
|
4109
|
+
module.exports = class BridgeEnv extends NodeEnvironment {
|
|
4110
|
+
constructor(config, context) {
|
|
4111
|
+
super(config, context);
|
|
4112
|
+
const { AsyncLocalStorage } = require('node:async_hooks');
|
|
4113
|
+
this._als = new AsyncLocalStorage();
|
|
4114
|
+
this._cleanup = [];
|
|
4115
|
+
}
|
|
4116
|
+
|
|
4117
|
+
_ctx() {
|
|
4118
|
+
try { const s = this._als.getStore(); if (s) return s; } catch {}
|
|
4119
|
+
try {
|
|
4120
|
+
const st = this.global.expect && typeof this.global.expect.getState === 'function' ? this.global.expect.getState() : {};
|
|
4121
|
+
return { testPath: st.testPath, currentTestName: st.currentTestName };
|
|
4122
|
+
} catch { return {}; }
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
async setup() {
|
|
4126
|
+
await super.setup();
|
|
4127
|
+
|
|
4128
|
+
try { Error.stackTraceLimit = Math.max(Error.stackTraceLimit || 10, 50); } catch {}
|
|
4129
|
+
|
|
4130
|
+
const print = (payload) => { try { this.global.console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {} };
|
|
4131
|
+
const toErr = (x) => { try { return x instanceof Error ? x : new Error(String(x)); } catch { return new Error('unknown'); } };
|
|
4132
|
+
|
|
4133
|
+
const onRej = (reason) => {
|
|
4134
|
+
const e = toErr(reason);
|
|
4135
|
+
const c = this._ctx();
|
|
4136
|
+
print({ type: 'unhandledRejection', name: e.name, message: e.message, stack: e.stack, code: e.code ?? undefined, ...c });
|
|
4137
|
+
};
|
|
4138
|
+
const onExc = (error) => {
|
|
4139
|
+
const e = toErr(error);
|
|
4140
|
+
const c = this._ctx();
|
|
4141
|
+
print({ type: 'uncaughtException', name: e.name, message: e.message, stack: e.stack, code: e.code ?? undefined, ...c });
|
|
4142
|
+
};
|
|
4143
|
+
|
|
4144
|
+
this.global.process.on('unhandledRejection', onRej);
|
|
4145
|
+
this.global.process.on('uncaughtException', onExc);
|
|
4146
|
+
this._cleanup.push(() => {
|
|
4147
|
+
this.global.process.off('unhandledRejection', onRej);
|
|
4148
|
+
this.global.process.off('uncaughtException', onExc);
|
|
4149
|
+
});
|
|
4150
|
+
|
|
4151
|
+
// Signal environment readiness so we can confirm the custom env loaded
|
|
4152
|
+
try { const c = this._ctx(); print({ type: 'envReady', ...c }); } catch {}
|
|
4153
|
+
|
|
4154
|
+
try {
|
|
4155
|
+
const http = this.global.require ? this.global.require('http') : require('http');
|
|
4156
|
+
const originalEmit = http && http.Server && http.Server.prototype && http.Server.prototype.emit;
|
|
4157
|
+
if (originalEmit) {
|
|
4158
|
+
const MAX = 64 * 1024;
|
|
4159
|
+
const asString = (x) => { try { if (typeof x === 'string') return x; if (Buffer.isBuffer(x)) return x.toString('utf8'); return String(x); } catch { return ''; } };
|
|
4160
|
+
|
|
4161
|
+
const patched = function(eventName, req, res) {
|
|
4162
|
+
try {
|
|
4163
|
+
if (eventName === 'request' && req && res && typeof res.write === 'function' && typeof res.end === 'function') {
|
|
4164
|
+
const startAt = Date.now();
|
|
4165
|
+
const safeHeader = (k) => { try { return req && req.headers ? String((req.headers[k.toLowerCase()] ?? '')) : ''; } catch { return ''; } };
|
|
4166
|
+
const reqIdHeader = safeHeader('x-request-id');
|
|
4167
|
+
const chunks = [];
|
|
4168
|
+
const write = res.write.bind(res);
|
|
4169
|
+
const end = res.end.bind(res);
|
|
4170
|
+
const method = req.method ? String(req.method) : undefined;
|
|
4171
|
+
const url = (req.originalUrl || req.url) ? String(req.originalUrl || req.url) : undefined;
|
|
4172
|
+
|
|
4173
|
+
res.write = function(chunk, enc, cb) {
|
|
4174
|
+
try { const s = asString(chunk); if (s) chunks.push(s); } catch {}
|
|
4175
|
+
return write(chunk, enc, cb);
|
|
4176
|
+
};
|
|
4177
|
+
res.end = function(chunk, enc, cb) {
|
|
4178
|
+
try { const s = asString(chunk); if (s) chunks.push(s); } catch {}
|
|
4179
|
+
try {
|
|
4180
|
+
const preview = chunks.join('').slice(0, MAX);
|
|
4181
|
+
const statusCode = typeof res.statusCode === 'number' ? res.statusCode : undefined;
|
|
4182
|
+
const ct = (typeof res.getHeader === 'function' && res.getHeader('content-type')) || undefined;
|
|
4183
|
+
const routePath = (req && req.route && req.route.path) || (req && req.baseUrl && req.path ? (req.baseUrl + req.path) : undefined);
|
|
4184
|
+
const jsonParsed = (() => { try { return JSON.parse(preview); } catch { return undefined; } })();
|
|
4185
|
+
const requestId = reqIdHeader || (jsonParsed && typeof jsonParsed === 'object' ? (jsonParsed.requestId || jsonParsed.reqId || '') : '');
|
|
4186
|
+
const ctx = (global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx) ? global.__JEST_BRIDGE_ENV_REF._ctx() : {};
|
|
4187
|
+
const payload = {
|
|
4188
|
+
type: 'httpResponse',
|
|
4189
|
+
timestampMs: Date.now(),
|
|
4190
|
+
durationMs: Math.max(0, Date.now() - startAt),
|
|
4191
|
+
method, url, statusCode,
|
|
4192
|
+
route: routePath ? String(routePath) : undefined,
|
|
4193
|
+
contentType: ct ? String(ct) : undefined,
|
|
4194
|
+
headers: (typeof res.getHeaders === 'function') ? res.getHeaders() : undefined,
|
|
4195
|
+
requestId: requestId ? String(requestId) : undefined,
|
|
4196
|
+
bodyPreview: preview,
|
|
4197
|
+
json: jsonParsed,
|
|
4198
|
+
testPath: ctx.testPath, currentTestName: ctx.currentTestName,
|
|
4199
|
+
};
|
|
4200
|
+
try {
|
|
4201
|
+
if (!global.__JEST_HTTP_EVENTS__) global.__JEST_HTTP_EVENTS__ = [];
|
|
4202
|
+
const arr = global.__JEST_HTTP_EVENTS__;
|
|
4203
|
+
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 });
|
|
4204
|
+
if (arr.length > 25) arr.splice(0, arr.length - 25);
|
|
4205
|
+
} catch {}
|
|
4206
|
+
try { console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
|
|
4207
|
+
} catch {}
|
|
4208
|
+
return end(chunk, enc, cb);
|
|
4209
|
+
};
|
|
4210
|
+
try {
|
|
4211
|
+
res.on('close', function onClose() {
|
|
4212
|
+
try {
|
|
4213
|
+
const ended = typeof res.writableEnded === 'boolean' ? res.writableEnded : false;
|
|
4214
|
+
if (!ended) {
|
|
4215
|
+
const routePath = (req && req.route && req.route.path) || (req && req.baseUrl && req.path ? (req.baseUrl + req.path) : undefined);
|
|
4216
|
+
const ctx = (global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx) ? global.__JEST_BRIDGE_ENV_REF._ctx() : {};
|
|
4217
|
+
const payload = {
|
|
4218
|
+
type: 'httpAbort',
|
|
4219
|
+
timestampMs: Date.now(),
|
|
4220
|
+
durationMs: Math.max(0, Date.now() - startAt),
|
|
4221
|
+
method, url,
|
|
4222
|
+
route: routePath ? String(routePath) : undefined,
|
|
4223
|
+
testPath: ctx.testPath, currentTestName: ctx.currentTestName,
|
|
4224
|
+
};
|
|
4225
|
+
try { console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
|
|
4226
|
+
}
|
|
4227
|
+
} catch {}
|
|
4228
|
+
});
|
|
4229
|
+
} catch {}
|
|
4230
|
+
}
|
|
4231
|
+
} catch {}
|
|
4232
|
+
return originalEmit.apply(this, arguments);
|
|
4233
|
+
};
|
|
4234
|
+
|
|
4235
|
+
try { this.global.__JEST_BRIDGE_ENV_REF = this; } catch {}
|
|
4236
|
+
http.Server.prototype.emit = patched;
|
|
4237
|
+
|
|
4238
|
+
this._cleanup.push(() => {
|
|
4239
|
+
try { if (http.Server && http.Server.prototype) http.Server.prototype.emit = originalEmit; } catch {}
|
|
4240
|
+
try { delete this.global.__JEST_BRIDGE_ENV_REF; } catch {}
|
|
4241
|
+
});
|
|
4242
|
+
}
|
|
4243
|
+
} catch {}
|
|
4244
|
+
|
|
4245
|
+
// Wrap test functions to emit rich assertion events on failures
|
|
4246
|
+
try {
|
|
4247
|
+
const g = this.global;
|
|
4248
|
+
const ctxFn = () => {
|
|
4249
|
+
try {
|
|
4250
|
+
const ref = g.__JEST_BRIDGE_ENV_REF;
|
|
4251
|
+
return ref && typeof ref._ctx === 'function' ? ref._ctx() : {};
|
|
4252
|
+
} catch { return {}; }
|
|
4253
|
+
};
|
|
4254
|
+
const emitAssertion = (err) => {
|
|
4255
|
+
try {
|
|
4256
|
+
const e = toErr(err);
|
|
4257
|
+
const mr = e && typeof e === 'object' && e.matcherResult ? e.matcherResult : undefined;
|
|
4258
|
+
const messageText = (() => { try { return mr && typeof mr.message === 'function' ? String(mr.message()) : (e.message || ''); } catch { return e.message || ''; } })();
|
|
4259
|
+
const expectedPreview = (() => { try { return mr && mr.expected !== undefined ? JSON.stringify(mr.expected, null, 2) : undefined; } catch { return undefined; } })();
|
|
4260
|
+
const actualPreview = (() => { try { return mr && mr.received !== undefined ? JSON.stringify(mr.received, null, 2) : undefined; } catch { return undefined; } })();
|
|
4261
|
+
const c = ctxFn();
|
|
4262
|
+
const expectedRaw = (() => { try { return mr?.expected; } catch { return undefined; } })();
|
|
4263
|
+
const receivedRaw = (() => { try { return mr?.received; } catch { return undefined; } })();
|
|
4264
|
+
print({
|
|
4265
|
+
type: 'assertionFailure',
|
|
4266
|
+
timestampMs: Date.now(),
|
|
4267
|
+
matcher: mr && typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
|
|
4268
|
+
expectedPreview,
|
|
4269
|
+
actualPreview,
|
|
4270
|
+
expectedNumber: typeof expectedRaw === 'number' ? expectedRaw : undefined,
|
|
4271
|
+
receivedNumber: typeof receivedRaw === 'number' ? receivedRaw : undefined,
|
|
4272
|
+
message: messageText,
|
|
4273
|
+
stack: e.stack,
|
|
4274
|
+
...c,
|
|
4275
|
+
});
|
|
4276
|
+
} catch {}
|
|
4277
|
+
};
|
|
4278
|
+
const wrap = (orig) => {
|
|
4279
|
+
if (!orig || typeof orig !== 'function') return orig;
|
|
4280
|
+
const wrapped = function(name, fn, timeout) {
|
|
4281
|
+
if (typeof fn !== 'function') return orig.call(this, name, fn, timeout);
|
|
4282
|
+
const run = function() {
|
|
4283
|
+
try {
|
|
4284
|
+
const res = fn.apply(this, arguments);
|
|
4285
|
+
if (res && typeof res.then === 'function') {
|
|
4286
|
+
return res.catch((err) => { emitAssertion(err); throw err; });
|
|
4287
|
+
}
|
|
4288
|
+
return res;
|
|
4289
|
+
} catch (err) {
|
|
4290
|
+
emitAssertion(err);
|
|
4291
|
+
throw err;
|
|
4292
|
+
}
|
|
4293
|
+
};
|
|
4294
|
+
return orig.call(this, name, run, timeout);
|
|
4295
|
+
};
|
|
4296
|
+
try { wrapped.only = orig.only && typeof orig.only === 'function' ? wrap(orig.only) : orig.only; } catch {}
|
|
4297
|
+
try { wrapped.skip = orig.skip && typeof orig.skip === 'function' ? wrap(orig.skip) : orig.skip; } catch {}
|
|
4298
|
+
return wrapped;
|
|
4299
|
+
};
|
|
4300
|
+
try { g.it = wrap(g.it); } catch {}
|
|
4301
|
+
try { g.test = wrap(g.test); } catch {}
|
|
4302
|
+
} catch {}
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
async handleTestEvent(evt, state) {
|
|
4306
|
+
if (evt.name === 'test_start') {
|
|
4307
|
+
const store = { testPath: state.testPath, currentTestName: evt.test.name };
|
|
4308
|
+
try { this._als.enterWith(store); } catch {}
|
|
4309
|
+
} else if (evt.name === 'test_done') {
|
|
4310
|
+
try { this._als.enterWith({}); } catch {}
|
|
4311
|
+
try {
|
|
4312
|
+
const events = Array.isArray(global.__JEST_HTTP_EVENTS__) ? global.__JEST_HTTP_EVENTS__ : [];
|
|
4313
|
+
if (events.length) {
|
|
4314
|
+
const batch = events.slice(-10);
|
|
4315
|
+
const payload = { type: 'httpResponseBatch', events: batch, testPath: state.testPath, currentTestName: evt.test.name };
|
|
4316
|
+
try { this.global.console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
|
|
4317
|
+
try { global.__JEST_HTTP_EVENTS__ = []; } catch {}
|
|
4318
|
+
}
|
|
4319
|
+
} catch {}
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
async teardown() {
|
|
4324
|
+
for (let i = this._cleanup.length - 1; i >= 0; i--) {
|
|
4325
|
+
try { this._cleanup[i](); } catch {}
|
|
4326
|
+
}
|
|
4327
|
+
await super.teardown();
|
|
4328
|
+
}
|
|
4329
|
+
};
|
|
4330
|
+
`;
|
|
4006
4331
|
|
|
4007
4332
|
// src/lib/stacks.ts
|
|
4008
4333
|
var isStackLine = (line) => /\s+at\s+/.test(line);
|
|
@@ -4065,30 +4390,81 @@ var collapseStacks = (lines) => {
|
|
|
4065
4390
|
return out;
|
|
4066
4391
|
};
|
|
4067
4392
|
|
|
4068
|
-
// src/lib/
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4393
|
+
// src/lib/fp.ts
|
|
4394
|
+
function pipe(initial, ...fns) {
|
|
4395
|
+
return fns.reduce((acc, fn) => fn(acc), initial);
|
|
4396
|
+
}
|
|
4397
|
+
var some = (value) => ({ tag: "Some", value });
|
|
4398
|
+
var none = { tag: "None" };
|
|
4399
|
+
var unfoldr = (initial, step2) => {
|
|
4400
|
+
const out = [];
|
|
4401
|
+
for (let state = initial; ; ) {
|
|
4402
|
+
const result = step2(state);
|
|
4403
|
+
if (result.tag === "None") {
|
|
4404
|
+
break;
|
|
4405
|
+
}
|
|
4406
|
+
const [element, next] = result.value;
|
|
4407
|
+
out.push(element);
|
|
4408
|
+
state = next;
|
|
4075
4409
|
}
|
|
4076
|
-
|
|
4077
|
-
return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
|
|
4410
|
+
return out;
|
|
4078
4411
|
};
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4412
|
+
|
|
4413
|
+
// src/lib/formatter/parse.ts
|
|
4414
|
+
var isFailureStart = (lineText) => /^\s*●\s+/.test(lineText);
|
|
4415
|
+
var isSuiteLine = (lineText) => /^\s*(PASS|FAIL)\s+/.test(lineText);
|
|
4416
|
+
var isSummaryLine = (lineText) => /^\s*(Test Suites:|Tests:|Snapshots:|Time:|Ran all)/.test(lineText);
|
|
4417
|
+
var collectFailure = (allLines, startIndex) => {
|
|
4418
|
+
const title = stripAnsiSimple(allLines[startIndex]).replace(/^\s*●\s+/, "").trim();
|
|
4419
|
+
const buf = [allLines[startIndex]];
|
|
4420
|
+
let i = startIndex + 1;
|
|
4421
|
+
for (; i < allLines.length; i += 1) {
|
|
4422
|
+
const simple = stripAnsiSimple(allLines[i]);
|
|
4423
|
+
const nextIsStart = isFailureStart(simple) || isSuiteLine(simple) || isSummaryLine(simple);
|
|
4424
|
+
const prevBlank = stripAnsiSimple(allLines[i - 1] ?? "").trim() === "";
|
|
4425
|
+
if (nextIsStart && prevBlank) {
|
|
4426
|
+
break;
|
|
4427
|
+
}
|
|
4428
|
+
buf.push(allLines[i]);
|
|
4086
4429
|
}
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4430
|
+
return [{ tag: "FailureBlock", title, lines: buf }, i];
|
|
4431
|
+
};
|
|
4432
|
+
var parseSuite = (lineText) => {
|
|
4433
|
+
const match = lineText.match(/^\s*(PASS|FAIL)\s+(.+)$/);
|
|
4434
|
+
return { tag: "PassFail", badge: match[1], rel: match[2] };
|
|
4435
|
+
};
|
|
4436
|
+
var parseChunks = (raw) => {
|
|
4437
|
+
const lines = raw.split(/\r?\n/);
|
|
4438
|
+
return unfoldr({ index: 0 }, (state) => {
|
|
4439
|
+
if (state.index >= lines.length) {
|
|
4440
|
+
return none;
|
|
4441
|
+
}
|
|
4442
|
+
const line = lines[state.index];
|
|
4443
|
+
const simple = stripAnsiSimple(line);
|
|
4444
|
+
if (isFailureStart(simple)) {
|
|
4445
|
+
const [chunk, next] = collectFailure(lines, state.index);
|
|
4446
|
+
return some([chunk, { index: next }]);
|
|
4447
|
+
}
|
|
4448
|
+
if (isSuiteLine(simple)) {
|
|
4449
|
+
return some([parseSuite(simple), { index: state.index + 1 }]);
|
|
4450
|
+
}
|
|
4451
|
+
if (isSummaryLine(simple)) {
|
|
4452
|
+
return some([{ tag: "Summary", line }, { index: state.index + 1 }]);
|
|
4453
|
+
}
|
|
4454
|
+
if (isStackLine(simple)) {
|
|
4455
|
+
return some([{ tag: "Stack", line }, { index: state.index + 1 }]);
|
|
4456
|
+
}
|
|
4457
|
+
return some([{ tag: "Other", line }, { index: state.index + 1 }]);
|
|
4458
|
+
});
|
|
4090
4459
|
};
|
|
4091
|
-
|
|
4460
|
+
|
|
4461
|
+
// src/lib/formatter/render.ts
|
|
4462
|
+
var path9 = __toESM(require("node:path"), 1);
|
|
4463
|
+
|
|
4464
|
+
// src/lib/formatter/fns.ts
|
|
4465
|
+
var fs4 = __toESM(require("node:fs"), 1);
|
|
4466
|
+
var util = __toESM(require("node:util"), 1);
|
|
4467
|
+
var import_json5 = __toESM(require_lib(), 1);
|
|
4092
4468
|
var colorTokens = {
|
|
4093
4469
|
pass: Colors.Success,
|
|
4094
4470
|
fail: Colors.Failure,
|
|
@@ -4099,31 +4475,17 @@ var colorTokens = {
|
|
|
4099
4475
|
failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `)),
|
|
4100
4476
|
runPill: (text) => BackgroundColors.Run(ansi.white(` ${text} `))
|
|
4101
4477
|
};
|
|
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
|
-
}
|
|
4478
|
+
var drawRule = (label) => {
|
|
4479
|
+
const width = Math.max(
|
|
4480
|
+
40,
|
|
4481
|
+
process.stdout && process.stdout.columns || 80
|
|
4482
|
+
);
|
|
4483
|
+
if (!label) {
|
|
4484
|
+
return ansi.dim("\u2500".repeat(width));
|
|
4125
4485
|
}
|
|
4126
|
-
|
|
4486
|
+
const plain = stripAnsiSimple(label);
|
|
4487
|
+
const pad = Math.max(1, width - plain.length - 1);
|
|
4488
|
+
return `${ansi.dim("\u2500".repeat(pad))} ${label}`;
|
|
4127
4489
|
};
|
|
4128
4490
|
var drawFailLine = () => {
|
|
4129
4491
|
const width = Math.max(
|
|
@@ -4133,9 +4495,29 @@ var drawFailLine = () => {
|
|
|
4133
4495
|
return colorTokens.fail("\u2500".repeat(width));
|
|
4134
4496
|
};
|
|
4135
4497
|
var renderRunLine = (cwd) => `${colorTokens.runPill("RUN")} ${ansi.dim(cwd.replace(/\\/g, "/"))}`;
|
|
4498
|
+
var buildFileBadgeLine = (rel, failedCount) => failedCount > 0 ? `${colorTokens.failPill("FAIL")} ${ansi.white(rel)}` : `${colorTokens.passPill("PASS")} ${ansi.white(rel)}`;
|
|
4499
|
+
var buildPerFileOverview = (rel, assertions) => {
|
|
4500
|
+
const out = [];
|
|
4501
|
+
out.push(`${ansi.magenta(rel)} ${ansi.dim(`(${assertions.length})`)}`);
|
|
4502
|
+
for (const assertion of assertions) {
|
|
4503
|
+
const name = assertion.fullName;
|
|
4504
|
+
if (assertion.status === "passed") {
|
|
4505
|
+
out.push(` ${colorTokens.pass("\u2713")} ${ansi.dim(name)}`);
|
|
4506
|
+
} else if (assertion.status === "todo") {
|
|
4507
|
+
out.push(` ${colorTokens.todo("\u2610")} ${ansi.dim(name)} ${colorTokens.todo("[todo]")}`);
|
|
4508
|
+
} else if (assertion.status === "pending") {
|
|
4509
|
+
out.push(` ${colorTokens.skip("\u2193")} ${ansi.dim(name)} ${colorTokens.skip("[skipped]")}`);
|
|
4510
|
+
} else {
|
|
4511
|
+
out.push(` ${colorTokens.fail("\xD7")} ${ansi.white(name)}`);
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
out.push("");
|
|
4515
|
+
return out;
|
|
4516
|
+
};
|
|
4517
|
+
var isObjectRecord = (value) => typeof value === "object" && value !== null;
|
|
4136
4518
|
var colorStackLine = (line, projectHint) => {
|
|
4137
4519
|
const plainLine = stripAnsiSimple(line);
|
|
4138
|
-
if (
|
|
4520
|
+
if (!/\s+at\s+/.test(plainLine)) {
|
|
4139
4521
|
return plainLine;
|
|
4140
4522
|
}
|
|
4141
4523
|
const match = plainLine.match(/\(?([^\s()]+):(\d+):(\d+)\)?$/);
|
|
@@ -4151,298 +4533,144 @@ var colorStackLine = (line, projectHint) => {
|
|
|
4151
4533
|
`(${coloredPath}${ansi.dim(":")}${ansi.white(`${lineNumber}:${columnNumber}`)})`
|
|
4152
4534
|
);
|
|
4153
4535
|
};
|
|
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}`);
|
|
4536
|
+
var extractBridgePath = (raw, cwd) => {
|
|
4537
|
+
const re = /Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g;
|
|
4538
|
+
const matches = Array.from(raw.matchAll(re));
|
|
4539
|
+
if (matches.length === 0) {
|
|
4540
|
+
return null;
|
|
4180
4541
|
}
|
|
4181
|
-
|
|
4542
|
+
const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["'`]|["'`]$/g, "");
|
|
4543
|
+
return /^\//.test(jsonPath) ? jsonPath : `${cwd.replace(/\\/g, "/")}/${jsonPath}`;
|
|
4182
4544
|
};
|
|
4545
|
+
var findCodeFrameStart = (lines) => lines.findIndex((line) => /^\s*(>?\s*\d+\s*\|)/.test(stripAnsiSimple(line)));
|
|
4183
4546
|
var _sourceCache = /* @__PURE__ */ new Map();
|
|
4184
4547
|
var readSource = (file) => {
|
|
4185
|
-
const
|
|
4186
|
-
const
|
|
4187
|
-
if (
|
|
4188
|
-
return
|
|
4548
|
+
const normalized = file.replace(/\\/g, "/");
|
|
4549
|
+
const hit = _sourceCache.get(normalized);
|
|
4550
|
+
if (hit) {
|
|
4551
|
+
return hit;
|
|
4189
4552
|
}
|
|
4190
4553
|
try {
|
|
4191
|
-
const
|
|
4192
|
-
|
|
4193
|
-
_sourceCache.set(normalizedFile, arr);
|
|
4554
|
+
const arr = fs4.readFileSync(normalized, "utf8").split(/\r?\n/);
|
|
4555
|
+
_sourceCache.set(normalized, arr);
|
|
4194
4556
|
return arr;
|
|
4195
4557
|
} catch {
|
|
4196
4558
|
return [];
|
|
4197
4559
|
}
|
|
4198
4560
|
};
|
|
4561
|
+
var renderInlineCodeFrame = (lines, start) => {
|
|
4562
|
+
const out = [];
|
|
4563
|
+
for (let i = start; i < lines.length; i += 1) {
|
|
4564
|
+
const raw = stripAnsiSimple(lines[i]);
|
|
4565
|
+
if (!raw.trim()) {
|
|
4566
|
+
break;
|
|
4567
|
+
}
|
|
4568
|
+
if (/^\s*\^+\s*$/.test(raw)) {
|
|
4569
|
+
out.push(` ${Colors.Failure(raw.trimEnd())}`);
|
|
4570
|
+
} else {
|
|
4571
|
+
const ptr = raw.match(/^\s*>(\s*\d+)\s*\|\s?(.*)$/);
|
|
4572
|
+
if (ptr) {
|
|
4573
|
+
const num = ansi.dim(ptr[1].trim());
|
|
4574
|
+
const code = ansi.yellow(ptr[2] ?? "");
|
|
4575
|
+
out.push(` ${Colors.Failure(">")} ${num} ${ansi.dim("|")} ${code}`);
|
|
4576
|
+
} else {
|
|
4577
|
+
const nor = raw.match(/^\s*(\d+)\s*\|\s?(.*)$/);
|
|
4578
|
+
if (nor) {
|
|
4579
|
+
const num = ansi.dim(nor[1]);
|
|
4580
|
+
const code = ansi.dim(nor[2] ?? "");
|
|
4581
|
+
out.push(` ${num} ${ansi.dim("|")} ${code}`);
|
|
4582
|
+
} else {
|
|
4583
|
+
out.push(` ${raw}`);
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
return out;
|
|
4589
|
+
};
|
|
4199
4590
|
var renderSourceCodeFrame = (file, line, context = 3) => {
|
|
4200
4591
|
const lines = readSource(file);
|
|
4201
|
-
if (
|
|
4592
|
+
if (lines.length === 0 || !Number.isFinite(line)) {
|
|
4202
4593
|
return [];
|
|
4203
4594
|
}
|
|
4204
4595
|
const idx = Math.max(1, Math.min(line, lines.length));
|
|
4205
4596
|
const start = Math.max(1, idx - context);
|
|
4206
4597
|
const end = Math.min(lines.length, idx + context);
|
|
4207
4598
|
const out = [];
|
|
4208
|
-
for (let
|
|
4209
|
-
const num = ansi.dim(String(
|
|
4210
|
-
const code =
|
|
4211
|
-
if (
|
|
4212
|
-
out.push(` ${
|
|
4599
|
+
for (let current = start; current <= end; current += 1) {
|
|
4600
|
+
const num = ansi.dim(String(current));
|
|
4601
|
+
const code = current === idx ? ansi.yellow(lines[current - 1] ?? "") : ansi.dim(lines[current - 1] ?? "");
|
|
4602
|
+
if (current === idx) {
|
|
4603
|
+
out.push(` ${Colors.Failure(">")} ${num} ${ansi.dim("|")} ${code}`);
|
|
4213
4604
|
} else {
|
|
4214
4605
|
out.push(` ${num} ${ansi.dim("|")} ${code}`);
|
|
4215
4606
|
}
|
|
4216
4607
|
}
|
|
4217
|
-
out.push(` ${
|
|
4608
|
+
out.push(` ${Colors.Failure("^")}`);
|
|
4218
4609
|
return out;
|
|
4219
4610
|
};
|
|
4220
|
-
var
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
return i;
|
|
4225
|
-
}
|
|
4611
|
+
var stackLocation = (line) => {
|
|
4612
|
+
const match = stripAnsiSimple(line).match(/\(?([^\s()]+):(\d+):\d+\)?$/);
|
|
4613
|
+
if (!match) {
|
|
4614
|
+
return null;
|
|
4226
4615
|
}
|
|
4227
|
-
return
|
|
4616
|
+
return { file: match[1].replace(/\\/g, "/"), line: Number(match[2]) };
|
|
4228
4617
|
};
|
|
4229
|
-
var
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4618
|
+
var deepestProjectLoc = (stackLines, projectHint) => {
|
|
4619
|
+
for (let i = stackLines.length - 1; i >= 0; i -= 1) {
|
|
4620
|
+
const simple = stripAnsiSimple(stackLines[i]);
|
|
4621
|
+
if (isStackLine(simple) && projectHint.test(simple) && !/node_modules|vitest|jest/.test(simple)) {
|
|
4622
|
+
return stackLocation(stackLines[i]);
|
|
4623
|
+
}
|
|
4233
4624
|
}
|
|
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)}`);
|
|
4625
|
+
return null;
|
|
4241
4626
|
};
|
|
4242
|
-
var
|
|
4243
|
-
var extractAssertionMessage = (msgLines) => {
|
|
4244
|
-
const lines = msgLines.map((rawLine) => stripAnsiSimple(rawLine));
|
|
4627
|
+
var buildCodeFrameSection = (messageLines, ctx, synthLoc) => {
|
|
4245
4628
|
const out = [];
|
|
4246
|
-
const
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
out.push(lines[hintIdx]);
|
|
4251
|
-
}
|
|
4252
|
-
const collectBlock = (start) => {
|
|
4253
|
-
out.push(lines[start]);
|
|
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);
|
|
4629
|
+
const start = findCodeFrameStart(messageLines);
|
|
4630
|
+
if (start >= 0) {
|
|
4631
|
+
out.push(...renderInlineCodeFrame(messageLines, start), "");
|
|
4632
|
+
return out;
|
|
4279
4633
|
}
|
|
4280
|
-
if (
|
|
4281
|
-
|
|
4282
|
-
const candidate = lines[i];
|
|
4283
|
-
if (isTerminator(candidate)) {
|
|
4284
|
-
break;
|
|
4285
|
-
}
|
|
4286
|
-
out.push(candidate);
|
|
4287
|
-
}
|
|
4634
|
+
if (ctx.showStacks && synthLoc) {
|
|
4635
|
+
out.push(...renderSourceCodeFrame(synthLoc.file, synthLoc.line), "");
|
|
4288
4636
|
}
|
|
4289
4637
|
return out;
|
|
4290
4638
|
};
|
|
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
|
-
}
|
|
4639
|
+
var normalizeBlock = (raw) => raw.replace(/^\s*Array\s*\[/, "[").replace(/^\s*Object\s*\{/, "{").replace(/,(\s*[\]}])/g, "$1");
|
|
4640
|
+
var stringifyPrettierish = (value) => {
|
|
4641
|
+
if (typeof value === "string") {
|
|
4642
|
+
const text = normalizeBlock(value.trim());
|
|
4643
|
+
try {
|
|
4644
|
+
const parsed = import_json5.default.parse(text);
|
|
4645
|
+
return JSON.stringify(parsed, null, 2);
|
|
4646
|
+
} catch {
|
|
4647
|
+
return value;
|
|
4405
4648
|
}
|
|
4406
4649
|
}
|
|
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;
|
|
4650
|
+
if (Array.isArray(value) || isObjectRecord(value)) {
|
|
4651
|
+
try {
|
|
4652
|
+
return JSON.stringify(value, null, 2);
|
|
4653
|
+
} catch {
|
|
4654
|
+
return util.inspect(value, {
|
|
4655
|
+
depth: 10,
|
|
4656
|
+
breakLength: Infinity,
|
|
4657
|
+
compact: false,
|
|
4658
|
+
sorted: true
|
|
4659
|
+
});
|
|
4440
4660
|
}
|
|
4441
4661
|
}
|
|
4442
|
-
return {
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4662
|
+
return util.inspect(value, {
|
|
4663
|
+
depth: 10,
|
|
4664
|
+
breakLength: Infinity,
|
|
4665
|
+
compact: false,
|
|
4666
|
+
sorted: true
|
|
4667
|
+
});
|
|
4668
|
+
};
|
|
4669
|
+
var isArrayOfPrimitives = (value) => Array.isArray(value) && value.every(
|
|
4670
|
+
(element) => ["string", "number", "boolean"].includes(typeof element) || element === null
|
|
4671
|
+
);
|
|
4672
|
+
var extractFromUnifiedDiff = (rawLines) => {
|
|
4673
|
+
const lines = (rawLines ?? []).map((lineText) => stripAnsiSimple(lineText));
|
|
4446
4674
|
let startIndex = -1;
|
|
4447
4675
|
for (let i = 0; i < lines.length; i += 1) {
|
|
4448
4676
|
const lt = lines[i];
|
|
@@ -4489,12 +4717,10 @@ function extractFromUnifiedDiff(rawLines) {
|
|
|
4489
4717
|
receivedParts.push(unsigned);
|
|
4490
4718
|
}
|
|
4491
4719
|
if (!expDone && expectedParts.length > 0) {
|
|
4492
|
-
|
|
4493
|
-
expDone = canParseJsonish(expJoined);
|
|
4720
|
+
expDone = canParseJsonish(expectedParts.join("\n"));
|
|
4494
4721
|
}
|
|
4495
4722
|
if (!recDone && receivedParts.length > 0) {
|
|
4496
|
-
|
|
4497
|
-
recDone = canParseJsonish(recJoined);
|
|
4723
|
+
recDone = canParseJsonish(receivedParts.join("\n"));
|
|
4498
4724
|
}
|
|
4499
4725
|
if (opened && expDone && recDone) {
|
|
4500
4726
|
break;
|
|
@@ -4524,32 +4750,108 @@ function extractFromUnifiedDiff(rawLines) {
|
|
|
4524
4750
|
result.received = recStr;
|
|
4525
4751
|
}
|
|
4526
4752
|
return result;
|
|
4527
|
-
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4753
|
+
};
|
|
4754
|
+
var extractExpectedReceived = (details, lines) => {
|
|
4755
|
+
if (details) {
|
|
4756
|
+
for (const detail of details) {
|
|
4757
|
+
const dict = isObjectRecord(detail) ? detail : void 0;
|
|
4758
|
+
const matcher = dict && isObjectRecord(dict.matcherResult) ? dict.matcherResult : void 0;
|
|
4759
|
+
if (matcher) {
|
|
4760
|
+
const expectedValue = matcher.expected;
|
|
4761
|
+
const receivedValue = matcher.received;
|
|
4762
|
+
const matcherName = String(
|
|
4763
|
+
matcher.matcherName || ""
|
|
4764
|
+
);
|
|
4765
|
+
if (matcherName === "toHaveBeenCalledTimes" || matcherName === "toBeCalledTimes") {
|
|
4766
|
+
const getCallsCount = (actual) => {
|
|
4767
|
+
if (isObjectRecord(actual) && Array.isArray(actual.calls)) {
|
|
4768
|
+
return actual.calls.length;
|
|
4769
|
+
}
|
|
4770
|
+
if (typeof actual === "number") {
|
|
4771
|
+
return actual;
|
|
4772
|
+
}
|
|
4773
|
+
if (Array.isArray(actual)) {
|
|
4774
|
+
return actual.length;
|
|
4775
|
+
}
|
|
4776
|
+
return void 0;
|
|
4777
|
+
};
|
|
4778
|
+
const expectedNumber = getCallsCount(expectedValue);
|
|
4779
|
+
const actualValue = matcher.actual ?? receivedValue;
|
|
4780
|
+
const receivedNumber = getCallsCount(actualValue);
|
|
4781
|
+
if (expectedNumber !== void 0 || receivedNumber !== void 0) {
|
|
4782
|
+
return { expected: expectedNumber, received: receivedNumber };
|
|
4783
|
+
}
|
|
4784
|
+
}
|
|
4785
|
+
if (expectedValue !== void 0 && receivedValue !== void 0) {
|
|
4786
|
+
return { expected: expectedValue, received: receivedValue };
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
if (lines && lines.length) {
|
|
4792
|
+
const expectedLines = [];
|
|
4793
|
+
const receivedLines = [];
|
|
4794
|
+
let mode = "none";
|
|
4795
|
+
for (const rawLine of lines) {
|
|
4796
|
+
const simple = stripAnsiSimple(rawLine);
|
|
4797
|
+
if (/^\s*Expected:/.test(simple)) {
|
|
4798
|
+
mode = "exp";
|
|
4799
|
+
expectedLines.push(simple.replace(/^\s*Expected:\s*/, ""));
|
|
4800
|
+
continue;
|
|
4801
|
+
}
|
|
4802
|
+
if (/^\s*Received:/.test(simple)) {
|
|
4803
|
+
mode = "rec";
|
|
4804
|
+
receivedLines.push(simple.replace(/^\s*Received:\s*/, ""));
|
|
4805
|
+
continue;
|
|
4806
|
+
}
|
|
4807
|
+
if (/^\s*[-+]\s/.test(simple)) {
|
|
4808
|
+
continue;
|
|
4809
|
+
}
|
|
4810
|
+
if (!simple.trim()) {
|
|
4811
|
+
mode = "none";
|
|
4812
|
+
} else if (mode === "exp") {
|
|
4813
|
+
expectedLines.push(simple);
|
|
4814
|
+
} else if (mode === "rec") {
|
|
4815
|
+
receivedLines.push(simple);
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
if (expectedLines.length || receivedLines.length) {
|
|
4819
|
+
return { expected: expectedLines.join("\n"), received: receivedLines.join("\n") };
|
|
4820
|
+
}
|
|
4821
|
+
const unified = extractFromUnifiedDiff(lines);
|
|
4822
|
+
if (unified.expected !== void 0 || unified.received !== void 0) {
|
|
4823
|
+
return unified;
|
|
4824
|
+
}
|
|
4533
4825
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4826
|
+
return {};
|
|
4827
|
+
};
|
|
4828
|
+
var buildPrettyDiffSection = (details, messageLines) => {
|
|
4829
|
+
const payload = extractExpectedReceived(details, messageLines);
|
|
4830
|
+
if (payload.expected === void 0 && payload.received === void 0) {
|
|
4831
|
+
return [];
|
|
4832
|
+
}
|
|
4833
|
+
const expectedString = stringifyPrettierish(payload.expected);
|
|
4834
|
+
const receivedString = stringifyPrettierish(payload.received);
|
|
4835
|
+
const out = [];
|
|
4836
|
+
const expectedLenLabel = Array.isArray(payload.expected) ? ansi.dim(` (len ${payload.expected.length})`) : "";
|
|
4837
|
+
out.push(` ${ansi.bold("Expected")}${expectedLenLabel}`);
|
|
4536
4838
|
out.push(
|
|
4537
|
-
|
|
4538
|
-
expected && Array.isArray(expected) ? `(len ${expected.length})` : ""
|
|
4539
|
-
)}`
|
|
4839
|
+
expectedString.split("\n").map((expectedLine) => ` ${Colors.Success(expectedLine)}`).join("\n")
|
|
4540
4840
|
);
|
|
4541
|
-
|
|
4841
|
+
const receivedLenLabel = Array.isArray(payload.received) ? ansi.dim(` (len ${payload.received.length})`) : "";
|
|
4842
|
+
out.push(` ${ansi.bold("Received")}${receivedLenLabel}`);
|
|
4542
4843
|
out.push(
|
|
4543
|
-
|
|
4544
|
-
received && Array.isArray(received) ? `(len ${received.length})` : ""
|
|
4545
|
-
)}`
|
|
4844
|
+
receivedString.split("\n").map((receivedLine) => ` ${Colors.Failure(receivedLine)}`).join("\n")
|
|
4546
4845
|
);
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
const
|
|
4552
|
-
|
|
4846
|
+
if (isArrayOfPrimitives(payload.expected) && isArrayOfPrimitives(payload.received)) {
|
|
4847
|
+
const expectedSet = new Set(
|
|
4848
|
+
payload.expected.map((element) => String(element))
|
|
4849
|
+
);
|
|
4850
|
+
const receivedSet = new Set(
|
|
4851
|
+
payload.received.map((element) => String(element))
|
|
4852
|
+
);
|
|
4853
|
+
const missing = Array.from(expectedSet).filter((element) => !receivedSet.has(element));
|
|
4854
|
+
const unexpected = Array.from(receivedSet).filter((element) => !expectedSet.has(element));
|
|
4553
4855
|
const parts = [];
|
|
4554
4856
|
if (missing.length) {
|
|
4555
4857
|
parts.push(
|
|
@@ -4562,67 +4864,85 @@ function renderPrettyDiff(payload) {
|
|
|
4562
4864
|
);
|
|
4563
4865
|
}
|
|
4564
4866
|
if (parts.length) {
|
|
4565
|
-
out.push(` ${ansi.dim("Difference:")} ${
|
|
4867
|
+
out.push(` ${ansi.dim("Difference:")} ${Colors.Failure(parts.join(ansi.dim(" | ")))}`);
|
|
4566
4868
|
}
|
|
4567
4869
|
}
|
|
4568
4870
|
out.push("");
|
|
4569
4871
|
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)
|
|
4872
|
+
};
|
|
4873
|
+
var buildMessageSection = (messageLines, details, _ctx, opts) => {
|
|
4874
|
+
const out = [];
|
|
4875
|
+
const lines = messageLines.map((lineText) => stripAnsiSimple(lineText));
|
|
4876
|
+
const hintIdx = lines.findIndex(
|
|
4877
|
+
(candidate) => /expect\(.+?\)\.(?:to|not\.)/.test(candidate) || /\b(?:AssertionError|Error):/.test(candidate)
|
|
4578
4878
|
);
|
|
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);
|
|
4879
|
+
const acc = [];
|
|
4880
|
+
if (hintIdx >= 0) {
|
|
4881
|
+
acc.push(lines[hintIdx]);
|
|
4591
4882
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4883
|
+
const pushBlock = (start) => {
|
|
4884
|
+
acc.push(lines[start]);
|
|
4885
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
4886
|
+
const candidate = lines[i];
|
|
4887
|
+
if (!candidate.trim() || isStackLine(candidate)) {
|
|
4888
|
+
break;
|
|
4889
|
+
}
|
|
4890
|
+
acc.push(candidate);
|
|
4891
|
+
}
|
|
4892
|
+
};
|
|
4893
|
+
const expectedIdx = lines.findIndex((lineText) => /^\s*Expected:/.test(lineText));
|
|
4894
|
+
const receivedIdx = lines.findIndex((lineText) => /^\s*Received:/.test(lineText));
|
|
4895
|
+
const diffIdx = lines.findIndex(
|
|
4896
|
+
(lineText) => /^\s*(?:- Expected|\+ Received|Difference:)/.test(lineText)
|
|
4897
|
+
);
|
|
4898
|
+
if (expectedIdx >= 0) {
|
|
4899
|
+
pushBlock(expectedIdx);
|
|
4594
4900
|
}
|
|
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;
|
|
4901
|
+
if (receivedIdx >= 0) {
|
|
4902
|
+
pushBlock(receivedIdx);
|
|
4608
4903
|
}
|
|
4609
|
-
if (
|
|
4610
|
-
|
|
4904
|
+
if (diffIdx >= 0) {
|
|
4905
|
+
pushBlock(diffIdx);
|
|
4611
4906
|
}
|
|
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) => {
|
|
4907
|
+
const filtered = opts?.suppressDiff ? acc.filter((raw) => {
|
|
4618
4908
|
const simple = stripAnsiSimple(raw);
|
|
4619
4909
|
return !/^\s*(Expected:|Received:|Difference:)\b/.test(simple) && !/^\s*[-+]\s/.test(simple) && !/^\s*(Array\s*\[|Object\s*\{)/.test(simple);
|
|
4620
|
-
}) :
|
|
4621
|
-
|
|
4622
|
-
|
|
4910
|
+
}) : acc;
|
|
4911
|
+
const hasOnlyBareError = filtered.length === 0 || filtered.length === 1 && /^\s*(?:Error|AssertionError):?\s*$/.test(filtered[0] ?? "");
|
|
4912
|
+
const fallbackLines = [];
|
|
4913
|
+
if (hasOnlyBareError) {
|
|
4914
|
+
const startFrom = hintIdx >= 0 ? hintIdx + 1 : 0;
|
|
4915
|
+
for (let i = startFrom; i < lines.length; i += 1) {
|
|
4916
|
+
const candidate = lines[i];
|
|
4917
|
+
if (!candidate.trim()) {
|
|
4918
|
+
break;
|
|
4919
|
+
}
|
|
4920
|
+
if (isStackLine(candidate)) {
|
|
4921
|
+
break;
|
|
4922
|
+
}
|
|
4923
|
+
fallbackLines.push(candidate);
|
|
4924
|
+
}
|
|
4925
|
+
if (fallbackLines.length === 0 && details && details.messages && details.messages.length) {
|
|
4926
|
+
fallbackLines.push(
|
|
4927
|
+
...details.messages.map((messageText) => stripAnsiSimple(messageText)).filter((messageText) => messageText.trim().length > 0).slice(0, 6)
|
|
4928
|
+
);
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
if (filtered.length > 0) {
|
|
4932
|
+
const label = (() => {
|
|
4933
|
+
const joined = filtered.join(" ");
|
|
4934
|
+
const matchResult = joined.match(/\b(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/) || joined.match(/\bError\b/);
|
|
4935
|
+
if (matchResult) {
|
|
4936
|
+
const typeName = matchResult[1] ?? "Error";
|
|
4937
|
+
return `${typeName}:`;
|
|
4938
|
+
}
|
|
4939
|
+
return /expect\(.+?\)\.(?:to|not\.)/.test(joined) ? "Assertion:" : "Message:";
|
|
4940
|
+
})();
|
|
4623
4941
|
out.push(` ${ansi.bold(label)}`);
|
|
4624
|
-
|
|
4625
|
-
|
|
4942
|
+
const body = hasOnlyBareError ? fallbackLines : filtered;
|
|
4943
|
+
for (const lineText of body) {
|
|
4944
|
+
const colored = /^\s*-\s/.test(lineText) ? Colors.Failure(lineText) : /^\s*\+\s/.test(lineText) ? Colors.Success(lineText) : lineText;
|
|
4945
|
+
out.push(` ${ansi.yellow(colored)}`);
|
|
4626
4946
|
}
|
|
4627
4947
|
if (opts?.stackPreview && opts.stackPreview.length) {
|
|
4628
4948
|
for (const frame of opts.stackPreview) {
|
|
@@ -4633,32 +4953,85 @@ var buildMessageSection = (messageLines, details, ctx, opts) => {
|
|
|
4633
4953
|
}
|
|
4634
4954
|
return out;
|
|
4635
4955
|
};
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
if (!Array.isArray(maybeConsole)) {
|
|
4642
|
-
return out;
|
|
4956
|
+
var linesFromDetails = (details) => {
|
|
4957
|
+
const stacks = [];
|
|
4958
|
+
const messages = [];
|
|
4959
|
+
if (!details) {
|
|
4960
|
+
return { stacks, messages };
|
|
4643
4961
|
}
|
|
4644
|
-
const
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
}
|
|
4649
|
-
const
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4962
|
+
const pushMaybe = (value, bucket) => {
|
|
4963
|
+
if (typeof value === "string" && value.trim()) {
|
|
4964
|
+
bucket.push(...value.split(/\r?\n/));
|
|
4965
|
+
}
|
|
4966
|
+
};
|
|
4967
|
+
const visitDeep = (value, depth) => {
|
|
4968
|
+
if (depth > 3 || value == null) {
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
if (typeof value === "string") {
|
|
4972
|
+
pushMaybe(value, messages);
|
|
4973
|
+
return;
|
|
4974
|
+
}
|
|
4975
|
+
if (typeof value !== "object") {
|
|
4976
|
+
return;
|
|
4977
|
+
}
|
|
4978
|
+
const obj = value;
|
|
4979
|
+
if (typeof obj.message === "string") {
|
|
4980
|
+
pushMaybe(obj.message, messages);
|
|
4981
|
+
}
|
|
4982
|
+
if (typeof obj.stack === "string") {
|
|
4983
|
+
pushMaybe(obj.stack, stacks);
|
|
4984
|
+
}
|
|
4985
|
+
if (typeof obj.expected === "string") {
|
|
4986
|
+
pushMaybe(obj.expected, messages);
|
|
4987
|
+
}
|
|
4988
|
+
if (typeof obj.received === "string") {
|
|
4989
|
+
pushMaybe(obj.received, messages);
|
|
4990
|
+
}
|
|
4991
|
+
const arrays = ["errors", "causes", "aggregatedErrors"];
|
|
4992
|
+
for (const key of arrays) {
|
|
4993
|
+
const arr = obj[key];
|
|
4994
|
+
if (Array.isArray(arr)) {
|
|
4995
|
+
for (const element of arr) {
|
|
4996
|
+
visitDeep(element, depth + 1);
|
|
4997
|
+
}
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
const nestedCandidates = ["error", "cause", "matcherResult"];
|
|
5001
|
+
for (const key of nestedCandidates) {
|
|
5002
|
+
if (obj[key] && typeof obj[key] === "object") {
|
|
5003
|
+
visitDeep(obj[key], depth + 1);
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
};
|
|
5007
|
+
for (const detail of details) {
|
|
5008
|
+
if (typeof detail === "string") {
|
|
5009
|
+
if (/\s+at\s.+\(.+:\d+:\d+\)/.test(detail)) {
|
|
5010
|
+
pushMaybe(detail, stacks);
|
|
5011
|
+
} else {
|
|
5012
|
+
pushMaybe(detail, messages);
|
|
5013
|
+
}
|
|
5014
|
+
} else if (isObjectRecord(detail)) {
|
|
5015
|
+
pushMaybe(detail.stack, stacks);
|
|
5016
|
+
pushMaybe(detail.message, messages);
|
|
5017
|
+
const err = isObjectRecord(detail.error) ? detail.error : void 0;
|
|
5018
|
+
if (err) {
|
|
5019
|
+
pushMaybe(err.stack, stacks);
|
|
5020
|
+
pushMaybe(err.message, messages);
|
|
5021
|
+
}
|
|
5022
|
+
const matcher = isObjectRecord(detail.matcherResult) ? detail.matcherResult : void 0;
|
|
5023
|
+
if (matcher) {
|
|
5024
|
+
pushMaybe(matcher.stack, stacks);
|
|
5025
|
+
pushMaybe(matcher.message, messages);
|
|
5026
|
+
pushMaybe(matcher.expected, messages);
|
|
5027
|
+
pushMaybe(matcher.received, messages);
|
|
5028
|
+
}
|
|
5029
|
+
if (messages.length === 0 && stacks.length === 0) {
|
|
5030
|
+
visitDeep(detail, 0);
|
|
5031
|
+
}
|
|
4658
5032
|
}
|
|
4659
|
-
out.push("");
|
|
4660
5033
|
}
|
|
4661
|
-
return
|
|
5034
|
+
return { stacks, messages };
|
|
4662
5035
|
};
|
|
4663
5036
|
var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
4664
5037
|
const out = [];
|
|
@@ -4667,13 +5040,18 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
4667
5040
|
out.push(` ${ansi.dim("(hidden by TEST_CLI_STACKS=)")}`, "");
|
|
4668
5041
|
return out;
|
|
4669
5042
|
}
|
|
4670
|
-
const
|
|
5043
|
+
const onlyStack = mergedForStack.filter(
|
|
5044
|
+
(lineText) => isStackLine(stripAnsiSimple(lineText))
|
|
5045
|
+
);
|
|
5046
|
+
const tail = onlyStack.slice(-4);
|
|
4671
5047
|
if (tail.length) {
|
|
4672
|
-
|
|
5048
|
+
for (const frameLine of tail) {
|
|
5049
|
+
out.push(` ${colorStackLine(String(frameLine), ctx.projectHint)}`);
|
|
5050
|
+
}
|
|
4673
5051
|
const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
4674
5052
|
if (loc) {
|
|
4675
5053
|
const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
|
|
4676
|
-
out.push(` ${ansi.dim("at")} ${osc8(`${
|
|
5054
|
+
out.push(` ${ansi.dim("at")} ${osc8(`${loc.file.split("/").pop()}:${loc.line}`, href)}`);
|
|
4677
5055
|
}
|
|
4678
5056
|
out.push("");
|
|
4679
5057
|
return out;
|
|
@@ -4688,171 +5066,460 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
4688
5066
|
out.push(` ${ansi.dim("(no stack provided)")}`, "");
|
|
4689
5067
|
return out;
|
|
4690
5068
|
};
|
|
4691
|
-
var
|
|
4692
|
-
var
|
|
5069
|
+
var MAX_CONSOLE_ERRORS_TO_SHOW = 3;
|
|
5070
|
+
var isConsoleEntry = (candidate) => typeof candidate === "object" && candidate !== null;
|
|
5071
|
+
var buildConsoleSection = (maybeConsole) => {
|
|
4693
5072
|
const out = [];
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
5073
|
+
if (!Array.isArray(maybeConsole)) {
|
|
5074
|
+
return out;
|
|
5075
|
+
}
|
|
5076
|
+
const entries = maybeConsole.filter(isConsoleEntry);
|
|
5077
|
+
const errorsOnly = entries.filter((entry) => String(entry?.type ?? "").toLowerCase() === "error");
|
|
5078
|
+
const scored = errorsOnly.map((entry) => {
|
|
5079
|
+
const raw = entry?.message;
|
|
5080
|
+
const msg = Array.isArray(raw) ? raw.map(String).join(" ") : typeof raw === "string" ? raw : String(raw ?? "");
|
|
5081
|
+
return { msg, score: msg.length };
|
|
5082
|
+
}).filter((item) => item.msg.trim().length > 0).sort((left, right) => right.score - left.score).slice(0, MAX_CONSOLE_ERRORS_TO_SHOW);
|
|
5083
|
+
if (scored.length) {
|
|
5084
|
+
out.push(ansi.dim(" Console errors:"));
|
|
5085
|
+
for (const item of scored) {
|
|
5086
|
+
out.push(` ${ansi.dim("\u2022")} ${item.msg}`);
|
|
4705
5087
|
}
|
|
5088
|
+
out.push("");
|
|
4706
5089
|
}
|
|
4707
|
-
out.push("");
|
|
4708
5090
|
return out;
|
|
4709
5091
|
};
|
|
4710
|
-
var
|
|
4711
|
-
const
|
|
4712
|
-
const
|
|
4713
|
-
const
|
|
4714
|
-
|
|
5092
|
+
var buildFallbackMessageBlock = (messageLines, details) => {
|
|
5093
|
+
const normalize2 = (arr) => arr.map((lineText) => stripAnsiSimple(lineText)).filter((line) => line.trim().length > 0);
|
|
5094
|
+
const normalized = normalize2(messageLines);
|
|
5095
|
+
const informative = normalized.filter((line) => !/^\s*(?:Error|AssertionError):?\s*$/.test(line));
|
|
5096
|
+
if (informative.length > 0) {
|
|
5097
|
+
return [];
|
|
5098
|
+
}
|
|
5099
|
+
const errorIdx = normalized.findIndex(
|
|
5100
|
+
(line) => /(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError|Error):?/.test(line)
|
|
4715
5101
|
);
|
|
4716
|
-
const
|
|
4717
|
-
|
|
5102
|
+
const collected = [];
|
|
5103
|
+
if (errorIdx >= 0) {
|
|
5104
|
+
for (let i = errorIdx; i < normalized.length && collected.length < 8; i += 1) {
|
|
5105
|
+
const ln = normalized[i];
|
|
5106
|
+
if (!ln.trim()) {
|
|
5107
|
+
break;
|
|
5108
|
+
}
|
|
5109
|
+
if (isStackLine(ln)) {
|
|
5110
|
+
break;
|
|
5111
|
+
}
|
|
5112
|
+
collected.push(ln);
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
const fromDetails = collected.length > 0 ? [] : normalize2(details.messages).slice(0, 6);
|
|
5116
|
+
const linesToShow = collected.length > 0 ? collected : fromDetails;
|
|
5117
|
+
if (linesToShow.length === 0) {
|
|
5118
|
+
return [];
|
|
5119
|
+
}
|
|
4718
5120
|
const out = [];
|
|
4719
|
-
|
|
4720
|
-
const
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
5121
|
+
out.push(` ${ansi.bold("Message:")}`);
|
|
5122
|
+
for (const lineText of linesToShow) {
|
|
5123
|
+
out.push(` ${ansi.yellow(lineText)}`);
|
|
5124
|
+
}
|
|
5125
|
+
out.push("");
|
|
5126
|
+
return out;
|
|
5127
|
+
};
|
|
5128
|
+
var buildThrownSection = (details) => {
|
|
5129
|
+
const toLines = (value) => {
|
|
5130
|
+
if (value == null) {
|
|
5131
|
+
return [];
|
|
5132
|
+
}
|
|
5133
|
+
if (typeof value === "string") {
|
|
5134
|
+
return value.split(/\r?\n/);
|
|
5135
|
+
}
|
|
5136
|
+
try {
|
|
5137
|
+
return JSON.stringify(value, null, 2).split(/\r?\n/);
|
|
5138
|
+
} catch {
|
|
5139
|
+
return [String(value)];
|
|
5140
|
+
}
|
|
5141
|
+
};
|
|
5142
|
+
const candidates = [];
|
|
5143
|
+
for (const d of details) {
|
|
5144
|
+
const obj = d && typeof d === "object" ? d : null;
|
|
5145
|
+
if (obj && obj.error && typeof obj.error === "object") {
|
|
5146
|
+
const err = obj.error;
|
|
5147
|
+
if (typeof err.name === "string") {
|
|
5148
|
+
candidates.push(`name: ${err.name}`);
|
|
4735
5149
|
}
|
|
4736
|
-
|
|
4737
|
-
(
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
if (
|
|
4743
|
-
|
|
5150
|
+
if (typeof err.message === "string") {
|
|
5151
|
+
candidates.push(`message: ${err.message}`);
|
|
5152
|
+
}
|
|
5153
|
+
if (typeof err.code === "string" || typeof err.code === "number") {
|
|
5154
|
+
candidates.push(`code: ${String(err.code)}`);
|
|
5155
|
+
}
|
|
5156
|
+
if (typeof err.cause === "string") {
|
|
5157
|
+
candidates.push(`cause: ${err.cause}`);
|
|
5158
|
+
}
|
|
5159
|
+
if (err.cause && typeof err.cause === "object") {
|
|
5160
|
+
candidates.push("cause:");
|
|
5161
|
+
candidates.push(...toLines(err.cause));
|
|
5162
|
+
}
|
|
5163
|
+
const rest = { ...err };
|
|
5164
|
+
delete rest.name;
|
|
5165
|
+
delete rest.message;
|
|
5166
|
+
delete rest.code;
|
|
5167
|
+
delete rest.stack;
|
|
5168
|
+
if (Object.keys(rest).length > 0) {
|
|
5169
|
+
candidates.push("details:");
|
|
5170
|
+
candidates.push(...toLines(rest));
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
}
|
|
5174
|
+
if (!candidates.length) {
|
|
5175
|
+
return [];
|
|
5176
|
+
}
|
|
5177
|
+
const out = [];
|
|
5178
|
+
out.push(` ${ansi.bold("Thrown:")}`);
|
|
5179
|
+
for (const line of candidates.slice(0, 50)) {
|
|
5180
|
+
out.push(` ${ansi.yellow(line)}`);
|
|
5181
|
+
}
|
|
5182
|
+
out.push("");
|
|
5183
|
+
return out;
|
|
5184
|
+
};
|
|
5185
|
+
var mkPrettyFns = () => ({
|
|
5186
|
+
drawRule,
|
|
5187
|
+
drawFailLine,
|
|
5188
|
+
renderRunLine,
|
|
5189
|
+
buildPerFileOverview,
|
|
5190
|
+
buildFileBadgeLine,
|
|
5191
|
+
extractBridgePath,
|
|
5192
|
+
buildCodeFrameSection,
|
|
5193
|
+
buildMessageSection,
|
|
5194
|
+
buildPrettyDiffSection,
|
|
5195
|
+
buildStackSection,
|
|
5196
|
+
deepestProjectLoc,
|
|
5197
|
+
findCodeFrameStart,
|
|
5198
|
+
linesFromDetails,
|
|
5199
|
+
buildFallbackMessageBlock,
|
|
5200
|
+
buildThrownSection
|
|
5201
|
+
});
|
|
5202
|
+
|
|
5203
|
+
// src/lib/formatter/render.ts
|
|
5204
|
+
var relPath = (abs, cwd) => abs.replace(/\\/g, "/").replace(`${cwd}/`, "");
|
|
5205
|
+
var renderChunks = (chunks, ctx, fns, opts) => {
|
|
5206
|
+
const out = [];
|
|
5207
|
+
const seenFiles = /* @__PURE__ */ new Set();
|
|
5208
|
+
const seenFailures = /* @__PURE__ */ new Set();
|
|
5209
|
+
const onlyFailures = Boolean(opts?.onlyFailures);
|
|
5210
|
+
let currentRelFile = null;
|
|
5211
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5212
|
+
for (const ch of chunks) {
|
|
5213
|
+
if (ch.tag === "PassFail") {
|
|
5214
|
+
const rel = relPath(ch.rel, ctx.cwd);
|
|
5215
|
+
if (seenFiles.has(rel)) {
|
|
4744
5216
|
continue;
|
|
4745
5217
|
}
|
|
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
|
-
|
|
5218
|
+
seenFiles.add(rel);
|
|
5219
|
+
currentRelFile = rel;
|
|
5220
|
+
if (!(onlyFailures && ch.badge === "PASS")) {
|
|
5221
|
+
out.push(fns.buildFileBadgeLine(rel, ch.badge === "FAIL" ? 1 : 0));
|
|
5222
|
+
}
|
|
5223
|
+
continue;
|
|
5224
|
+
}
|
|
5225
|
+
if (ch.tag === "FailureBlock") {
|
|
5226
|
+
out.push(fns.drawFailLine());
|
|
5227
|
+
const location = firstTestLocation(ch.lines, ctx.projectHint);
|
|
5228
|
+
const rel = location ? relPath(location.split(":")[0] ?? "", ctx.cwd) : "";
|
|
5229
|
+
const headerText = rel ? `${rel} > ${ch.title}` : ch.title;
|
|
5230
|
+
out.push(`${Colors.Failure("\xD7")} ${ansi.white(headerText)}`);
|
|
5231
|
+
const codeStart = fns.findCodeFrameStart(ch.lines);
|
|
5232
|
+
const collapsedForSrc = collapseStacks(ch.lines.slice(0));
|
|
5233
|
+
const deepestLoc = fns.deepestProjectLoc(collapsedForSrc, ctx.projectHint);
|
|
5234
|
+
let effectiveLoc = deepestLoc;
|
|
5235
|
+
if (!effectiveLoc && currentRelFile) {
|
|
5236
|
+
try {
|
|
5237
|
+
const abs = path9.resolve(ctx.cwd, currentRelFile);
|
|
5238
|
+
const source = ctx.readSource(abs);
|
|
5239
|
+
const testName = (() => {
|
|
5240
|
+
const parts = ch.title.split(">");
|
|
5241
|
+
return (parts[parts.length - 1] || ch.title).trim();
|
|
5242
|
+
})();
|
|
5243
|
+
const itRe = new RegExp(
|
|
5244
|
+
String.raw`\b(?:it|test)\s*\(\s*['\"]${escapeRegExp(testName)}['\"]`
|
|
5245
|
+
);
|
|
5246
|
+
let index = source.findIndex((line) => itRe.test(line));
|
|
5247
|
+
if (index < 0) {
|
|
5248
|
+
index = source.findIndex((line) => /\bexpect\s*\(/.test(line));
|
|
5249
|
+
} else {
|
|
5250
|
+
const windowEnd = Math.min(source.length, index + 80);
|
|
5251
|
+
for (let i = index; i < windowEnd; i += 1) {
|
|
5252
|
+
if (/\bexpect\s*\(/.test(source[i])) {
|
|
5253
|
+
index = i;
|
|
5254
|
+
break;
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
if (index >= 0) {
|
|
5259
|
+
effectiveLoc = { file: abs.replace(/\\/g, "/"), line: index + 1 };
|
|
5260
|
+
}
|
|
5261
|
+
} catch {
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
if (codeStart >= 0) {
|
|
5265
|
+
out.push("", ...fns.buildCodeFrameSection(ch.lines, ctx, effectiveLoc), "");
|
|
5266
|
+
} else {
|
|
5267
|
+
out.push("", ...fns.buildCodeFrameSection(ch.lines, ctx, effectiveLoc), "");
|
|
5268
|
+
}
|
|
5269
|
+
const pretty = fns.buildPrettyDiffSection(void 0, ch.lines);
|
|
5270
|
+
out.push(...pretty);
|
|
5271
|
+
const hasPretty = pretty.length > 0;
|
|
5272
|
+
const details = fns.linesFromDetails(void 0);
|
|
5273
|
+
const minimal = (() => {
|
|
5274
|
+
const plain = ch.lines.map((ln) => stripAnsiSimple(ln));
|
|
5275
|
+
const hint = plain.findIndex(
|
|
5276
|
+
(lineText) => /expect\(.+?\)\.(?:to|not\.)/.test(lineText) || /\bError:?\b/.test(lineText)
|
|
5277
|
+
);
|
|
5278
|
+
const acc = [];
|
|
5279
|
+
const start = hint >= 0 ? hint : 0;
|
|
5280
|
+
for (let i = start; i < plain.length; i += 1) {
|
|
5281
|
+
const ln = plain[i];
|
|
5282
|
+
if (!ln.trim()) {
|
|
5283
|
+
break;
|
|
5284
|
+
}
|
|
5285
|
+
if (isStackLine(ln)) {
|
|
5286
|
+
break;
|
|
5287
|
+
}
|
|
5288
|
+
acc.push(ln);
|
|
5289
|
+
}
|
|
5290
|
+
return acc;
|
|
5291
|
+
})();
|
|
5292
|
+
const collapsedForTail = collapseStacks(ch.lines.slice(0));
|
|
5293
|
+
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
5294
|
out.push(
|
|
4772
|
-
...buildMessageSection(
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
{ suppressDiff: hasPretty, stackPreview }
|
|
4777
|
-
)
|
|
5295
|
+
...fns.buildMessageSection(minimal.length ? minimal : ch.lines, details, ctx, {
|
|
5296
|
+
suppressDiff: hasPretty,
|
|
5297
|
+
stackPreview
|
|
5298
|
+
})
|
|
4778
5299
|
);
|
|
4779
|
-
if (
|
|
4780
|
-
|
|
4781
|
-
out.push(
|
|
4782
|
-
...buildStackSection(collapsed, {
|
|
4783
|
-
projectHint,
|
|
4784
|
-
editorCmd: opts?.editorCmd,
|
|
4785
|
-
showStacks
|
|
4786
|
-
})
|
|
4787
|
-
);
|
|
5300
|
+
if (minimal.length === 0 && fns.buildFallbackMessageBlock) {
|
|
5301
|
+
out.push(...fns.buildFallbackMessageBlock(ch.lines, { messages: details.messages }));
|
|
4788
5302
|
}
|
|
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;
|
|
5303
|
+
const consoleInline = (() => {
|
|
5304
|
+
const plain = ch.lines.map((ln) => stripAnsiSimple(ln));
|
|
5305
|
+
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);
|
|
5306
|
+
return cand;
|
|
5307
|
+
})();
|
|
5308
|
+
if (consoleInline.length > 0) {
|
|
5309
|
+
out.push(ansi.dim(" Console errors:"), ...consoleInline.map((ln) => ` ${ln}`), "");
|
|
4802
5310
|
}
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
5311
|
+
if (ctx.showStacks && fns.buildStackSection && stackPreview.length === 0) {
|
|
5312
|
+
const collapsed = collapseStacks(ch.lines.slice(0));
|
|
5313
|
+
out.push(...fns.buildStackSection(collapsed, ctx));
|
|
5314
|
+
}
|
|
5315
|
+
out.push(fns.drawFailLine(), "");
|
|
5316
|
+
if (rel) {
|
|
5317
|
+
seenFailures.add(`${rel}|${ch.title}`);
|
|
4807
5318
|
}
|
|
4808
|
-
lineIndex += 1;
|
|
4809
5319
|
continue;
|
|
4810
5320
|
}
|
|
4811
|
-
if (
|
|
4812
|
-
out.push(
|
|
4813
|
-
lineIndex += 1;
|
|
5321
|
+
if (ch.tag === "Summary") {
|
|
5322
|
+
out.push(ch.line);
|
|
4814
5323
|
continue;
|
|
4815
5324
|
}
|
|
4816
|
-
if (
|
|
4817
|
-
if (showStacks) {
|
|
4818
|
-
|
|
4819
|
-
out.push(...kept);
|
|
5325
|
+
if (ch.tag === "Stack") {
|
|
5326
|
+
if (ctx.showStacks) {
|
|
5327
|
+
out.push(ch.line);
|
|
4820
5328
|
}
|
|
4821
|
-
lineIndex += 1;
|
|
4822
5329
|
continue;
|
|
4823
5330
|
}
|
|
4824
|
-
|
|
4825
|
-
|
|
5331
|
+
if (!onlyFailures) {
|
|
5332
|
+
out.push(ch.line);
|
|
5333
|
+
}
|
|
4826
5334
|
}
|
|
4827
|
-
const
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
5335
|
+
const hadParsed = seenFiles.size > 0 || seenFailures.size > 0 || out.some((lineText) => /^(?:\s*)(PASS|FAIL)\b/.test(stripAnsiSimple(lineText)));
|
|
5336
|
+
return { text: out.join("\n"), hadParsed };
|
|
5337
|
+
};
|
|
5338
|
+
|
|
5339
|
+
// src/lib/formatter/context.ts
|
|
5340
|
+
var fs5 = __toESM(require("node:fs"), 1);
|
|
5341
|
+
var makeCtx = (opts, showStacks = false) => {
|
|
5342
|
+
const cwd = (opts?.cwd ?? process.cwd()).replace(/\\/g, "/");
|
|
5343
|
+
const width = Math.max(
|
|
5344
|
+
40,
|
|
5345
|
+
process.stdout && process.stdout.columns || 80
|
|
5346
|
+
);
|
|
5347
|
+
const projectHint = new RegExp(
|
|
5348
|
+
`(${cwd.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})|(/gigworx-node/)`
|
|
5349
|
+
);
|
|
5350
|
+
const readSource2 = (file) => {
|
|
5351
|
+
try {
|
|
5352
|
+
return fs5.readFileSync(file.replace(/\\/g, "/"), "utf8").split(/\r?\n/);
|
|
5353
|
+
} catch {
|
|
5354
|
+
return [];
|
|
4841
5355
|
}
|
|
5356
|
+
};
|
|
5357
|
+
return { cwd, width, showStacks, projectHint, editorCmd: opts?.editorCmd, readSource: readSource2 };
|
|
5358
|
+
};
|
|
5359
|
+
|
|
5360
|
+
// src/lib/formatter/bridge.ts
|
|
5361
|
+
var fs6 = __toESM(require("node:fs"), 1);
|
|
5362
|
+
var path10 = __toESM(require("node:path"), 1);
|
|
5363
|
+
var import_json52 = __toESM(require_lib(), 1);
|
|
5364
|
+
var colorTokens2 = {
|
|
5365
|
+
pass: Colors.Success,
|
|
5366
|
+
fail: Colors.Failure,
|
|
5367
|
+
skip: Colors.Skip,
|
|
5368
|
+
todo: Colors.Todo,
|
|
5369
|
+
passPill: (text) => BackgroundColors.Success(ansi.white(` ${text} `)),
|
|
5370
|
+
failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `))
|
|
5371
|
+
};
|
|
5372
|
+
var by = (keySelector) => (left, right) => keySelector(left) - keySelector(right);
|
|
5373
|
+
var isObject = (candidateValue) => !!candidateValue && typeof candidateValue === "object";
|
|
5374
|
+
var asHttpList = (candidateValue) => Array.isArray(candidateValue) ? candidateValue : [];
|
|
5375
|
+
var summarizeUrl = (method, url, route) => {
|
|
5376
|
+
const base = route || url || "";
|
|
5377
|
+
const qs = url && url.includes("?") ? ` ? ${url.split("?")[1]}` : "";
|
|
5378
|
+
return [method || "", base, qs].filter(Boolean).join(" ").trim();
|
|
5379
|
+
};
|
|
5380
|
+
var stripBridgeEventsFromConsole = (maybeConsole) => {
|
|
5381
|
+
if (!Array.isArray(maybeConsole)) {
|
|
5382
|
+
return maybeConsole;
|
|
4842
5383
|
}
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5384
|
+
return maybeConsole.filter((entry) => {
|
|
5385
|
+
try {
|
|
5386
|
+
const raw = Array.isArray(entry.message) ? entry.message.map(String).join(" ") : String(entry.message ?? "");
|
|
5387
|
+
return !raw.includes("[JEST-BRIDGE-EVENT]");
|
|
5388
|
+
} catch {
|
|
5389
|
+
return true;
|
|
5390
|
+
}
|
|
5391
|
+
});
|
|
5392
|
+
};
|
|
5393
|
+
var extractBridgePath2 = (raw, cwd) => {
|
|
5394
|
+
const matches = Array.from(
|
|
5395
|
+
raw.matchAll(/Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g)
|
|
5396
|
+
);
|
|
5397
|
+
if (!matches.length) {
|
|
5398
|
+
return null;
|
|
5399
|
+
}
|
|
5400
|
+
const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["'`]|["'`]$/g, "");
|
|
5401
|
+
return path10.isAbsolute(jsonPath) ? jsonPath : path10.resolve(cwd, jsonPath).replace(/\\/g, "/");
|
|
5402
|
+
};
|
|
5403
|
+
var isTransportError = (msg) => {
|
|
5404
|
+
const lowercaseMessage = (msg ?? "").toLowerCase();
|
|
5405
|
+
return /\bsocket hang up\b|\beconnreset\b|\betimedout\b|\beconnrefused\b|\bwrite epipe\b/.test(
|
|
5406
|
+
lowercaseMessage
|
|
5407
|
+
);
|
|
5408
|
+
};
|
|
5409
|
+
var envNumber = (name, fallback) => {
|
|
5410
|
+
const parsed = Number(process.env[name]);
|
|
5411
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
5412
|
+
};
|
|
5413
|
+
var HEADLAMP_HTTP_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_WINDOW_MS", 3e3);
|
|
5414
|
+
var HEADLAMP_HTTP_STRICT_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_STRICT_WINDOW_MS", 600);
|
|
5415
|
+
var HEADLAMP_HTTP_MIN_SCORE = () => envNumber("HEADLAMP_HTTP_MIN_SCORE", 1200);
|
|
5416
|
+
var HEADLAMP_HTTP_DIFF_LIMIT = () => envNumber("HEADLAMP_HTTP_DIFF_LIMIT", 6);
|
|
5417
|
+
var HEADLAMP_HTTP_SHOW_MISS = () => process.env.HEADLAMP_HTTP_MISS === "1";
|
|
5418
|
+
var eventsNear = (http, ts, testPath, windowMs = HEADLAMP_HTTP_WINDOW_MS()) => {
|
|
5419
|
+
if (typeof ts !== "number" || !Number.isFinite(ts)) {
|
|
5420
|
+
return [];
|
|
5421
|
+
}
|
|
5422
|
+
return http.filter((e) => {
|
|
5423
|
+
const timeOk = typeof e.timestampMs === "number" && Math.abs(e.timestampMs - ts) <= windowMs;
|
|
5424
|
+
const pathOk = !testPath || e.testPath === testPath;
|
|
5425
|
+
return timeOk && pathOk;
|
|
5426
|
+
});
|
|
5427
|
+
};
|
|
5428
|
+
var parseMethodPathFromTitle = (title) => {
|
|
5429
|
+
if (!title) {
|
|
5430
|
+
return {};
|
|
5431
|
+
}
|
|
5432
|
+
const matchResult = title.match(/\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+([^\s)]+)/i);
|
|
5433
|
+
return matchResult ? { method: matchResult[1]?.toUpperCase(), path: matchResult[2] } : {};
|
|
5434
|
+
};
|
|
5435
|
+
var isHttpStatusNumber = (statusNumber) => typeof statusNumber === "number" && statusNumber >= 100 && statusNumber <= 599;
|
|
5436
|
+
var hasStatusSemantics = (assertionLike) => {
|
|
5437
|
+
if (!assertionLike) {
|
|
5438
|
+
return false;
|
|
4848
5439
|
}
|
|
4849
|
-
|
|
5440
|
+
if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
|
|
5441
|
+
return true;
|
|
5442
|
+
}
|
|
5443
|
+
const combinedRaw = `${assertionLike.matcher ?? ""} ${assertionLike.message ?? ""}`;
|
|
5444
|
+
const combinedMessage = combinedRaw.toLowerCase();
|
|
5445
|
+
return /\bstatus(code)?\b|\btohaves(tatus|tatuscode)\b/.test(combinedMessage);
|
|
5446
|
+
};
|
|
5447
|
+
var fileSuggestsHttp = (relPath2) => /(?:^|\/)(routes?|api|controllers?|e2e|integration)(?:\/|\.test\.)/i.test(relPath2);
|
|
5448
|
+
var inferHttpNumbersFromText = (lines) => {
|
|
5449
|
+
const text = lines.join("\n");
|
|
5450
|
+
const match = text.match(/Expected:\s*(\d{3})[\s\S]*?Received:\s*(\d{3})/i);
|
|
5451
|
+
if (match) {
|
|
5452
|
+
return { expectedNumber: Number(match[1]), receivedNumber: Number(match[2]) };
|
|
5453
|
+
}
|
|
5454
|
+
return {};
|
|
5455
|
+
};
|
|
5456
|
+
var titleSuggestsHttp = (title) => {
|
|
5457
|
+
const { method, path: parsedPath } = parseMethodPathFromTitle(title);
|
|
5458
|
+
return Boolean(method || parsedPath && parsedPath.startsWith("/"));
|
|
5459
|
+
};
|
|
5460
|
+
var isHttpRelevant = (ctx) => {
|
|
5461
|
+
const assertionCtx = ctx.assertion;
|
|
5462
|
+
return ctx.hasTransportSignal || ctx.httpCountInSameTest > 0 || titleSuggestsHttp(ctx.title) || hasStatusSemantics(assertionCtx) || fileSuggestsHttp(ctx.relPath);
|
|
5463
|
+
};
|
|
5464
|
+
var routeSimilarityScore = (hint, evt) => {
|
|
5465
|
+
if (!hint.path && !hint.method) {
|
|
5466
|
+
return 0;
|
|
5467
|
+
}
|
|
5468
|
+
const methodOk = hint.method && evt.method ? Number(hint.method === evt.method) : 0;
|
|
5469
|
+
const route = evt.route || evt.url || "";
|
|
5470
|
+
if (!route) {
|
|
5471
|
+
return methodOk * 10;
|
|
5472
|
+
}
|
|
5473
|
+
if (hint.path && route === hint.path) {
|
|
5474
|
+
return 500 + methodOk * 50;
|
|
5475
|
+
}
|
|
5476
|
+
if (hint.path && route.endsWith(hint.path)) {
|
|
5477
|
+
return 300 + methodOk * 50;
|
|
5478
|
+
}
|
|
5479
|
+
if (hint.path && route.includes(hint.path)) {
|
|
5480
|
+
return 200 + methodOk * 50;
|
|
5481
|
+
}
|
|
5482
|
+
return methodOk * 10;
|
|
4850
5483
|
};
|
|
4851
|
-
var
|
|
4852
|
-
const
|
|
4853
|
-
|
|
5484
|
+
var scoreHttpForAssertion = (assertion, titleHint) => (candidateEvent) => {
|
|
5485
|
+
const tsA = assertion.timestampMs;
|
|
5486
|
+
const tsH = candidateEvent.timestampMs;
|
|
5487
|
+
const window = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
|
|
5488
|
+
const timeScore = typeof tsA === "number" && typeof tsH === "number" ? Math.max(0, window - Math.abs(tsA - tsH)) : 0;
|
|
5489
|
+
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;
|
|
5490
|
+
const routeScore = routeSimilarityScore(titleHint, candidateEvent);
|
|
5491
|
+
const specificity = candidateEvent.route ? 80 : candidateEvent.url ? 40 : 0;
|
|
5492
|
+
return timeScore + statusScore + routeScore + specificity;
|
|
5493
|
+
};
|
|
5494
|
+
var pickRelevantHttp = (assertion, http, ctx) => {
|
|
5495
|
+
const hint = parseMethodPathFromTitle(ctx.title);
|
|
5496
|
+
const nameMatches = (leftName, rightName) => !!leftName && !!rightName && (leftName === rightName || leftName.includes(rightName) || rightName.includes(leftName));
|
|
5497
|
+
const sameTest = (leftCtx, rightCtx) => !!leftCtx && !!rightCtx && leftCtx.testPath === rightCtx.testPath && nameMatches(leftCtx.currentTestName, rightCtx.currentTestName);
|
|
5498
|
+
const strictPool = http.filter(
|
|
5499
|
+
(httpEvent) => sameTest(assertion, httpEvent) || sameTest(ctx, httpEvent)
|
|
5500
|
+
);
|
|
5501
|
+
const windowMs = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
|
|
5502
|
+
let pool = strictPool;
|
|
5503
|
+
if (!pool.length) {
|
|
5504
|
+
pool = http.filter(
|
|
5505
|
+
(e) => e.testPath === ctx.testPath && typeof assertion.timestampMs === "number" && typeof e.timestampMs === "number" && Math.abs(e.timestampMs - assertion.timestampMs) <= windowMs
|
|
5506
|
+
);
|
|
5507
|
+
}
|
|
5508
|
+
if (!pool.length) {
|
|
5509
|
+
pool = http.filter(
|
|
5510
|
+
(e) => typeof assertion.timestampMs === "number" && typeof e.timestampMs === "number" && Math.abs(e.timestampMs - assertion.timestampMs) <= windowMs
|
|
5511
|
+
);
|
|
5512
|
+
}
|
|
5513
|
+
if (!pool.length) {
|
|
5514
|
+
return void 0;
|
|
5515
|
+
}
|
|
5516
|
+
const scored = pool.map((httpEvent) => ({ h: httpEvent, s: scoreHttpForAssertion(assertion, hint)(httpEvent) })).sort((leftScore, rightScore) => rightScore.s - leftScore.s);
|
|
5517
|
+
const [best] = scored;
|
|
5518
|
+
const threshold = isTransportError(assertion.message) ? Math.max(HEADLAMP_HTTP_MIN_SCORE(), 1400) : HEADLAMP_HTTP_MIN_SCORE();
|
|
5519
|
+
return best && best.s >= threshold ? best.h : void 0;
|
|
4854
5520
|
};
|
|
4855
|
-
|
|
5521
|
+
var isBridgeJSONLike = (candidateValue) => !!candidateValue && typeof candidateValue === "object" && "aggregated" in candidateValue;
|
|
5522
|
+
var coerceJestJsonToBridge = (raw) => {
|
|
4856
5523
|
if (isBridgeJSONLike(raw)) {
|
|
4857
5524
|
return raw;
|
|
4858
5525
|
}
|
|
@@ -4862,18 +5529,21 @@ function coerceJestJsonToBridge(raw) {
|
|
|
4862
5529
|
}
|
|
4863
5530
|
return {
|
|
4864
5531
|
startTime: Number(j.startTime ?? Date.now()),
|
|
4865
|
-
testResults: j.testResults.map((
|
|
4866
|
-
testFilePath:
|
|
4867
|
-
status:
|
|
4868
|
-
failureMessage:
|
|
4869
|
-
failureDetails:
|
|
4870
|
-
|
|
5532
|
+
testResults: j.testResults.map((tr) => ({
|
|
5533
|
+
testFilePath: tr.testFilePath || tr.name || "",
|
|
5534
|
+
status: tr.status,
|
|
5535
|
+
failureMessage: tr.failureMessage || "",
|
|
5536
|
+
failureDetails: tr.failureDetails ?? [],
|
|
5537
|
+
testExecError: tr.testExecError ?? null,
|
|
5538
|
+
console: tr.console ?? null,
|
|
5539
|
+
testResults: (tr.assertionResults || []).map((assertion) => ({
|
|
4871
5540
|
title: assertion.title,
|
|
4872
5541
|
fullName: assertion.fullName || [...assertion.ancestorTitles || [], assertion.title].join(" "),
|
|
4873
5542
|
status: assertion.status,
|
|
4874
5543
|
duration: assertion.duration || 0,
|
|
4875
5544
|
location: assertion.location ?? null,
|
|
4876
|
-
failureMessages: assertion.failureMessages || []
|
|
5545
|
+
failureMessages: assertion.failureMessages || [],
|
|
5546
|
+
failureDetails: assertion.failureDetails || []
|
|
4877
5547
|
}))
|
|
4878
5548
|
})),
|
|
4879
5549
|
aggregated: {
|
|
@@ -4889,21 +5559,20 @@ function coerceJestJsonToBridge(raw) {
|
|
|
4889
5559
|
success: j.success
|
|
4890
5560
|
}
|
|
4891
5561
|
};
|
|
4892
|
-
}
|
|
4893
|
-
var vitestFooter = (agg,
|
|
5562
|
+
};
|
|
5563
|
+
var vitestFooter = (agg, durationMs) => {
|
|
4894
5564
|
const files = [
|
|
4895
|
-
agg.numFailedTestSuites ?
|
|
4896
|
-
agg.numPassedTestSuites ?
|
|
4897
|
-
agg.numPendingTests ?
|
|
5565
|
+
agg.numFailedTestSuites ? colorTokens2.fail(`${agg.numFailedTestSuites} failed`) : "",
|
|
5566
|
+
agg.numPassedTestSuites ? colorTokens2.pass(`${agg.numPassedTestSuites} passed`) : "",
|
|
5567
|
+
agg.numPendingTests ? colorTokens2.skip(`${agg.numPendingTests} skipped`) : ""
|
|
4898
5568
|
].filter(Boolean).join(ansi.dim(" | "));
|
|
4899
5569
|
const tests = [
|
|
4900
|
-
agg.numFailedTests ?
|
|
4901
|
-
agg.numPassedTests ?
|
|
4902
|
-
agg.numPendingTests ?
|
|
4903
|
-
agg.numTodoTests ?
|
|
5570
|
+
agg.numFailedTests ? colorTokens2.fail(`${agg.numFailedTests} failed`) : "",
|
|
5571
|
+
agg.numPassedTests ? colorTokens2.pass(`${agg.numPassedTests} passed`) : "",
|
|
5572
|
+
agg.numPendingTests ? colorTokens2.skip(`${agg.numPendingTests} skipped`) : "",
|
|
5573
|
+
agg.numTodoTests ? colorTokens2.todo(`${agg.numTodoTests} todo`) : ""
|
|
4904
5574
|
].filter(Boolean).join(ansi.dim(" | "));
|
|
4905
|
-
const
|
|
4906
|
-
const time = durMs != null ? `${Math.max(0, Math.round(durMs))}ms` : "";
|
|
5575
|
+
const time = durationMs != null ? `${Math.max(0, Math.round(durationMs))}ms` : typeof agg.runTimeMs === "number" ? `${Math.max(0, Math.round(agg.runTimeMs))}ms` : "";
|
|
4907
5576
|
const thread = ansi.dim("(in thread 0ms, 0.00%)");
|
|
4908
5577
|
return [
|
|
4909
5578
|
`${ansi.bold("Test Files")} ${files} ${ansi.dim(`(${agg.numTotalTestSuites})`)}`,
|
|
@@ -4911,20 +5580,14 @@ var vitestFooter = (agg, _startedAt, durationMs) => {
|
|
|
4911
5580
|
`${ansi.bold("Time")} ${time} ${thread}`
|
|
4912
5581
|
].join("\n");
|
|
4913
5582
|
};
|
|
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);
|
|
5583
|
+
var renderVitestFromJestJSON = (data, ctx, opts) => {
|
|
4921
5584
|
const out = [];
|
|
5585
|
+
const onlyFailures = Boolean(opts?.onlyFailures);
|
|
4922
5586
|
if (!onlyFailures) {
|
|
4923
|
-
out.push(
|
|
4924
|
-
out.push("");
|
|
5587
|
+
out.push(`${BackgroundColors.Run(ansi.white(" RUN "))} ${ansi.dim(ctx.cwd)}`, "");
|
|
4925
5588
|
}
|
|
4926
5589
|
for (const file of data.testResults) {
|
|
4927
|
-
const rel = file.testFilePath.replace(/\\/g, "/").replace(`${cwd}/`, "");
|
|
5590
|
+
const rel = file.testFilePath.replace(/\\/g, "/").replace(`${ctx.cwd}/`, "");
|
|
4928
5591
|
const failed = file.testResults.filter((assertion) => assertion.status === "failed");
|
|
4929
5592
|
if (!onlyFailures) {
|
|
4930
5593
|
out.push(...buildPerFileOverview(rel, file.testResults));
|
|
@@ -4932,79 +5595,490 @@ function renderVitestFromJestJSON(data, opts) {
|
|
|
4932
5595
|
if (!(onlyFailures && failed.length === 0)) {
|
|
4933
5596
|
out.push(buildFileBadgeLine(rel, failed.length));
|
|
4934
5597
|
}
|
|
4935
|
-
|
|
5598
|
+
let httpSorted = [];
|
|
5599
|
+
let assertionEvents = [];
|
|
5600
|
+
{
|
|
5601
|
+
const parseBridge = (consoleEntries) => {
|
|
5602
|
+
const http = [];
|
|
5603
|
+
const assertions = [];
|
|
5604
|
+
if (!Array.isArray(consoleEntries)) {
|
|
5605
|
+
return { http, assertions };
|
|
5606
|
+
}
|
|
5607
|
+
for (const entry of consoleEntries) {
|
|
5608
|
+
const rec = entry;
|
|
5609
|
+
const rawMsgVal = rec && typeof rec.message !== "undefined" ? rec.message : "";
|
|
5610
|
+
const raw = Array.isArray(rawMsgVal) ? rawMsgVal.map(String).join(" ") : String(rawMsgVal ?? "");
|
|
5611
|
+
if (!raw.includes("[JEST-BRIDGE-EVENT]")) {
|
|
5612
|
+
continue;
|
|
5613
|
+
}
|
|
5614
|
+
const jsonText = raw.split("[JEST-BRIDGE-EVENT]").pop()?.trim() ?? "";
|
|
5615
|
+
try {
|
|
5616
|
+
const evt = import_json52.default.parse(jsonText);
|
|
5617
|
+
const type = evt?.type;
|
|
5618
|
+
if (type === "httpResponse") {
|
|
5619
|
+
const timestampMs = Number(evt.timestampMs ?? Date.now());
|
|
5620
|
+
http.push({
|
|
5621
|
+
kind: "response",
|
|
5622
|
+
timestampMs,
|
|
5623
|
+
method: evt.method,
|
|
5624
|
+
url: evt.url,
|
|
5625
|
+
route: evt.route,
|
|
5626
|
+
statusCode: evt.statusCode,
|
|
5627
|
+
durationMs: evt.durationMs,
|
|
5628
|
+
contentType: evt.contentType,
|
|
5629
|
+
requestId: evt.requestId,
|
|
5630
|
+
json: evt.json,
|
|
5631
|
+
bodyPreview: evt.bodyPreview,
|
|
5632
|
+
testPath: evt.testPath,
|
|
5633
|
+
currentTestName: evt.currentTestName
|
|
5634
|
+
});
|
|
5635
|
+
} else if (type === "httpAbort") {
|
|
5636
|
+
http.push({
|
|
5637
|
+
kind: "abort",
|
|
5638
|
+
timestampMs: Number(evt.timestampMs ?? Date.now()),
|
|
5639
|
+
method: evt.method,
|
|
5640
|
+
url: evt.url,
|
|
5641
|
+
route: evt.route,
|
|
5642
|
+
durationMs: evt.durationMs,
|
|
5643
|
+
testPath: evt.testPath,
|
|
5644
|
+
currentTestName: evt.currentTestName
|
|
5645
|
+
});
|
|
5646
|
+
} else if (type === "httpResponseBatch") {
|
|
5647
|
+
const list = asHttpList(evt?.events);
|
|
5648
|
+
for (const item of list) {
|
|
5649
|
+
const anyItem = item;
|
|
5650
|
+
http.push({
|
|
5651
|
+
timestampMs: Number(anyItem.timestampMs ?? Date.now()),
|
|
5652
|
+
method: anyItem.method,
|
|
5653
|
+
url: anyItem.url,
|
|
5654
|
+
route: anyItem.route,
|
|
5655
|
+
statusCode: anyItem.statusCode,
|
|
5656
|
+
durationMs: anyItem.durationMs,
|
|
5657
|
+
contentType: anyItem.contentType,
|
|
5658
|
+
requestId: anyItem.requestId,
|
|
5659
|
+
json: anyItem.json,
|
|
5660
|
+
bodyPreview: anyItem.bodyPreview,
|
|
5661
|
+
testPath: evt.testPath,
|
|
5662
|
+
currentTestName: evt.currentTestName
|
|
5663
|
+
});
|
|
5664
|
+
}
|
|
5665
|
+
} else if (type === "assertionFailure") {
|
|
5666
|
+
assertions.push({
|
|
5667
|
+
timestampMs: typeof evt.timestampMs === "number" ? evt.timestampMs : void 0,
|
|
5668
|
+
matcher: evt.matcher,
|
|
5669
|
+
expectedNumber: typeof evt.expectedNumber === "number" ? evt.expectedNumber : void 0,
|
|
5670
|
+
receivedNumber: typeof evt.receivedNumber === "number" ? evt.receivedNumber : void 0,
|
|
5671
|
+
message: typeof evt.message === "string" ? evt.message : void 0,
|
|
5672
|
+
stack: typeof evt.stack === "string" ? evt.stack : void 0,
|
|
5673
|
+
testPath: evt.testPath,
|
|
5674
|
+
currentTestName: evt.currentTestName,
|
|
5675
|
+
expectedPreview: typeof evt.expectedPreview === "string" ? evt.expectedPreview : void 0,
|
|
5676
|
+
actualPreview: typeof evt.actualPreview === "string" ? evt.actualPreview : void 0
|
|
5677
|
+
});
|
|
5678
|
+
}
|
|
5679
|
+
} catch {
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
return { http, assertions };
|
|
5683
|
+
};
|
|
5684
|
+
const parsed = parseBridge(file.console);
|
|
5685
|
+
httpSorted = [...parsed.http].sort(by((event) => event.timestampMs));
|
|
5686
|
+
assertionEvents = parsed.assertions;
|
|
5687
|
+
}
|
|
5688
|
+
const inSameCtx = (testPath, testName) => httpSorted.filter(
|
|
5689
|
+
(event) => event.testPath === testPath && event.currentTestName === testName
|
|
5690
|
+
);
|
|
5691
|
+
if (file.failureMessage || file.testExecError) {
|
|
4936
5692
|
const lines = file.failureMessage.split(/\r?\n/);
|
|
4937
|
-
const
|
|
4938
|
-
|
|
4939
|
-
|
|
5693
|
+
const combinedDetails = (() => {
|
|
5694
|
+
const base = linesFromDetails(file.failureDetails);
|
|
5695
|
+
const exec = linesFromDetails(
|
|
5696
|
+
Array.isArray(file.testExecError) ? file.testExecError : [file.testExecError]
|
|
5697
|
+
);
|
|
5698
|
+
return {
|
|
5699
|
+
stacks: [...base.stacks, ...exec.stacks],
|
|
5700
|
+
messages: [...base.messages, ...exec.messages]
|
|
5701
|
+
};
|
|
5702
|
+
})();
|
|
5703
|
+
const mergedForStack = collapseStacks([...lines, ...combinedDetails.stacks]);
|
|
5704
|
+
const synthLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
4940
5705
|
out.push(...buildCodeFrameSection(lines, ctx, synthLoc));
|
|
4941
|
-
const
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
const stackPreview = ctx.showStacks ?
|
|
5706
|
+
const payloadPretty = buildPrettyDiffSection(file.failureDetails, lines);
|
|
5707
|
+
out.push(...payloadPretty);
|
|
5708
|
+
const hasPretty = payloadPretty.length > 0;
|
|
5709
|
+
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
5710
|
out.push(
|
|
4946
|
-
...buildMessageSection(lines,
|
|
5711
|
+
...buildMessageSection(lines, combinedDetails, ctx, {
|
|
4947
5712
|
suppressDiff: hasPretty,
|
|
4948
5713
|
stackPreview
|
|
4949
5714
|
})
|
|
4950
5715
|
);
|
|
4951
|
-
out.push(...buildConsoleSection(file.console ?? null));
|
|
5716
|
+
out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
|
|
4952
5717
|
if (ctx.showStacks && stackPreview.length === 0) {
|
|
4953
|
-
|
|
5718
|
+
const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
|
|
5719
|
+
if (tail.length) {
|
|
5720
|
+
out.push(ansi.dim(" Stack:"), ...tail, "");
|
|
5721
|
+
}
|
|
4954
5722
|
}
|
|
4955
5723
|
}
|
|
4956
|
-
for (const
|
|
5724
|
+
for (const assertion of failed) {
|
|
4957
5725
|
out.push(drawFailLine());
|
|
4958
|
-
const header = `${rel} > ${
|
|
4959
|
-
const messagesArray =
|
|
4960
|
-
|
|
5726
|
+
const header = `${rel} > ${assertion.fullName}`;
|
|
5727
|
+
const messagesArray = (() => {
|
|
5728
|
+
if (assertion.failureMessages && assertion.failureMessages.length > 0) {
|
|
5729
|
+
return assertion.failureMessages;
|
|
5730
|
+
}
|
|
5731
|
+
if (file.failureMessage && file.failureMessage.trim().length > 0) {
|
|
5732
|
+
return file.failureMessage.split(/\r?\n/);
|
|
5733
|
+
}
|
|
5734
|
+
const linesFromMatcher = linesFromDetails(
|
|
5735
|
+
assertion.failureDetails || file.failureDetails
|
|
5736
|
+
).messages;
|
|
5737
|
+
if (Array.isArray(linesFromMatcher) && linesFromMatcher.length > 0) {
|
|
5738
|
+
return linesFromMatcher;
|
|
5739
|
+
}
|
|
5740
|
+
return [""];
|
|
5741
|
+
})();
|
|
5742
|
+
const details = linesFromDetails(assertion.failureDetails || file.failureDetails);
|
|
5743
|
+
const matcherMsg = (() => {
|
|
5744
|
+
try {
|
|
5745
|
+
const arr = assertion.failureDetails || file.failureDetails;
|
|
5746
|
+
if (!arr) {
|
|
5747
|
+
return [];
|
|
5748
|
+
}
|
|
5749
|
+
for (const detailEntry of arr) {
|
|
5750
|
+
const obj = detailEntry && typeof detailEntry === "object" ? detailEntry : null;
|
|
5751
|
+
const mr = obj && obj.matcherResult && typeof obj.matcherResult === "object" ? obj.matcherResult : null;
|
|
5752
|
+
if (mr && typeof mr.message === "string" && mr.message.trim()) {
|
|
5753
|
+
const name = typeof mr.matcherName === "string" ? mr.matcherName : "";
|
|
5754
|
+
const matcherHeader = name ? ` ${ansi.bold("Matcher:")} ${ansi.yellow(name)}` : "";
|
|
5755
|
+
const bodyHeader = ` ${ansi.bold("Message:")}`;
|
|
5756
|
+
const body = String(mr.message).split(/\r?\n/).slice(0, 6).map((ln) => ` ${ansi.yellow(ln)}`);
|
|
5757
|
+
return [matcherHeader, bodyHeader, ...body, ""].filter(Boolean);
|
|
5758
|
+
}
|
|
5759
|
+
}
|
|
5760
|
+
} catch {
|
|
5761
|
+
}
|
|
5762
|
+
return [];
|
|
5763
|
+
})();
|
|
4961
5764
|
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 = `${
|
|
5765
|
+
const deepestLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
5766
|
+
const locLink = deepestLoc ? (() => {
|
|
5767
|
+
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, ctx.editorCmd);
|
|
5768
|
+
const base = `${deepestLoc.file.split("/").pop()}:${deepestLoc.line}`;
|
|
4966
5769
|
return osc8(base, href);
|
|
4967
|
-
})();
|
|
5770
|
+
})() : void 0;
|
|
5771
|
+
const bullet = (text) => `${Colors.Failure("\xD7")} ${ansi.white(text)}`;
|
|
4968
5772
|
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
4969
|
-
const bullet = (text) => `${colorTokens.fail("\xD7")} ${ansi.white(text)}`;
|
|
4970
5773
|
out.push(bullet(headerLine));
|
|
4971
5774
|
const msgLines = messagesArray.join("\n").split("\n");
|
|
4972
|
-
const assertFallback = deepestLoc ||
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
const stackPreview = ctx.showStacks ?
|
|
5775
|
+
const assertFallback = deepestLoc || assertion.location && { file: file.testFilePath, line: assertion.location.line };
|
|
5776
|
+
out.push("", ...buildCodeFrameSection(msgLines, ctx, assertFallback || void 0), "");
|
|
5777
|
+
const pretty = buildPrettyDiffSection(
|
|
5778
|
+
assertion.failureDetails || file.failureDetails,
|
|
5779
|
+
msgLines
|
|
5780
|
+
);
|
|
5781
|
+
out.push(...pretty);
|
|
5782
|
+
const hasPretty = pretty.length > 0;
|
|
5783
|
+
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)}`) : [];
|
|
5784
|
+
if (matcherMsg.length) {
|
|
5785
|
+
out.push(...matcherMsg);
|
|
5786
|
+
}
|
|
4981
5787
|
out.push(
|
|
4982
5788
|
...buildMessageSection(msgLines, details, ctx, { suppressDiff: hasPretty, stackPreview })
|
|
4983
5789
|
);
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
5790
|
+
{
|
|
5791
|
+
const HEADLAMP_HTTP_DIFF_LIMIT_LOCAL = () => HEADLAMP_HTTP_DIFF_LIMIT();
|
|
5792
|
+
const safeParseJSON = (text) => {
|
|
5793
|
+
try {
|
|
5794
|
+
return text ? import_json52.default.parse(text) : void 0;
|
|
5795
|
+
} catch {
|
|
5796
|
+
return void 0;
|
|
5797
|
+
}
|
|
5798
|
+
};
|
|
5799
|
+
const jsonDiff = (expected, actual, limit = HEADLAMP_HTTP_DIFF_LIMIT_LOCAL()) => {
|
|
5800
|
+
const outChanges = [];
|
|
5801
|
+
const queue = [];
|
|
5802
|
+
queue.push({
|
|
5803
|
+
pathSoFar: "$",
|
|
5804
|
+
expectedValue: expected,
|
|
5805
|
+
actualValue: actual
|
|
5806
|
+
});
|
|
5807
|
+
while (queue.length && outChanges.length < limit) {
|
|
5808
|
+
const { pathSoFar, expectedValue, actualValue } = queue.shift();
|
|
5809
|
+
const expectedIsObj = expectedValue && typeof expectedValue === "object";
|
|
5810
|
+
const actualIsObj = actualValue && typeof actualValue === "object";
|
|
5811
|
+
if (!expectedIsObj && !actualIsObj) {
|
|
5812
|
+
if (JSON.stringify(expectedValue) !== JSON.stringify(actualValue)) {
|
|
5813
|
+
outChanges.push({
|
|
5814
|
+
kind: "changed",
|
|
5815
|
+
path: pathSoFar,
|
|
5816
|
+
preview: `${String(expectedValue)} \u2192 ${String(actualValue)}`
|
|
5817
|
+
});
|
|
5818
|
+
}
|
|
5819
|
+
} else if (expectedIsObj && !actualIsObj) {
|
|
5820
|
+
outChanges.push({
|
|
5821
|
+
kind: "changed",
|
|
5822
|
+
path: pathSoFar,
|
|
5823
|
+
preview: "[object] \u2192 primitive"
|
|
5824
|
+
});
|
|
5825
|
+
} else if (!expectedIsObj && actualIsObj) {
|
|
5826
|
+
outChanges.push({
|
|
5827
|
+
kind: "changed",
|
|
5828
|
+
path: pathSoFar,
|
|
5829
|
+
preview: "primitive \u2192 [object]"
|
|
5830
|
+
});
|
|
5831
|
+
} else {
|
|
5832
|
+
const expectedKeys = new Set(Object.keys(expectedValue));
|
|
5833
|
+
const actualKeys = new Set(Object.keys(actualValue));
|
|
5834
|
+
for (const key of expectedKeys) {
|
|
5835
|
+
if (!actualKeys.has(key) && outChanges.length < limit) {
|
|
5836
|
+
outChanges.push({ kind: "removed", path: `${pathSoFar}.${key}` });
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
for (const key of actualKeys) {
|
|
5840
|
+
if (!expectedKeys.has(key) && outChanges.length < limit) {
|
|
5841
|
+
outChanges.push({ kind: "added", path: `${pathSoFar}.${key}` });
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
for (const key of expectedKeys) {
|
|
5845
|
+
if (actualKeys.has(key) && outChanges.length < limit) {
|
|
5846
|
+
queue.push({
|
|
5847
|
+
pathSoFar: `${pathSoFar}.${key}`,
|
|
5848
|
+
expectedValue: expectedValue[key],
|
|
5849
|
+
actualValue: actualValue[key]
|
|
5850
|
+
});
|
|
5851
|
+
}
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
return outChanges;
|
|
5856
|
+
};
|
|
5857
|
+
const importantMessages = (json) => {
|
|
5858
|
+
const msgs = [];
|
|
5859
|
+
try {
|
|
5860
|
+
const obj = isObject(json) ? json : {};
|
|
5861
|
+
const pushMaybe = (candidate) => {
|
|
5862
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
5863
|
+
msgs.push(candidate);
|
|
5864
|
+
}
|
|
5865
|
+
};
|
|
5866
|
+
pushMaybe(obj.displayMessage);
|
|
5867
|
+
pushMaybe(obj.message);
|
|
5868
|
+
if (Array.isArray(obj.errors)) {
|
|
5869
|
+
for (const element of obj.errors) {
|
|
5870
|
+
pushMaybe(isObject(element) ? element.message : void 0);
|
|
5871
|
+
}
|
|
5872
|
+
}
|
|
5873
|
+
if (Array.isArray(obj.data)) {
|
|
5874
|
+
for (const element of obj.data) {
|
|
5875
|
+
pushMaybe(isObject(element) ? element.message : void 0);
|
|
5876
|
+
}
|
|
5877
|
+
}
|
|
5878
|
+
} catch {
|
|
5879
|
+
}
|
|
5880
|
+
return msgs.slice(0, 2);
|
|
5881
|
+
};
|
|
5882
|
+
const nameMatches = (leftName, rightName) => !!leftName && !!rightName && (leftName === rightName || leftName.includes(rightName) || rightName.includes(leftName));
|
|
5883
|
+
const corresponding = assertionEvents.find(
|
|
5884
|
+
(aevt) => aevt.testPath === file.testFilePath && nameMatches(aevt.currentTestName, assertion.title)
|
|
5885
|
+
) ?? assertion;
|
|
5886
|
+
const perTestSlice = inSameCtx(file.testFilePath, assertion.title);
|
|
5887
|
+
const nearByTime = eventsNear(
|
|
5888
|
+
httpSorted,
|
|
5889
|
+
corresponding?.timestampMs,
|
|
5890
|
+
file.testFilePath
|
|
4991
5891
|
);
|
|
5892
|
+
const hasAbort = perTestSlice.some((event) => event.kind === "abort");
|
|
5893
|
+
const hasTransport = isTransportError(corresponding?.message) || hasAbort;
|
|
5894
|
+
const httpLikely = isHttpRelevant({
|
|
5895
|
+
assertion: corresponding,
|
|
5896
|
+
title: assertion.fullName,
|
|
5897
|
+
relPath: rel,
|
|
5898
|
+
httpCountInSameTest: perTestSlice.length || nearByTime.length,
|
|
5899
|
+
hasTransportSignal: hasTransport
|
|
5900
|
+
});
|
|
5901
|
+
if (!httpLikely) {
|
|
5902
|
+
} else {
|
|
5903
|
+
const expPreview = corresponding?.expectedPreview;
|
|
5904
|
+
const actPreview = corresponding?.actualPreview;
|
|
5905
|
+
const parsedExpected = safeParseJSON(expPreview);
|
|
5906
|
+
const parsedActual = safeParseJSON(actPreview);
|
|
5907
|
+
let corr = corresponding;
|
|
5908
|
+
if (!isHttpStatusNumber(corr.expectedNumber) && !isHttpStatusNumber(corr.receivedNumber)) {
|
|
5909
|
+
const inferred = inferHttpNumbersFromText(msgLines);
|
|
5910
|
+
if (isHttpStatusNumber(inferred.expectedNumber) || isHttpStatusNumber(inferred.receivedNumber)) {
|
|
5911
|
+
corr = { ...corr, ...inferred };
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5914
|
+
const relevant = pickRelevantHttp(
|
|
5915
|
+
{
|
|
5916
|
+
timestampMs: corr?.timestampMs,
|
|
5917
|
+
expectedNumber: corr?.expectedNumber,
|
|
5918
|
+
receivedNumber: corr?.receivedNumber,
|
|
5919
|
+
matcher: corr?.matcher,
|
|
5920
|
+
message: corr?.message,
|
|
5921
|
+
stack: corr?.stack,
|
|
5922
|
+
testPath: file.testFilePath,
|
|
5923
|
+
currentTestName: assertion.title
|
|
5924
|
+
},
|
|
5925
|
+
httpSorted,
|
|
5926
|
+
{
|
|
5927
|
+
testPath: file.testFilePath,
|
|
5928
|
+
currentTestName: assertion.title,
|
|
5929
|
+
title: assertion.fullName
|
|
5930
|
+
}
|
|
5931
|
+
);
|
|
5932
|
+
if (hasTransport) {
|
|
5933
|
+
const tsBase = corresponding?.timestampMs ?? 0;
|
|
5934
|
+
const abortCandidates = perTestSlice.filter((event) => event.kind === "abort").sort((leftEvent, rightEvent) => {
|
|
5935
|
+
const deltaLeft = Math.abs(tsBase - (leftEvent.timestampMs ?? 0));
|
|
5936
|
+
const deltaRight = Math.abs(tsBase - (rightEvent.timestampMs ?? 0));
|
|
5937
|
+
return deltaLeft - deltaRight;
|
|
5938
|
+
});
|
|
5939
|
+
const [nearestAbort] = abortCandidates;
|
|
5940
|
+
if (nearestAbort) {
|
|
5941
|
+
out.push(
|
|
5942
|
+
" HTTP:",
|
|
5943
|
+
`
|
|
5944
|
+
${summarizeUrl(nearestAbort.method, nearestAbort.url, nearestAbort.route)} ${ansi.dim("->")} ${ansi.yellow("connection aborted")}`,
|
|
5945
|
+
(() => {
|
|
5946
|
+
const ms = nearestAbort.durationMs;
|
|
5947
|
+
return ms != null ? ` ${ansi.dim(`(${ms}ms)`)} ` : "";
|
|
5948
|
+
})(),
|
|
5949
|
+
"\n"
|
|
5950
|
+
);
|
|
5951
|
+
} else if (relevant) {
|
|
5952
|
+
} else if (HEADLAMP_HTTP_SHOW_MISS()) {
|
|
5953
|
+
out.push(
|
|
5954
|
+
" HTTP:",
|
|
5955
|
+
`
|
|
5956
|
+
${ansi.dim("Transport error; no matching HTTP exchange in window.")}`,
|
|
5957
|
+
"\n"
|
|
5958
|
+
);
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
if (!hasTransport && relevant) {
|
|
5962
|
+
const parts = [];
|
|
5963
|
+
const where = summarizeUrl(relevant.method, relevant.url, relevant.route);
|
|
5964
|
+
const line1 = [
|
|
5965
|
+
" HTTP:",
|
|
5966
|
+
`
|
|
5967
|
+
${where} ${ansi.dim("->")} ${relevant.statusCode ?? "?"}`,
|
|
5968
|
+
(() => {
|
|
5969
|
+
const ms = relevant.durationMs;
|
|
5970
|
+
return typeof ms === "number" ? ` ${ansi.dim(`(${ms}ms)`)} ` : " ";
|
|
5971
|
+
})(),
|
|
5972
|
+
relevant.contentType ? ansi.dim(`(${relevant.contentType})`) : "",
|
|
5973
|
+
relevant.requestId ? ansi.dim(` reqId=${relevant.requestId}`) : ""
|
|
5974
|
+
].join("");
|
|
5975
|
+
const expVsAct = (() => {
|
|
5976
|
+
if (typeof corresponding?.expectedNumber === "number" || typeof corresponding?.receivedNumber === "number") {
|
|
5977
|
+
const exp = corresponding?.expectedNumber != null ? String(corresponding.expectedNumber) : "?";
|
|
5978
|
+
const got = corresponding?.receivedNumber != null ? String(corresponding.receivedNumber) : String(relevant.statusCode ?? "?");
|
|
5979
|
+
return `
|
|
5980
|
+
Expected: ${ansi.yellow(exp)} Received: ${ansi.yellow(got)}`;
|
|
5981
|
+
}
|
|
5982
|
+
return "";
|
|
5983
|
+
})();
|
|
5984
|
+
const whyLines = importantMessages(relevant.json).map((msg) => `
|
|
5985
|
+
Why: ${ansi.white(msg)}`).slice(0, 1).join("");
|
|
5986
|
+
const diffLines = (() => {
|
|
5987
|
+
const rightActual = parsedActual ?? relevant.json;
|
|
5988
|
+
if (!parsedExpected || !rightActual) {
|
|
5989
|
+
return "";
|
|
5990
|
+
}
|
|
5991
|
+
const changes = jsonDiff(parsedExpected, rightActual);
|
|
5992
|
+
if (!changes.length) {
|
|
5993
|
+
return "";
|
|
5994
|
+
}
|
|
5995
|
+
const head = "\n Diff:";
|
|
5996
|
+
const body = changes.map((change) => {
|
|
5997
|
+
const marker = change.kind === "added" ? "+" : change.kind === "removed" ? "-" : "~";
|
|
5998
|
+
const previewText = change.preview ? `: ${ansi.dim(change.preview)}` : "";
|
|
5999
|
+
return `
|
|
6000
|
+
${marker} ${change.path}${previewText}`;
|
|
6001
|
+
}).join("");
|
|
6002
|
+
return head + body;
|
|
6003
|
+
})();
|
|
6004
|
+
parts.push(line1, expVsAct, whyLines, diffLines, "\n");
|
|
6005
|
+
out.push(...parts.filter(Boolean));
|
|
6006
|
+
} else if (!hasTransport && !relevant && HEADLAMP_HTTP_SHOW_MISS()) {
|
|
6007
|
+
out.push(
|
|
6008
|
+
" HTTP:",
|
|
6009
|
+
`
|
|
6010
|
+
${ansi.dim("No relevant HTTP exchange found. (HEADLAMP_HTTP_MISS=0 to hide)")}`,
|
|
6011
|
+
"\n"
|
|
6012
|
+
);
|
|
6013
|
+
}
|
|
6014
|
+
}
|
|
4992
6015
|
}
|
|
4993
|
-
|
|
4994
|
-
|
|
6016
|
+
const minimalInfo = msgLines.every((ln) => !ln.trim());
|
|
6017
|
+
if (minimalInfo) {
|
|
6018
|
+
try {
|
|
6019
|
+
out.push(...buildThrownSection(assertion.failureDetails || []));
|
|
6020
|
+
} catch {
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
|
|
6024
|
+
if (ctx.showStacks && stackPreview.length === 0) {
|
|
6025
|
+
const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
|
|
6026
|
+
if (tail.length) {
|
|
6027
|
+
out.push(ansi.dim(" Stack:"), ...tail, "");
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
out.push(drawFailLine(), "");
|
|
4995
6031
|
}
|
|
4996
6032
|
}
|
|
4997
6033
|
const failedCount = data.aggregated.numFailedTests;
|
|
4998
|
-
out.push(drawRule(
|
|
6034
|
+
out.push(drawRule(BackgroundColors.Failure(ansi.white(` Failed Tests ${failedCount} `))));
|
|
4999
6035
|
out.push("");
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
);
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
}
|
|
6036
|
+
out.push(vitestFooter(data.aggregated));
|
|
6037
|
+
return out.join("\n");
|
|
6038
|
+
};
|
|
6039
|
+
var tryBridgeFallback = (raw, ctx, opts) => {
|
|
6040
|
+
const bridgeJsonPath = extractBridgePath2(raw, ctx.cwd);
|
|
6041
|
+
if (!bridgeJsonPath || !fs6.existsSync(bridgeJsonPath)) {
|
|
6042
|
+
return null;
|
|
6043
|
+
}
|
|
6044
|
+
try {
|
|
6045
|
+
const json = import_json52.default.parse(fs6.readFileSync(bridgeJsonPath, "utf8"));
|
|
6046
|
+
const bridge = coerceJestJsonToBridge(json);
|
|
6047
|
+
return renderVitestFromJestJSON(bridge, ctx, opts);
|
|
6048
|
+
} catch {
|
|
6049
|
+
return null;
|
|
6050
|
+
}
|
|
6051
|
+
};
|
|
6052
|
+
|
|
6053
|
+
// src/lib/formatJestOutputVitest.ts
|
|
6054
|
+
var formatJestOutputVitest = (raw, opts) => pipe(
|
|
6055
|
+
{ raw, opts },
|
|
6056
|
+
(state) => ({
|
|
6057
|
+
...state,
|
|
6058
|
+
ctx: makeCtx(state.opts, /\bFAIL\b/.test(stripAnsiSimple(state.raw)))
|
|
6059
|
+
}),
|
|
6060
|
+
(state) => ({ ...state, chunks: parseChunks(state.raw) }),
|
|
6061
|
+
(state) => ({
|
|
6062
|
+
...state,
|
|
6063
|
+
rendered: renderChunks(state.chunks, state.ctx, mkPrettyFns(), {
|
|
6064
|
+
onlyFailures: Boolean(state.opts?.onlyFailures)
|
|
6065
|
+
})
|
|
6066
|
+
}),
|
|
6067
|
+
(state) => {
|
|
6068
|
+
if (state.rendered.hadParsed) {
|
|
6069
|
+
return state.rendered.text;
|
|
6070
|
+
}
|
|
6071
|
+
const fallback = tryBridgeFallback(state.raw, state.ctx, {
|
|
6072
|
+
onlyFailures: Boolean(state.opts?.onlyFailures)
|
|
6073
|
+
});
|
|
6074
|
+
if (!fallback) {
|
|
6075
|
+
return state.rendered.text;
|
|
6076
|
+
}
|
|
6077
|
+
const prefix = state.rendered.text;
|
|
6078
|
+
return prefix ? `${prefix}
|
|
6079
|
+
${fallback}` : fallback;
|
|
6080
|
+
}
|
|
6081
|
+
);
|
|
5008
6082
|
|
|
5009
6083
|
// src/lib/program.ts
|
|
5010
6084
|
var jestBin = "./node_modules/.bin/jest";
|
|
@@ -5049,7 +6123,7 @@ var mergeLcov = async () => {
|
|
|
5049
6123
|
try {
|
|
5050
6124
|
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
5051
6125
|
for (const entry of entries) {
|
|
5052
|
-
const full =
|
|
6126
|
+
const full = path11.join(dir, entry.name);
|
|
5053
6127
|
if (entry.isDirectory()) {
|
|
5054
6128
|
out.push(...collectLcovs(full));
|
|
5055
6129
|
} else if (entry.isFile() && entry.name === "lcov.info") {
|
|
@@ -5061,8 +6135,8 @@ var mergeLcov = async () => {
|
|
|
5061
6135
|
return out;
|
|
5062
6136
|
};
|
|
5063
6137
|
try {
|
|
5064
|
-
const jestRoot =
|
|
5065
|
-
const candidates = [
|
|
6138
|
+
const jestRoot = path11.join("coverage", "jest");
|
|
6139
|
+
const candidates = [path11.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path11.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
|
|
5066
6140
|
for (const filePath of candidates) {
|
|
5067
6141
|
try {
|
|
5068
6142
|
const content = await readOrEmpty(filePath);
|
|
@@ -5102,7 +6176,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5102
6176
|
try {
|
|
5103
6177
|
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
5104
6178
|
for (const entry of entries) {
|
|
5105
|
-
const full =
|
|
6179
|
+
const full = path11.join(dir, entry.name);
|
|
5106
6180
|
if (entry.isDirectory()) {
|
|
5107
6181
|
out.push(...listJsons(full));
|
|
5108
6182
|
} else if (entry.isFile() && entry.name === "coverage-final.json") {
|
|
@@ -5113,11 +6187,11 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5113
6187
|
}
|
|
5114
6188
|
return out;
|
|
5115
6189
|
};
|
|
5116
|
-
const coverageRoot =
|
|
6190
|
+
const coverageRoot = path11.join("coverage", "jest");
|
|
5117
6191
|
const jsonCandidates = [
|
|
5118
|
-
|
|
6192
|
+
path11.join(coverageRoot, "coverage-final.json"),
|
|
5119
6193
|
...listJsons(coverageRoot)
|
|
5120
|
-
].map((candidatePath) =>
|
|
6194
|
+
].map((candidatePath) => path11.resolve(candidatePath)).filter((absolutePath, index, arr) => {
|
|
5121
6195
|
const isFirst = arr.indexOf(absolutePath) === index;
|
|
5122
6196
|
const exists = fsSync3.existsSync(absolutePath);
|
|
5123
6197
|
return isFirst && exists;
|
|
@@ -5179,7 +6253,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5179
6253
|
executedTests: opts.executedTests ?? []
|
|
5180
6254
|
});
|
|
5181
6255
|
const context = LibReport.createContext({
|
|
5182
|
-
dir:
|
|
6256
|
+
dir: path11.resolve("coverage", "merged"),
|
|
5183
6257
|
coverageMap: filteredMap,
|
|
5184
6258
|
defaultSummarizer: "nested"
|
|
5185
6259
|
});
|
|
@@ -5247,8 +6321,8 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5247
6321
|
for (const reporter of reporters) {
|
|
5248
6322
|
reporter.execute(context);
|
|
5249
6323
|
}
|
|
5250
|
-
const textPath =
|
|
5251
|
-
const summaryPath =
|
|
6324
|
+
const textPath = path11.resolve("coverage", "merged", "coverage.txt");
|
|
6325
|
+
const summaryPath = path11.resolve("coverage", "merged", "coverage-summary.txt");
|
|
5252
6326
|
const filesToPrint = [];
|
|
5253
6327
|
if (fsSync3.existsSync(textPath)) {
|
|
5254
6328
|
filesToPrint.push(textPath);
|
|
@@ -5391,13 +6465,13 @@ var program = async () => {
|
|
|
5391
6465
|
const rels2 = Array.from(
|
|
5392
6466
|
/* @__PURE__ */ new Set([...branchDiff, ...stagedNow, ...unstagedNow, ...untrackedNow])
|
|
5393
6467
|
);
|
|
5394
|
-
return rels2.map((rel) =>
|
|
6468
|
+
return rels2.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
5395
6469
|
}
|
|
5396
6470
|
const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
|
|
5397
6471
|
const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
|
|
5398
6472
|
const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
|
|
5399
6473
|
const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
|
|
5400
|
-
return rels.map((rel) =>
|
|
6474
|
+
return rels.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
5401
6475
|
};
|
|
5402
6476
|
const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
|
|
5403
6477
|
const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
|
|
@@ -5422,18 +6496,18 @@ var program = async () => {
|
|
|
5422
6496
|
if (!token) {
|
|
5423
6497
|
continue;
|
|
5424
6498
|
}
|
|
5425
|
-
const isAbs =
|
|
6499
|
+
const isAbs = path11.isAbsolute(token);
|
|
5426
6500
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
5427
6501
|
let candidateFromRoot;
|
|
5428
6502
|
if (token.startsWith("/")) {
|
|
5429
|
-
candidateFromRoot =
|
|
6503
|
+
candidateFromRoot = path11.join(repoRoot, token.slice(1));
|
|
5430
6504
|
} else if (looksLikeRelPath) {
|
|
5431
|
-
candidateFromRoot =
|
|
6505
|
+
candidateFromRoot = path11.join(repoRoot, token);
|
|
5432
6506
|
} else {
|
|
5433
6507
|
candidateFromRoot = void 0;
|
|
5434
6508
|
}
|
|
5435
6509
|
const tryPushIfProd = (absPath) => {
|
|
5436
|
-
const norm =
|
|
6510
|
+
const norm = path11.resolve(absPath).replace(/\\/g, "/");
|
|
5437
6511
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
5438
6512
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
5439
6513
|
results.add(norm);
|
|
@@ -5455,7 +6529,7 @@ var program = async () => {
|
|
|
5455
6529
|
}),
|
|
5456
6530
|
timeoutMs: 4e3
|
|
5457
6531
|
});
|
|
5458
|
-
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) =>
|
|
6532
|
+
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path11.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
|
|
5459
6533
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5460
6534
|
);
|
|
5461
6535
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -5476,8 +6550,8 @@ var program = async () => {
|
|
|
5476
6550
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
5477
6551
|
const projectConfigs = [];
|
|
5478
6552
|
try {
|
|
5479
|
-
const baseCfg =
|
|
5480
|
-
const tsCfg =
|
|
6553
|
+
const baseCfg = path11.resolve("jest.config.js");
|
|
6554
|
+
const tsCfg = path11.resolve("jest.ts.config.js");
|
|
5481
6555
|
if (fsSync3.existsSync(baseCfg)) {
|
|
5482
6556
|
projectConfigs.push(baseCfg);
|
|
5483
6557
|
}
|
|
@@ -5494,7 +6568,7 @@ var program = async () => {
|
|
|
5494
6568
|
);
|
|
5495
6569
|
const prodSelections2 = expandedProdSelections;
|
|
5496
6570
|
for (const cfg of projectConfigs) {
|
|
5497
|
-
const cfgCwd =
|
|
6571
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5498
6572
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5499
6573
|
cwd: cfgCwd
|
|
5500
6574
|
});
|
|
@@ -5507,7 +6581,7 @@ var program = async () => {
|
|
|
5507
6581
|
});
|
|
5508
6582
|
} catch (err) {
|
|
5509
6583
|
if (isDebug()) {
|
|
5510
|
-
console.warn(`direct selection failed for project ${
|
|
6584
|
+
console.warn(`direct selection failed for project ${path11.basename(cfg)}: ${String(err)}`);
|
|
5511
6585
|
}
|
|
5512
6586
|
}
|
|
5513
6587
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -5519,7 +6593,7 @@ var program = async () => {
|
|
|
5519
6593
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
5520
6594
|
);
|
|
5521
6595
|
for (const cfg of projectConfigs) {
|
|
5522
|
-
const cfgCwd =
|
|
6596
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5523
6597
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5524
6598
|
cwd: cfgCwd
|
|
5525
6599
|
});
|
|
@@ -5534,13 +6608,13 @@ var program = async () => {
|
|
|
5534
6608
|
);
|
|
5535
6609
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
5536
6610
|
const absFiles = candidates.map(
|
|
5537
|
-
(candidatePath) =>
|
|
6611
|
+
(candidatePath) => path11.isAbsolute(candidatePath) ? candidatePath : path11.join(repoRootForDiscovery, candidatePath)
|
|
5538
6612
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
5539
6613
|
const onlyOwned = await filterCandidatesForProject(
|
|
5540
6614
|
cfg,
|
|
5541
6615
|
jestDiscoveryArgs,
|
|
5542
6616
|
absFiles,
|
|
5543
|
-
|
|
6617
|
+
path11.dirname(cfg)
|
|
5544
6618
|
);
|
|
5545
6619
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
5546
6620
|
}
|
|
@@ -5552,7 +6626,7 @@ var program = async () => {
|
|
|
5552
6626
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
5553
6627
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
5554
6628
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
5555
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
6629
|
+
const selectionKey = prodSelections.map((absPath) => path11.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
5556
6630
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
5557
6631
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
5558
6632
|
const rgMatches = await cachedRelated2({
|
|
@@ -5582,7 +6656,7 @@ var program = async () => {
|
|
|
5582
6656
|
cfg,
|
|
5583
6657
|
jestDiscoveryArgs,
|
|
5584
6658
|
rgCandidates,
|
|
5585
|
-
|
|
6659
|
+
path11.dirname(cfg)
|
|
5586
6660
|
);
|
|
5587
6661
|
perProjectFromRg.set(cfg, owned);
|
|
5588
6662
|
}
|
|
@@ -5597,9 +6671,9 @@ var program = async () => {
|
|
|
5597
6671
|
} else {
|
|
5598
6672
|
const repoRootForScan = repoRootForDiscovery;
|
|
5599
6673
|
const toSeeds = (abs) => {
|
|
5600
|
-
const rel =
|
|
6674
|
+
const rel = path11.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
5601
6675
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
5602
|
-
const base =
|
|
6676
|
+
const base = path11.basename(withoutExt);
|
|
5603
6677
|
const segs = withoutExt.split("/");
|
|
5604
6678
|
const tail2 = segs.slice(-2).join("/");
|
|
5605
6679
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -5614,8 +6688,8 @@ var program = async () => {
|
|
|
5614
6688
|
}
|
|
5615
6689
|
};
|
|
5616
6690
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5617
|
-
const baseDir =
|
|
5618
|
-
const cand =
|
|
6691
|
+
const baseDir = path11.dirname(fromFile);
|
|
6692
|
+
const cand = path11.resolve(baseDir, spec);
|
|
5619
6693
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5620
6694
|
for (const ext of exts) {
|
|
5621
6695
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -5624,7 +6698,7 @@ var program = async () => {
|
|
|
5624
6698
|
}
|
|
5625
6699
|
}
|
|
5626
6700
|
for (const ext of exts) {
|
|
5627
|
-
const full =
|
|
6701
|
+
const full = path11.join(cand, `index${ext}`);
|
|
5628
6702
|
if (fsSync3.existsSync(full)) {
|
|
5629
6703
|
return full;
|
|
5630
6704
|
}
|
|
@@ -5678,7 +6752,7 @@ var program = async () => {
|
|
|
5678
6752
|
cfg,
|
|
5679
6753
|
jestDiscoveryArgs,
|
|
5680
6754
|
keptCandidates,
|
|
5681
|
-
|
|
6755
|
+
path11.dirname(cfg)
|
|
5682
6756
|
);
|
|
5683
6757
|
perProjectFromScan.set(cfg, owned);
|
|
5684
6758
|
}
|
|
@@ -5708,7 +6782,7 @@ var program = async () => {
|
|
|
5708
6782
|
try {
|
|
5709
6783
|
const allAcross = [];
|
|
5710
6784
|
for (const cfg of projectConfigs) {
|
|
5711
|
-
const cfgCwd =
|
|
6785
|
+
const cfgCwd = path11.dirname(cfg);
|
|
5712
6786
|
const listed = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5713
6787
|
cwd: cfgCwd
|
|
5714
6788
|
});
|
|
@@ -5722,23 +6796,23 @@ var program = async () => {
|
|
|
5722
6796
|
}
|
|
5723
6797
|
}
|
|
5724
6798
|
const seeds = prodSelections.map(
|
|
5725
|
-
(abs) =>
|
|
6799
|
+
(abs) => path11.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
5726
6800
|
).flatMap((rel) => {
|
|
5727
|
-
const base =
|
|
6801
|
+
const base = path11.basename(rel);
|
|
5728
6802
|
const segments = rel.split("/");
|
|
5729
6803
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
5730
6804
|
});
|
|
5731
6805
|
const includesSeed = (text) => seeds.some((seed) => text.includes(seed));
|
|
5732
6806
|
const tryReadFile = async (absPath) => {
|
|
5733
6807
|
try {
|
|
5734
|
-
return await
|
|
6808
|
+
return await fs7.readFile(absPath, "utf8");
|
|
5735
6809
|
} catch {
|
|
5736
6810
|
return "";
|
|
5737
6811
|
}
|
|
5738
6812
|
};
|
|
5739
6813
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5740
|
-
const baseDir =
|
|
5741
|
-
const candidate =
|
|
6814
|
+
const baseDir = path11.dirname(fromFile);
|
|
6815
|
+
const candidate = path11.resolve(baseDir, spec);
|
|
5742
6816
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
5743
6817
|
for (const ext of extensions) {
|
|
5744
6818
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -5747,7 +6821,7 @@ var program = async () => {
|
|
|
5747
6821
|
}
|
|
5748
6822
|
}
|
|
5749
6823
|
for (const ext of extensions) {
|
|
5750
|
-
const fullPath =
|
|
6824
|
+
const fullPath = path11.join(candidate, `index${ext}`);
|
|
5751
6825
|
if (fsSync3.existsSync(fullPath)) {
|
|
5752
6826
|
return fullPath;
|
|
5753
6827
|
}
|
|
@@ -5904,10 +6978,10 @@ var program = async () => {
|
|
|
5904
6978
|
};
|
|
5905
6979
|
const prodSeedsForRun = (() => {
|
|
5906
6980
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
5907
|
-
(absPath) =>
|
|
6981
|
+
(absPath) => path11.resolve(absPath).replace(/\\/g, "/")
|
|
5908
6982
|
);
|
|
5909
6983
|
const selAbs = selectionPathsAugmented.map(
|
|
5910
|
-
(pathToken) =>
|
|
6984
|
+
(pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
|
|
5911
6985
|
);
|
|
5912
6986
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
5913
6987
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -5922,29 +6996,50 @@ var program = async () => {
|
|
|
5922
6996
|
const cfg = projectsToRun[projIndex];
|
|
5923
6997
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
5924
6998
|
if (files.length === 0) {
|
|
5925
|
-
console.info(`Project ${
|
|
6999
|
+
console.info(`Project ${path11.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
5926
7000
|
continue;
|
|
5927
7001
|
}
|
|
5928
7002
|
files.forEach(
|
|
5929
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
7003
|
+
(absTestPath) => executedTestFilesSet.add(path11.resolve(absTestPath).replace(/\\/g, "/"))
|
|
5930
7004
|
);
|
|
5931
|
-
const outJson =
|
|
5932
|
-
|
|
7005
|
+
const outJson = path11.join(
|
|
7006
|
+
os3.tmpdir(),
|
|
5933
7007
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
5934
7008
|
);
|
|
5935
|
-
const reporterPath =
|
|
7009
|
+
const reporterPath = path11.resolve("scripts/jest-vitest-bridge.cjs");
|
|
5936
7010
|
try {
|
|
5937
|
-
|
|
5938
|
-
|
|
7011
|
+
const needsWrite = (() => {
|
|
7012
|
+
try {
|
|
7013
|
+
const existing = fsSync3.readFileSync(reporterPath, "utf8");
|
|
7014
|
+
return existing !== JEST_BRIDGE_REPORTER_SOURCE;
|
|
7015
|
+
} catch {
|
|
7016
|
+
return true;
|
|
7017
|
+
}
|
|
7018
|
+
})();
|
|
7019
|
+
if (needsWrite) {
|
|
7020
|
+
fsSync3.mkdirSync(path11.dirname(reporterPath), { recursive: true });
|
|
5939
7021
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
5940
7022
|
}
|
|
7023
|
+
const envPath = path11.resolve("scripts/jest-bridge-env.cjs");
|
|
7024
|
+
try {
|
|
7025
|
+
const existingEnv = fsSync3.readFileSync(envPath, "utf8");
|
|
7026
|
+
if (existingEnv !== JEST_BRIDGE_ENV_SOURCE) {
|
|
7027
|
+
fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
|
|
7028
|
+
}
|
|
7029
|
+
} catch {
|
|
7030
|
+
try {
|
|
7031
|
+
fsSync3.mkdirSync(path11.dirname(envPath), { recursive: true });
|
|
7032
|
+
} catch {
|
|
7033
|
+
}
|
|
7034
|
+
fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
|
|
7035
|
+
}
|
|
5941
7036
|
} catch (ensureReporterError) {
|
|
5942
7037
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
5943
7038
|
}
|
|
5944
|
-
const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) =>
|
|
7039
|
+
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
7040
|
const coverageFromArgs = [];
|
|
5946
|
-
for (const
|
|
5947
|
-
coverageFromArgs.push("--collectCoverageFrom",
|
|
7041
|
+
for (const relPath2 of selectedFilesForCoverage) {
|
|
7042
|
+
coverageFromArgs.push("--collectCoverageFrom", relPath2);
|
|
5948
7043
|
}
|
|
5949
7044
|
const { code, output } = await runWithCapture(
|
|
5950
7045
|
babelNodeBin,
|
|
@@ -5954,17 +7049,16 @@ var program = async () => {
|
|
|
5954
7049
|
jestBin,
|
|
5955
7050
|
"--config",
|
|
5956
7051
|
cfg,
|
|
7052
|
+
"--testLocationInResults",
|
|
5957
7053
|
"--runTestsByPath",
|
|
5958
7054
|
`--reporters=${reporterPath}`,
|
|
5959
|
-
"--silent",
|
|
5960
7055
|
"--colors",
|
|
5961
|
-
"--
|
|
5962
|
-
"
|
|
5963
|
-
outJson,
|
|
7056
|
+
"--env",
|
|
7057
|
+
path11.resolve("scripts/jest-bridge-env.cjs"),
|
|
5964
7058
|
...sanitizedJestRunArgs,
|
|
5965
7059
|
...collectCoverage ? [
|
|
5966
7060
|
"--coverageDirectory",
|
|
5967
|
-
|
|
7061
|
+
path11.join("coverage", "jest", path11.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
5968
7062
|
] : [],
|
|
5969
7063
|
...coverageFromArgs,
|
|
5970
7064
|
"--passWithNoTests",
|
|
@@ -5997,17 +7091,23 @@ var program = async () => {
|
|
|
5997
7091
|
...bridge,
|
|
5998
7092
|
testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
|
|
5999
7093
|
};
|
|
6000
|
-
pretty = renderVitestFromJestJSON(
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
7094
|
+
pretty = renderVitestFromJestJSON(
|
|
7095
|
+
reordered,
|
|
7096
|
+
makeCtx(
|
|
7097
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7098
|
+
/\bFAIL\b/.test(stripAnsiSimple(output))
|
|
7099
|
+
),
|
|
7100
|
+
{ onlyFailures }
|
|
7101
|
+
);
|
|
6005
7102
|
} catch {
|
|
6006
|
-
pretty = renderVitestFromJestJSON(
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
7103
|
+
pretty = renderVitestFromJestJSON(
|
|
7104
|
+
bridge,
|
|
7105
|
+
makeCtx(
|
|
7106
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7107
|
+
/\bFAIL\b/.test(stripAnsiSimple(output))
|
|
7108
|
+
),
|
|
7109
|
+
{ onlyFailures }
|
|
7110
|
+
);
|
|
6011
7111
|
}
|
|
6012
7112
|
if (debug) {
|
|
6013
7113
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
@@ -6021,18 +7121,31 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6021
7121
|
console.info(String(jsonErr));
|
|
6022
7122
|
console.info(`fallback: raw output lines=${output.split(/\r?\n/).length}`);
|
|
6023
7123
|
}
|
|
6024
|
-
|
|
7124
|
+
pretty = formatJestOutputVitest(output, {
|
|
6025
7125
|
cwd: repoRootForDiscovery,
|
|
6026
7126
|
...editorCmd !== void 0 ? { editorCmd } : {},
|
|
6027
7127
|
onlyFailures
|
|
6028
|
-
};
|
|
6029
|
-
pretty = formatJestOutputVitest(output, renderOpts);
|
|
7128
|
+
});
|
|
6030
7129
|
if (debug) {
|
|
6031
7130
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
6032
7131
|
console.info(`pretty preview (text):
|
|
6033
7132
|
${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
6034
7133
|
}
|
|
6035
7134
|
}
|
|
7135
|
+
try {
|
|
7136
|
+
const looksSparse = /\n\s*Error:\s*\n/.test(pretty) && !/(Message:|Thrown:|Events:|Console errors:)/.test(pretty);
|
|
7137
|
+
if (looksSparse) {
|
|
7138
|
+
const rawAlso = formatJestOutputVitest(output, {
|
|
7139
|
+
cwd: repoRootForDiscovery,
|
|
7140
|
+
...editorCmd !== void 0 ? { editorCmd } : {},
|
|
7141
|
+
onlyFailures
|
|
7142
|
+
});
|
|
7143
|
+
const merged = `${stripFooter(pretty)}
|
|
7144
|
+
${stripFooter(rawAlso)}`.trimEnd();
|
|
7145
|
+
pretty = merged;
|
|
7146
|
+
}
|
|
7147
|
+
} catch {
|
|
7148
|
+
}
|
|
6036
7149
|
pretty = stripFooter(pretty);
|
|
6037
7150
|
if (pretty.trim().length > 0) {
|
|
6038
7151
|
process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
|
|
@@ -6071,10 +7184,10 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6071
7184
|
try {
|
|
6072
7185
|
const prodSeeds = (() => {
|
|
6073
7186
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
6074
|
-
(absPath) =>
|
|
7187
|
+
(absPath) => path11.resolve(absPath).replace(/\\/g, "/")
|
|
6075
7188
|
);
|
|
6076
7189
|
const selAbs = selectionPathsAugmented.map(
|
|
6077
|
-
(pathToken) =>
|
|
7190
|
+
(pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
|
|
6078
7191
|
);
|
|
6079
7192
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
6080
7193
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -6088,11 +7201,18 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
6088
7201
|
unified.testResults = ordered;
|
|
6089
7202
|
} catch {
|
|
6090
7203
|
}
|
|
6091
|
-
const
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
7204
|
+
const showStacks = Boolean(unified.aggregated?.numFailedTests > 0);
|
|
7205
|
+
let text = renderVitestFromJestJSON(
|
|
7206
|
+
unified,
|
|
7207
|
+
makeCtx(
|
|
7208
|
+
{ cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
|
|
7209
|
+
showStacks
|
|
7210
|
+
),
|
|
7211
|
+
{ onlyFailures }
|
|
7212
|
+
);
|
|
7213
|
+
if (onlyFailures) {
|
|
7214
|
+
text = text.split(/\r?\n/).filter((line) => !/^\s*PASS\b/.test(stripAnsiSimple(line))).join("\n");
|
|
7215
|
+
}
|
|
6096
7216
|
if (text.trim().length > 0) {
|
|
6097
7217
|
process.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
6098
7218
|
`);
|