headlamp 0.1.12 → 0.1.14
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 +689 -627
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +692 -634
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
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((resolve11, 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
|
+
resolve11();
|
|
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((resolve11, reject) => {
|
|
175
175
|
child.on("error", reject);
|
|
176
176
|
child.on(
|
|
177
177
|
"close",
|
|
178
|
-
(code) => Number(code) === 0 ?
|
|
178
|
+
(code) => Number(code) === 0 ? resolve11(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((resolve11, 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) => resolve11(Number(code)));
|
|
208
208
|
});
|
|
209
|
-
runWithCapture = async (cmd, args, opts) => new Promise((
|
|
209
|
+
runWithCapture = async (cmd, args, opts) => new Promise((resolve11, 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) => resolve11({ code: Number(code), output: buf }));
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
});
|
|
@@ -1980,16 +1980,16 @@ var require_lib = __commonJS({
|
|
|
1980
1980
|
"node_modules/json5/lib/index.js"(exports2, module2) {
|
|
1981
1981
|
var parse = require_parse();
|
|
1982
1982
|
var stringify = require_stringify();
|
|
1983
|
-
var
|
|
1983
|
+
var JSON54 = {
|
|
1984
1984
|
parse,
|
|
1985
1985
|
stringify
|
|
1986
1986
|
};
|
|
1987
|
-
module2.exports =
|
|
1987
|
+
module2.exports = JSON54;
|
|
1988
1988
|
}
|
|
1989
1989
|
});
|
|
1990
1990
|
|
|
1991
1991
|
// src/lib/program.ts
|
|
1992
|
-
var
|
|
1992
|
+
var path12 = __toESM(require("node:path"), 1);
|
|
1993
1993
|
var os3 = __toESM(require("node:os"), 1);
|
|
1994
1994
|
var fsSync3 = __toESM(require("node:fs"), 1);
|
|
1995
1995
|
var fs7 = __toESM(require("node:fs/promises"), 1);
|
|
@@ -3047,11 +3047,11 @@ var tintPct = (pct) => {
|
|
|
3047
3047
|
var bar = (pct, width = DEFAULT_BAR_WIDTH) => {
|
|
3048
3048
|
const filled = Math.round(pct / PERCENT_MAX * width);
|
|
3049
3049
|
const solid = supportsUnicode() ? "\u2588" : "#";
|
|
3050
|
-
const
|
|
3050
|
+
const empty2 = supportsUnicode() ? "\u2591" : "-";
|
|
3051
3051
|
const good = tintPct(pct);
|
|
3052
3052
|
const MIN_REMAINING = 0;
|
|
3053
3053
|
return `${good(solid.repeat(filled))}${ansi.gray(
|
|
3054
|
-
|
|
3054
|
+
empty2.repeat(Math.max(MIN_REMAINING, width - filled))
|
|
3055
3055
|
)}`;
|
|
3056
3056
|
};
|
|
3057
3057
|
|
|
@@ -4912,15 +4912,23 @@ var buildMessageSection = (messageLines, details, _ctx, opts) => {
|
|
|
4912
4912
|
const fallbackLines = [];
|
|
4913
4913
|
if (hasOnlyBareError) {
|
|
4914
4914
|
const startFrom = hintIdx >= 0 ? hintIdx + 1 : 0;
|
|
4915
|
+
let started = false;
|
|
4915
4916
|
for (let i = startFrom; i < lines.length; i += 1) {
|
|
4916
4917
|
const candidate = lines[i];
|
|
4917
|
-
if (
|
|
4918
|
+
if (isStackLine(candidate)) {
|
|
4918
4919
|
break;
|
|
4919
4920
|
}
|
|
4920
|
-
if (
|
|
4921
|
+
if (!candidate.trim()) {
|
|
4922
|
+
if (!started) {
|
|
4923
|
+
continue;
|
|
4924
|
+
}
|
|
4921
4925
|
break;
|
|
4922
4926
|
}
|
|
4927
|
+
started = true;
|
|
4923
4928
|
fallbackLines.push(candidate);
|
|
4929
|
+
if (fallbackLines.length >= 6) {
|
|
4930
|
+
break;
|
|
4931
|
+
}
|
|
4924
4932
|
}
|
|
4925
4933
|
if (fallbackLines.length === 0 && details && details.messages && details.messages.length) {
|
|
4926
4934
|
fallbackLines.push(
|
|
@@ -4988,7 +4996,7 @@ var linesFromDetails = (details) => {
|
|
|
4988
4996
|
if (typeof obj.received === "string") {
|
|
4989
4997
|
pushMaybe(obj.received, messages);
|
|
4990
4998
|
}
|
|
4991
|
-
const arrays = ["errors", "causes", "aggregatedErrors"];
|
|
4999
|
+
const arrays = ["errors", "details", "issues", "inner", "causes", "aggregatedErrors"];
|
|
4992
5000
|
for (const key of arrays) {
|
|
4993
5001
|
const arr = obj[key];
|
|
4994
5002
|
if (Array.isArray(arr)) {
|
|
@@ -4997,7 +5005,7 @@ var linesFromDetails = (details) => {
|
|
|
4997
5005
|
}
|
|
4998
5006
|
}
|
|
4999
5007
|
}
|
|
5000
|
-
const nestedCandidates = ["error", "cause", "matcherResult"];
|
|
5008
|
+
const nestedCandidates = ["error", "cause", "matcherResult", "context", "data"];
|
|
5001
5009
|
for (const key of nestedCandidates) {
|
|
5002
5010
|
if (obj[key] && typeof obj[key] === "object") {
|
|
5003
5011
|
visitDeep(obj[key], depth + 1);
|
|
@@ -5026,9 +5034,7 @@ var linesFromDetails = (details) => {
|
|
|
5026
5034
|
pushMaybe(matcher.expected, messages);
|
|
5027
5035
|
pushMaybe(matcher.received, messages);
|
|
5028
5036
|
}
|
|
5029
|
-
|
|
5030
|
-
visitDeep(detail, 0);
|
|
5031
|
-
}
|
|
5037
|
+
visitDeep(detail, 0);
|
|
5032
5038
|
}
|
|
5033
5039
|
}
|
|
5034
5040
|
return { stacks, messages };
|
|
@@ -5092,24 +5098,31 @@ var buildConsoleSection = (maybeConsole) => {
|
|
|
5092
5098
|
var buildFallbackMessageBlock = (messageLines, details) => {
|
|
5093
5099
|
const normalize2 = (arr) => arr.map((lineText) => stripAnsiSimple(lineText)).filter((line) => line.trim().length > 0);
|
|
5094
5100
|
const normalized = normalize2(messageLines);
|
|
5095
|
-
const informative = normalized.filter(
|
|
5101
|
+
const informative = normalized.filter(
|
|
5102
|
+
(line) => !/^\s*(?:Error|AssertionError):?\s*$/i.test(line)
|
|
5103
|
+
);
|
|
5096
5104
|
if (informative.length > 0) {
|
|
5097
5105
|
return [];
|
|
5098
5106
|
}
|
|
5099
5107
|
const errorIdx = normalized.findIndex(
|
|
5100
|
-
(line) => /(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError|Error)
|
|
5108
|
+
(line) => /(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError|Error):?/i.test(line)
|
|
5101
5109
|
);
|
|
5102
5110
|
const collected = [];
|
|
5103
5111
|
if (errorIdx >= 0) {
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5112
|
+
let started = false;
|
|
5113
|
+
for (let i = errorIdx + 1; i < messageLines.length && collected.length < 8; i += 1) {
|
|
5114
|
+
const raw = stripAnsiSimple(messageLines[i]);
|
|
5115
|
+
if (isStackLine(raw)) {
|
|
5107
5116
|
break;
|
|
5108
5117
|
}
|
|
5109
|
-
if (
|
|
5118
|
+
if (!raw.trim()) {
|
|
5119
|
+
if (!started) {
|
|
5120
|
+
continue;
|
|
5121
|
+
}
|
|
5110
5122
|
break;
|
|
5111
5123
|
}
|
|
5112
|
-
|
|
5124
|
+
started = true;
|
|
5125
|
+
collected.push(raw);
|
|
5113
5126
|
}
|
|
5114
5127
|
}
|
|
5115
5128
|
const fromDetails = collected.length > 0 ? [] : normalize2(details.messages).slice(0, 6);
|
|
@@ -5357,39 +5370,13 @@ var makeCtx = (opts, showStacks = false) => {
|
|
|
5357
5370
|
return { cwd, width, showStacks, projectHint, editorCmd: opts?.editorCmd, readSource: readSource2 };
|
|
5358
5371
|
};
|
|
5359
5372
|
|
|
5360
|
-
// src/lib/formatter/bridge.ts
|
|
5373
|
+
// src/lib/formatter/bridge/tryBridgeFallback.ts
|
|
5361
5374
|
var fs6 = __toESM(require("node:fs"), 1);
|
|
5375
|
+
var path11 = __toESM(require("node:path"), 1);
|
|
5376
|
+
var import_json53 = __toESM(require_lib(), 1);
|
|
5377
|
+
|
|
5378
|
+
// src/lib/formatter/bridge/logic.ts
|
|
5362
5379
|
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;
|
|
5383
|
-
}
|
|
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
5380
|
var extractBridgePath2 = (raw, cwd) => {
|
|
5394
5381
|
const matches = Array.from(
|
|
5395
5382
|
raw.matchAll(/Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g)
|
|
@@ -5397,15 +5384,14 @@ var extractBridgePath2 = (raw, cwd) => {
|
|
|
5397
5384
|
if (!matches.length) {
|
|
5398
5385
|
return null;
|
|
5399
5386
|
}
|
|
5400
|
-
const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["
|
|
5387
|
+
const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^['"`]|['"`]$/g, "");
|
|
5401
5388
|
return path10.isAbsolute(jsonPath) ? jsonPath : path10.resolve(cwd, jsonPath).replace(/\\/g, "/");
|
|
5402
5389
|
};
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
};
|
|
5390
|
+
|
|
5391
|
+
// src/lib/formatter/bridge/utils.ts
|
|
5392
|
+
var import_json52 = __toESM(require_lib(), 1);
|
|
5393
|
+
|
|
5394
|
+
// src/lib/formatter/bridge/http.ts
|
|
5409
5395
|
var envNumber = (name, fallback) => {
|
|
5410
5396
|
const parsed = Number(process.env[name]);
|
|
5411
5397
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
@@ -5415,15 +5401,11 @@ var HEADLAMP_HTTP_STRICT_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_STRICT_WINDO
|
|
|
5415
5401
|
var HEADLAMP_HTTP_MIN_SCORE = () => envNumber("HEADLAMP_HTTP_MIN_SCORE", 1200);
|
|
5416
5402
|
var HEADLAMP_HTTP_DIFF_LIMIT = () => envNumber("HEADLAMP_HTTP_DIFF_LIMIT", 6);
|
|
5417
5403
|
var HEADLAMP_HTTP_SHOW_MISS = () => process.env.HEADLAMP_HTTP_MISS === "1";
|
|
5418
|
-
var
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
}
|
|
5422
|
-
return
|
|
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
|
-
});
|
|
5404
|
+
var asHttpList = (candidateValue) => Array.isArray(candidateValue) ? candidateValue : [];
|
|
5405
|
+
var summarizeUrl = (method, url, route) => {
|
|
5406
|
+
const base = route || url || "";
|
|
5407
|
+
const qs = url && url.includes("?") ? ` ? ${url.split("?")[1]}` : "";
|
|
5408
|
+
return [method || "", base, qs].filter(Boolean).join(" ").trim();
|
|
5427
5409
|
};
|
|
5428
5410
|
var parseMethodPathFromTitle = (title) => {
|
|
5429
5411
|
if (!title) {
|
|
@@ -5432,19 +5414,17 @@ var parseMethodPathFromTitle = (title) => {
|
|
|
5432
5414
|
const matchResult = title.match(/\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+([^\s)]+)/i);
|
|
5433
5415
|
return matchResult ? { method: matchResult[1]?.toUpperCase(), path: matchResult[2] } : {};
|
|
5434
5416
|
};
|
|
5435
|
-
var
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
return false;
|
|
5439
|
-
}
|
|
5440
|
-
if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
|
|
5441
|
-
return true;
|
|
5417
|
+
var eventsNear = (http, ts, testPath, windowMs = HEADLAMP_HTTP_WINDOW_MS()) => {
|
|
5418
|
+
if (typeof ts !== "number" || !Number.isFinite(ts)) {
|
|
5419
|
+
return [];
|
|
5442
5420
|
}
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5421
|
+
return http.filter((event) => {
|
|
5422
|
+
const timeOk = typeof event.timestampMs === "number" && Math.abs(event.timestampMs - ts) <= windowMs;
|
|
5423
|
+
const pathOk = !testPath || event.testPath === testPath;
|
|
5424
|
+
return timeOk && pathOk;
|
|
5425
|
+
});
|
|
5446
5426
|
};
|
|
5447
|
-
var
|
|
5427
|
+
var isHttpStatusNumber = (statusNumber) => typeof statusNumber === "number" && statusNumber >= 100 && statusNumber <= 599;
|
|
5448
5428
|
var inferHttpNumbersFromText = (lines) => {
|
|
5449
5429
|
const text = lines.join("\n");
|
|
5450
5430
|
const match = text.match(/Expected:\s*(\d{3})[\s\S]*?Received:\s*(\d{3})/i);
|
|
@@ -5457,10 +5437,19 @@ var titleSuggestsHttp = (title) => {
|
|
|
5457
5437
|
const { method, path: parsedPath } = parseMethodPathFromTitle(title);
|
|
5458
5438
|
return Boolean(method || parsedPath && parsedPath.startsWith("/"));
|
|
5459
5439
|
};
|
|
5460
|
-
var
|
|
5461
|
-
|
|
5462
|
-
|
|
5440
|
+
var hasStatusSemantics = (assertionLike) => {
|
|
5441
|
+
if (!assertionLike) {
|
|
5442
|
+
return false;
|
|
5443
|
+
}
|
|
5444
|
+
if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
|
|
5445
|
+
return true;
|
|
5446
|
+
}
|
|
5447
|
+
const combinedRaw = `${assertionLike.matcher ?? ""} ${assertionLike.message ?? ""}`;
|
|
5448
|
+
const combinedMessage = combinedRaw.toLowerCase();
|
|
5449
|
+
return /\bstatus(code)?\b|\btohaves(tatus|tatuscode)\b/.test(combinedMessage);
|
|
5463
5450
|
};
|
|
5451
|
+
var fileSuggestsHttp = (relPath2) => /(?:^|\/)(routes?|api|controllers?|e2e|integration)(?:\/|\.test\.)/i.test(relPath2);
|
|
5452
|
+
var isHttpRelevant = (ctx) => ctx.hasTransportSignal || ctx.httpCountInSameTest > 0 || titleSuggestsHttp(ctx.title) || hasStatusSemantics(ctx.assertion) || fileSuggestsHttp(ctx.relPath);
|
|
5464
5453
|
var routeSimilarityScore = (hint, evt) => {
|
|
5465
5454
|
if (!hint.path && !hint.method) {
|
|
5466
5455
|
return 0;
|
|
@@ -5481,6 +5470,12 @@ var routeSimilarityScore = (hint, evt) => {
|
|
|
5481
5470
|
}
|
|
5482
5471
|
return methodOk * 10;
|
|
5483
5472
|
};
|
|
5473
|
+
var isTransportError = (msg) => {
|
|
5474
|
+
const lowercaseMessage = (msg ?? "").toLowerCase();
|
|
5475
|
+
return /\bsocket hang up\b|\beconnreset\b|\betimedout\b|\beconnrefused\b|\bwrite epipe\b/.test(
|
|
5476
|
+
lowercaseMessage
|
|
5477
|
+
);
|
|
5478
|
+
};
|
|
5484
5479
|
var scoreHttpForAssertion = (assertion, titleHint) => (candidateEvent) => {
|
|
5485
5480
|
const tsA = assertion.timestampMs;
|
|
5486
5481
|
const tsH = candidateEvent.timestampMs;
|
|
@@ -5501,14 +5496,20 @@ var pickRelevantHttp = (assertion, http, ctx) => {
|
|
|
5501
5496
|
const windowMs = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
|
|
5502
5497
|
let pool = strictPool;
|
|
5503
5498
|
if (!pool.length) {
|
|
5504
|
-
pool = http.filter(
|
|
5505
|
-
|
|
5506
|
-
|
|
5499
|
+
pool = http.filter((event) => {
|
|
5500
|
+
const samePath = event.testPath === ctx.testPath;
|
|
5501
|
+
const tsA = assertion.timestampMs;
|
|
5502
|
+
const tsH = event.timestampMs;
|
|
5503
|
+
const inWindow = typeof tsA === "number" && typeof tsH === "number" && Math.abs(tsH - tsA) <= windowMs;
|
|
5504
|
+
return samePath && inWindow;
|
|
5505
|
+
});
|
|
5507
5506
|
}
|
|
5508
5507
|
if (!pool.length) {
|
|
5509
|
-
pool = http.filter(
|
|
5510
|
-
|
|
5511
|
-
|
|
5508
|
+
pool = http.filter((event) => {
|
|
5509
|
+
const tsA = assertion.timestampMs;
|
|
5510
|
+
const tsH = event.timestampMs;
|
|
5511
|
+
return typeof tsA === "number" && typeof tsH === "number" && Math.abs(tsH - tsA) <= windowMs;
|
|
5512
|
+
});
|
|
5512
5513
|
}
|
|
5513
5514
|
if (!pool.length) {
|
|
5514
5515
|
return void 0;
|
|
@@ -5518,9 +5519,390 @@ var pickRelevantHttp = (assertion, http, ctx) => {
|
|
|
5518
5519
|
const threshold = isTransportError(assertion.message) ? Math.max(HEADLAMP_HTTP_MIN_SCORE(), 1400) : HEADLAMP_HTTP_MIN_SCORE();
|
|
5519
5520
|
return best && best.s >= threshold ? best.h : void 0;
|
|
5520
5521
|
};
|
|
5521
|
-
|
|
5522
|
+
|
|
5523
|
+
// src/lib/formatter/bridge/utils.ts
|
|
5524
|
+
var colorTokens2 = {
|
|
5525
|
+
pass: Colors.Success,
|
|
5526
|
+
fail: Colors.Failure,
|
|
5527
|
+
skip: Colors.Skip,
|
|
5528
|
+
todo: Colors.Todo,
|
|
5529
|
+
passPill: (text) => BackgroundColors.Success(ansi.white(` ${text} `)),
|
|
5530
|
+
failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `))
|
|
5531
|
+
};
|
|
5532
|
+
var joinLines = (chunks) => chunks.join("\n");
|
|
5533
|
+
var empty = [];
|
|
5534
|
+
var concat = (...xs) => xs.flat();
|
|
5535
|
+
var by = (keySelector) => (left, right) => keySelector(left) - keySelector(right);
|
|
5536
|
+
var isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5537
|
+
var stripBridgeEventsFromConsole = (maybeConsole) => {
|
|
5538
|
+
if (!Array.isArray(maybeConsole)) {
|
|
5539
|
+
return maybeConsole;
|
|
5540
|
+
}
|
|
5541
|
+
return maybeConsole.filter((entry) => {
|
|
5542
|
+
try {
|
|
5543
|
+
const raw = Array.isArray(entry.message) ? entry.message.map(String).join(" ") : String(entry.message ?? "");
|
|
5544
|
+
return !raw.includes("[JEST-BRIDGE-EVENT]");
|
|
5545
|
+
} catch {
|
|
5546
|
+
return true;
|
|
5547
|
+
}
|
|
5548
|
+
});
|
|
5549
|
+
};
|
|
5550
|
+
var parseBridgeConsole = (consoleEntries) => {
|
|
5551
|
+
const http = [];
|
|
5552
|
+
const assertions = [];
|
|
5553
|
+
if (!Array.isArray(consoleEntries)) {
|
|
5554
|
+
return { http, assertions };
|
|
5555
|
+
}
|
|
5556
|
+
for (const entry of consoleEntries) {
|
|
5557
|
+
const rec = entry;
|
|
5558
|
+
const rawMsgVal = rec && typeof rec.message !== "undefined" ? rec.message : "";
|
|
5559
|
+
const raw = Array.isArray(rawMsgVal) ? rawMsgVal.map(String).join(" ") : String(rawMsgVal ?? "");
|
|
5560
|
+
if (!raw.includes("[JEST-BRIDGE-EVENT]")) {
|
|
5561
|
+
continue;
|
|
5562
|
+
}
|
|
5563
|
+
const jsonText = raw.split("[JEST-BRIDGE-EVENT]").pop()?.trim() ?? "";
|
|
5564
|
+
try {
|
|
5565
|
+
const evt = import_json52.default.parse(jsonText);
|
|
5566
|
+
const type = evt?.type;
|
|
5567
|
+
if (type === "httpResponse") {
|
|
5568
|
+
const timestampMs = Number(evt.timestampMs ?? Date.now());
|
|
5569
|
+
http.push({
|
|
5570
|
+
kind: "response",
|
|
5571
|
+
timestampMs,
|
|
5572
|
+
method: evt.method,
|
|
5573
|
+
url: evt.url,
|
|
5574
|
+
route: evt.route,
|
|
5575
|
+
statusCode: evt.statusCode,
|
|
5576
|
+
durationMs: evt.durationMs,
|
|
5577
|
+
contentType: evt.contentType,
|
|
5578
|
+
requestId: evt.requestId,
|
|
5579
|
+
json: evt.json,
|
|
5580
|
+
bodyPreview: evt.bodyPreview,
|
|
5581
|
+
testPath: evt.testPath,
|
|
5582
|
+
currentTestName: evt.currentTestName
|
|
5583
|
+
});
|
|
5584
|
+
} else if (type === "httpAbort") {
|
|
5585
|
+
http.push({
|
|
5586
|
+
kind: "abort",
|
|
5587
|
+
timestampMs: Number(evt.timestampMs ?? Date.now()),
|
|
5588
|
+
method: evt.method,
|
|
5589
|
+
url: evt.url,
|
|
5590
|
+
route: evt.route,
|
|
5591
|
+
durationMs: evt.durationMs,
|
|
5592
|
+
testPath: evt.testPath,
|
|
5593
|
+
currentTestName: evt.currentTestName
|
|
5594
|
+
});
|
|
5595
|
+
} else if (type === "httpResponseBatch") {
|
|
5596
|
+
const list = asHttpList(evt?.events);
|
|
5597
|
+
for (const item of list) {
|
|
5598
|
+
const anyItem = item;
|
|
5599
|
+
http.push({
|
|
5600
|
+
timestampMs: Number(anyItem.timestampMs ?? Date.now()),
|
|
5601
|
+
method: anyItem.method,
|
|
5602
|
+
url: anyItem.url,
|
|
5603
|
+
route: anyItem.route,
|
|
5604
|
+
statusCode: anyItem.statusCode,
|
|
5605
|
+
durationMs: anyItem.durationMs,
|
|
5606
|
+
contentType: anyItem.contentType,
|
|
5607
|
+
requestId: anyItem.requestId,
|
|
5608
|
+
json: anyItem.json,
|
|
5609
|
+
bodyPreview: anyItem.bodyPreview,
|
|
5610
|
+
testPath: evt.testPath,
|
|
5611
|
+
currentTestName: evt.currentTestName
|
|
5612
|
+
});
|
|
5613
|
+
}
|
|
5614
|
+
} else if (type === "assertionFailure") {
|
|
5615
|
+
assertions.push({
|
|
5616
|
+
timestampMs: typeof evt.timestampMs === "number" ? evt.timestampMs : void 0,
|
|
5617
|
+
matcher: evt.matcher,
|
|
5618
|
+
expectedNumber: typeof evt.expectedNumber === "number" ? evt.expectedNumber : void 0,
|
|
5619
|
+
receivedNumber: typeof evt.receivedNumber === "number" ? evt.receivedNumber : void 0,
|
|
5620
|
+
message: typeof evt.message === "string" ? evt.message : void 0,
|
|
5621
|
+
stack: typeof evt.stack === "string" ? evt.stack : void 0,
|
|
5622
|
+
testPath: evt.testPath,
|
|
5623
|
+
currentTestName: evt.currentTestName,
|
|
5624
|
+
expectedPreview: typeof evt.expectedPreview === "string" ? evt.expectedPreview : void 0,
|
|
5625
|
+
actualPreview: typeof evt.actualPreview === "string" ? evt.actualPreview : void 0
|
|
5626
|
+
});
|
|
5627
|
+
}
|
|
5628
|
+
} catch {
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
return { http, assertions };
|
|
5632
|
+
};
|
|
5633
|
+
var renderRunHeader = ({ ctx, onlyFailures }) => onlyFailures ? empty : [`${BackgroundColors.Run(ansi.white(" RUN "))} ${ansi.dim(ctx.cwd)}`, ""];
|
|
5634
|
+
var renderPerFileOverviewBlock = (rel, testResults, onlyFailures) => onlyFailures ? empty : buildPerFileOverview(rel, testResults);
|
|
5635
|
+
var renderFileBadge = (rel, failedCount, onlyFailures) => onlyFailures && failedCount === 0 ? empty : [buildFileBadgeLine(rel, failedCount)];
|
|
5636
|
+
var condenseBlankRuns = (lines) => {
|
|
5637
|
+
const out = [];
|
|
5638
|
+
let lastBlank = false;
|
|
5639
|
+
for (const ln of lines) {
|
|
5640
|
+
const isBlank = !stripAnsiSimple(String(ln ?? "")).trim();
|
|
5641
|
+
if (isBlank) {
|
|
5642
|
+
if (!lastBlank) {
|
|
5643
|
+
out.push("");
|
|
5644
|
+
}
|
|
5645
|
+
lastBlank = true;
|
|
5646
|
+
} else {
|
|
5647
|
+
out.push(String(ln));
|
|
5648
|
+
lastBlank = false;
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
return out;
|
|
5652
|
+
};
|
|
5653
|
+
var mergeMsgLines = (primaryRaw, detailMsgs) => {
|
|
5654
|
+
const primary = primaryRaw.trim() ? primaryRaw.split(/\r?\n/) : [];
|
|
5655
|
+
const key = (line) => stripAnsiSimple(line).trim();
|
|
5656
|
+
const seen = new Set(primary.map(key));
|
|
5657
|
+
const merged = [...primary];
|
|
5658
|
+
for (const msg of detailMsgs) {
|
|
5659
|
+
const msgKey = key(String(msg ?? ""));
|
|
5660
|
+
if (!msgKey) {
|
|
5661
|
+
continue;
|
|
5662
|
+
}
|
|
5663
|
+
if (!seen.has(msgKey)) {
|
|
5664
|
+
merged.push(msg);
|
|
5665
|
+
seen.add(msgKey);
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
return condenseBlankRuns(merged);
|
|
5669
|
+
};
|
|
5670
|
+
var renderFileLevelFailure = (file, ctx) => {
|
|
5671
|
+
if (!(file.failureMessage || file.testExecError)) {
|
|
5672
|
+
return empty;
|
|
5673
|
+
}
|
|
5674
|
+
const base = linesFromDetails(file.failureDetails);
|
|
5675
|
+
const exec = linesFromDetails(
|
|
5676
|
+
Array.isArray(file.testExecError) ? file.testExecError : [file.testExecError]
|
|
5677
|
+
);
|
|
5678
|
+
const combinedDetails = {
|
|
5679
|
+
stacks: [...base.stacks, ...exec.stacks],
|
|
5680
|
+
messages: [...base.messages, ...exec.messages]
|
|
5681
|
+
};
|
|
5682
|
+
const msgLines = mergeMsgLines(file.failureMessage || "", combinedDetails.messages);
|
|
5683
|
+
const mergedForStack = collapseStacks([...msgLines, ...combinedDetails.stacks]);
|
|
5684
|
+
const synthLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
5685
|
+
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)}`) : [];
|
|
5686
|
+
const code = buildCodeFrameSection(msgLines, ctx, synthLoc);
|
|
5687
|
+
const pretty = buildPrettyDiffSection(file.failureDetails, msgLines);
|
|
5688
|
+
const message = buildMessageSection(msgLines, combinedDetails, ctx, {
|
|
5689
|
+
suppressDiff: pretty.length > 0,
|
|
5690
|
+
stackPreview
|
|
5691
|
+
});
|
|
5692
|
+
const consoleBlock = buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null));
|
|
5693
|
+
const stackTail = ctx.showStacks && stackPreview.length === 0 ? (() => {
|
|
5694
|
+
const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
|
|
5695
|
+
return tail.length ? [ansi.dim(" Stack:"), ...tail, ""] : empty;
|
|
5696
|
+
})() : empty;
|
|
5697
|
+
return concat(code, pretty, message, consoleBlock, stackTail);
|
|
5698
|
+
};
|
|
5699
|
+
var renderHttpCard = (args) => {
|
|
5700
|
+
const { file, relPath: rel, assertion, assertionEvents, httpSorted } = args;
|
|
5701
|
+
const nameMatches = (left, right) => !!left && !!right && (left === right || left.includes(right) || right.includes(left));
|
|
5702
|
+
const inSameCtx = (testPath, testName) => httpSorted.filter(
|
|
5703
|
+
(event) => event.testPath === testPath && nameMatches(event.currentTestName, testName)
|
|
5704
|
+
);
|
|
5705
|
+
const perTestSlice = inSameCtx(file.testFilePath, assertion.fullName);
|
|
5706
|
+
const corresponding = assertionEvents.find(
|
|
5707
|
+
(event) => event.testPath === file.testFilePath && nameMatches(event.currentTestName, assertion.fullName)
|
|
5708
|
+
) ?? assertion;
|
|
5709
|
+
const nearByTime = eventsNear(
|
|
5710
|
+
httpSorted,
|
|
5711
|
+
corresponding?.timestampMs,
|
|
5712
|
+
file.testFilePath
|
|
5713
|
+
);
|
|
5714
|
+
const hasAbort = perTestSlice.some((event) => event.kind === "abort");
|
|
5715
|
+
const hasTransport = isTransportError(corresponding?.message) || hasAbort;
|
|
5716
|
+
const httpLikely = isHttpRelevant({
|
|
5717
|
+
assertion: corresponding,
|
|
5718
|
+
title: assertion.fullName,
|
|
5719
|
+
relPath: rel,
|
|
5720
|
+
httpCountInSameTest: perTestSlice.length || nearByTime.length,
|
|
5721
|
+
hasTransportSignal: hasTransport
|
|
5722
|
+
});
|
|
5723
|
+
if (!httpLikely) {
|
|
5724
|
+
return empty;
|
|
5725
|
+
}
|
|
5726
|
+
const HEADLAMP_HTTP_DIFF_LIMIT_LOCAL = () => HEADLAMP_HTTP_DIFF_LIMIT();
|
|
5727
|
+
const safeParseJSON = (text) => {
|
|
5728
|
+
try {
|
|
5729
|
+
return text ? import_json52.default.parse(text) : void 0;
|
|
5730
|
+
} catch {
|
|
5731
|
+
return void 0;
|
|
5732
|
+
}
|
|
5733
|
+
};
|
|
5734
|
+
const expPreview = corresponding?.expectedPreview;
|
|
5735
|
+
const actPreview = corresponding?.actualPreview;
|
|
5736
|
+
const parsedExpected = safeParseJSON(expPreview);
|
|
5737
|
+
const parsedActual = safeParseJSON(actPreview);
|
|
5738
|
+
let corr = corresponding;
|
|
5739
|
+
if (!isHttpStatusNumber(corr.expectedNumber) && !isHttpStatusNumber(corr.receivedNumber)) {
|
|
5740
|
+
const inferred = inferHttpNumbersFromText(
|
|
5741
|
+
(assertion.failureMessages?.join("\n") || file.failureMessage || "").split("\n")
|
|
5742
|
+
);
|
|
5743
|
+
if (isHttpStatusNumber(inferred.expectedNumber) || isHttpStatusNumber(inferred.receivedNumber)) {
|
|
5744
|
+
corr = { ...corr, ...inferred };
|
|
5745
|
+
}
|
|
5746
|
+
}
|
|
5747
|
+
const relevant = pickRelevantHttp(
|
|
5748
|
+
{
|
|
5749
|
+
timestampMs: corr?.timestampMs,
|
|
5750
|
+
expectedNumber: corr?.expectedNumber,
|
|
5751
|
+
receivedNumber: corr?.receivedNumber,
|
|
5752
|
+
matcher: corr?.matcher,
|
|
5753
|
+
message: corr?.message,
|
|
5754
|
+
stack: corr?.stack,
|
|
5755
|
+
testPath: file.testFilePath,
|
|
5756
|
+
currentTestName: assertion.title
|
|
5757
|
+
},
|
|
5758
|
+
httpSorted,
|
|
5759
|
+
{
|
|
5760
|
+
testPath: file.testFilePath,
|
|
5761
|
+
currentTestName: assertion.fullName,
|
|
5762
|
+
title: assertion.fullName
|
|
5763
|
+
}
|
|
5764
|
+
);
|
|
5765
|
+
if (hasTransport) {
|
|
5766
|
+
const tsBase = corr?.timestampMs ?? 0;
|
|
5767
|
+
const [nearestAbort] = perTestSlice.filter((event) => event.kind === "abort").sort(
|
|
5768
|
+
(left, right) => Math.abs(tsBase - (left.timestampMs ?? 0)) - Math.abs(tsBase - (right.timestampMs ?? 0))
|
|
5769
|
+
);
|
|
5770
|
+
if (nearestAbort) {
|
|
5771
|
+
const ms = nearestAbort.durationMs;
|
|
5772
|
+
return [
|
|
5773
|
+
" HTTP:",
|
|
5774
|
+
`
|
|
5775
|
+
${summarizeUrl(nearestAbort.method, nearestAbort.url, nearestAbort.route)} ${ansi.dim("->")} ${ansi.yellow("connection aborted")}`,
|
|
5776
|
+
ms != null ? ` ${ansi.dim(`(${ms}ms)`)} ` : "",
|
|
5777
|
+
"\n"
|
|
5778
|
+
];
|
|
5779
|
+
}
|
|
5780
|
+
return HEADLAMP_HTTP_SHOW_MISS() ? [
|
|
5781
|
+
" HTTP:",
|
|
5782
|
+
`
|
|
5783
|
+
${ansi.dim("Transport error; no matching HTTP exchange in window.")}`,
|
|
5784
|
+
"\n"
|
|
5785
|
+
] : empty;
|
|
5786
|
+
}
|
|
5787
|
+
if (!relevant) {
|
|
5788
|
+
return HEADLAMP_HTTP_SHOW_MISS() ? [
|
|
5789
|
+
" HTTP:",
|
|
5790
|
+
`
|
|
5791
|
+
${ansi.dim("No relevant HTTP exchange found. (HEADLAMP_HTTP_MISS=0 to hide)")}`,
|
|
5792
|
+
"\n"
|
|
5793
|
+
] : empty;
|
|
5794
|
+
}
|
|
5795
|
+
const jsonDiff = (expected, actual, limit = HEADLAMP_HTTP_DIFF_LIMIT_LOCAL()) => {
|
|
5796
|
+
const out = [];
|
|
5797
|
+
const queue = [
|
|
5798
|
+
{ pathSoFar: "$", expectedValue: expected, actualValue: actual }
|
|
5799
|
+
];
|
|
5800
|
+
while (queue.length && out.length < limit) {
|
|
5801
|
+
const { pathSoFar, expectedValue, actualValue } = queue.shift();
|
|
5802
|
+
const expectedIsObject = expectedValue && typeof expectedValue === "object";
|
|
5803
|
+
const actualIsObject = actualValue && typeof actualValue === "object";
|
|
5804
|
+
if (!expectedIsObject && !actualIsObject) {
|
|
5805
|
+
if (JSON.stringify(expectedValue) !== JSON.stringify(actualValue)) {
|
|
5806
|
+
out.push({
|
|
5807
|
+
kind: "changed",
|
|
5808
|
+
path: pathSoFar,
|
|
5809
|
+
preview: `${String(expectedValue)} \u2192 ${String(actualValue)}`
|
|
5810
|
+
});
|
|
5811
|
+
}
|
|
5812
|
+
} else if (expectedIsObject && !actualIsObject) {
|
|
5813
|
+
out.push({ kind: "changed", path: pathSoFar, preview: "[object] \u2192 primitive" });
|
|
5814
|
+
} else if (!expectedIsObject && actualIsObject) {
|
|
5815
|
+
out.push({ kind: "changed", path: pathSoFar, preview: "primitive \u2192 [object]" });
|
|
5816
|
+
} else {
|
|
5817
|
+
const expectedKeys = new Set(Object.keys(expectedValue));
|
|
5818
|
+
const actualKeys = new Set(Object.keys(actualValue));
|
|
5819
|
+
for (const key of expectedKeys) {
|
|
5820
|
+
if (!actualKeys.has(key) && out.length < limit) {
|
|
5821
|
+
out.push({ kind: "removed", path: `${pathSoFar}.${key}` });
|
|
5822
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
for (const key of actualKeys) {
|
|
5825
|
+
if (!expectedKeys.has(key) && out.length < limit) {
|
|
5826
|
+
out.push({ kind: "added", path: `${pathSoFar}.${key}` });
|
|
5827
|
+
}
|
|
5828
|
+
}
|
|
5829
|
+
for (const key of expectedKeys) {
|
|
5830
|
+
if (actualKeys.has(key) && out.length < limit) {
|
|
5831
|
+
queue.push({
|
|
5832
|
+
pathSoFar: `${pathSoFar}.${key}`,
|
|
5833
|
+
expectedValue: expectedValue[key],
|
|
5834
|
+
actualValue: actualValue[key]
|
|
5835
|
+
});
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
}
|
|
5840
|
+
return out;
|
|
5841
|
+
};
|
|
5842
|
+
const importantMessages = (json) => {
|
|
5843
|
+
const msgs = [];
|
|
5844
|
+
try {
|
|
5845
|
+
const obj = isObject(json) ? json : {};
|
|
5846
|
+
const push = (msg) => {
|
|
5847
|
+
if (typeof msg === "string" && msg.trim()) {
|
|
5848
|
+
msgs.push(msg);
|
|
5849
|
+
}
|
|
5850
|
+
};
|
|
5851
|
+
push(obj.displayMessage);
|
|
5852
|
+
push(obj.message);
|
|
5853
|
+
if (Array.isArray(obj.errors)) {
|
|
5854
|
+
for (const event of obj.errors) {
|
|
5855
|
+
push(isObject(event) ? event.message : void 0);
|
|
5856
|
+
}
|
|
5857
|
+
}
|
|
5858
|
+
if (Array.isArray(obj.data)) {
|
|
5859
|
+
for (const event of obj.data) {
|
|
5860
|
+
push(isObject(event) ? event.message : void 0);
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
} catch {
|
|
5864
|
+
}
|
|
5865
|
+
return msgs.slice(0, 2);
|
|
5866
|
+
};
|
|
5867
|
+
const where = summarizeUrl(relevant.method, relevant.url, relevant.route);
|
|
5868
|
+
const header = [
|
|
5869
|
+
" HTTP:",
|
|
5870
|
+
`
|
|
5871
|
+
${where} ${ansi.dim("->")} ${relevant.statusCode ?? "?"}`,
|
|
5872
|
+
typeof relevant.durationMs === "number" ? ` ${ansi.dim(`(${relevant.durationMs}ms)`)} ` : " ",
|
|
5873
|
+
relevant.contentType ? ansi.dim(`(${relevant.contentType})`) : "",
|
|
5874
|
+
relevant.requestId ? ansi.dim(` reqId=${relevant.requestId}`) : ""
|
|
5875
|
+
].join("");
|
|
5876
|
+
const expVsAct = typeof corr?.expectedNumber === "number" || typeof corr?.receivedNumber === "number" ? (() => {
|
|
5877
|
+
const exp = corr?.expectedNumber != null ? String(corr.expectedNumber) : "?";
|
|
5878
|
+
const got = corr?.receivedNumber != null ? String(corr.receivedNumber) : String(relevant.statusCode ?? "?");
|
|
5879
|
+
return `
|
|
5880
|
+
Expected: ${ansi.yellow(exp)} Received: ${ansi.yellow(got)}`;
|
|
5881
|
+
})() : "";
|
|
5882
|
+
const why = importantMessages(parsedActual ?? relevant.json).map((msg) => `
|
|
5883
|
+
Why: ${ansi.white(msg)}`).slice(0, 1).join("") || "";
|
|
5884
|
+
const diff = (() => {
|
|
5885
|
+
const rightActual = parsedActual ?? relevant.json;
|
|
5886
|
+
if (!parsedExpected || !rightActual) {
|
|
5887
|
+
return "";
|
|
5888
|
+
}
|
|
5889
|
+
const changes = jsonDiff(parsedExpected, rightActual);
|
|
5890
|
+
if (!changes.length) {
|
|
5891
|
+
return "";
|
|
5892
|
+
}
|
|
5893
|
+
const body = changes.map((change) => {
|
|
5894
|
+
const marker = change.kind === "added" ? "+" : change.kind === "removed" ? "-" : "~";
|
|
5895
|
+
const preview = change.preview ? `: ${ansi.dim(change.preview)}` : "";
|
|
5896
|
+
return `
|
|
5897
|
+
${marker} ${change.path}${preview}`;
|
|
5898
|
+
}).join("");
|
|
5899
|
+
return `
|
|
5900
|
+
Diff:${body}`;
|
|
5901
|
+
})();
|
|
5902
|
+
return [header, expVsAct, why, diff, "\n"].filter(Boolean);
|
|
5903
|
+
};
|
|
5522
5904
|
var coerceJestJsonToBridge = (raw) => {
|
|
5523
|
-
if (
|
|
5905
|
+
if (raw && typeof raw === "object" && "aggregated" in raw) {
|
|
5524
5906
|
return raw;
|
|
5525
5907
|
}
|
|
5526
5908
|
const j = raw;
|
|
@@ -5547,19 +5929,113 @@ var coerceJestJsonToBridge = (raw) => {
|
|
|
5547
5929
|
}))
|
|
5548
5930
|
})),
|
|
5549
5931
|
aggregated: {
|
|
5550
|
-
numTotalTestSuites:
|
|
5551
|
-
numPassedTestSuites:
|
|
5552
|
-
numFailedTestSuites:
|
|
5553
|
-
numTotalTests:
|
|
5554
|
-
numPassedTests:
|
|
5555
|
-
numFailedTests:
|
|
5556
|
-
numPendingTests:
|
|
5557
|
-
numTodoTests:
|
|
5558
|
-
startTime:
|
|
5559
|
-
success:
|
|
5932
|
+
numTotalTestSuites: raw.numTotalTestSuites,
|
|
5933
|
+
numPassedTestSuites: raw.numPassedTestSuites,
|
|
5934
|
+
numFailedTestSuites: raw.numFailedTestSuites,
|
|
5935
|
+
numTotalTests: raw.numTotalTests,
|
|
5936
|
+
numPassedTests: raw.numPassedTests,
|
|
5937
|
+
numFailedTests: raw.numFailedTests,
|
|
5938
|
+
numPendingTests: raw.numPendingTests,
|
|
5939
|
+
numTodoTests: raw.numTodoTests,
|
|
5940
|
+
startTime: raw.startTime,
|
|
5941
|
+
success: raw.success,
|
|
5942
|
+
runTimeMs: raw.aggregated?.runTimeMs
|
|
5560
5943
|
}
|
|
5561
5944
|
};
|
|
5562
5945
|
};
|
|
5946
|
+
var renderFailedAssertion = (args) => {
|
|
5947
|
+
const { file, relPath: rel, assertion, ctx, assertionEvents, httpSorted } = args;
|
|
5948
|
+
const header = `${rel} > ${assertion.fullName}`;
|
|
5949
|
+
const bullet = (text) => `${Colors.Failure("\xD7")} ${ansi.white(text)}`;
|
|
5950
|
+
const failureMessage = file.failureMessage || "";
|
|
5951
|
+
const detailMsgs = linesFromDetails(assertion.failureDetails || file.failureDetails).messages;
|
|
5952
|
+
const primaryBlock = assertion.failureMessages?.length ? assertion.failureMessages.join("\n") : failureMessage;
|
|
5953
|
+
const messagesArray = mergeMsgLines(primaryBlock, detailMsgs);
|
|
5954
|
+
const details = linesFromDetails(assertion.failureDetails || file.failureDetails);
|
|
5955
|
+
const mergedForStack = collapseStacks([...messagesArray, ...details.stacks]);
|
|
5956
|
+
const deepestLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
5957
|
+
const locLink = deepestLoc ? (() => {
|
|
5958
|
+
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, ctx.editorCmd);
|
|
5959
|
+
const base = `${deepestLoc.file.split("/").pop()}:${deepestLoc.line}`;
|
|
5960
|
+
return osc8(base, href);
|
|
5961
|
+
})() : void 0;
|
|
5962
|
+
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
5963
|
+
const msgLines = messagesArray.join("\n").split("\n");
|
|
5964
|
+
const assertFallback = deepestLoc || assertion.location && { file: file.testFilePath, line: assertion.location.line };
|
|
5965
|
+
const matcherMsg = (() => {
|
|
5966
|
+
try {
|
|
5967
|
+
const arr = assertion.failureDetails || file.failureDetails;
|
|
5968
|
+
if (!arr) {
|
|
5969
|
+
return empty;
|
|
5970
|
+
}
|
|
5971
|
+
for (const detailEntry of arr) {
|
|
5972
|
+
const obj = detailEntry && typeof detailEntry === "object" ? detailEntry : null;
|
|
5973
|
+
const mr = obj && obj.matcherResult && typeof obj.matcherResult === "object" ? obj.matcherResult : null;
|
|
5974
|
+
if (mr && typeof mr.message === "string" && mr.message.trim()) {
|
|
5975
|
+
const name = typeof mr.matcherName === "string" ? mr.matcherName : "";
|
|
5976
|
+
const matcherHeader = name ? ` ${ansi.bold("Matcher:")} ${ansi.yellow(name)}` : "";
|
|
5977
|
+
const bodyHeader = ` ${ansi.bold("Message:")}`;
|
|
5978
|
+
const body = String(mr.message).split(/\r?\n/).slice(0, 6).map((ln) => ` ${ansi.yellow(ln)}`);
|
|
5979
|
+
return [matcherHeader, bodyHeader, ...body, ""].filter(Boolean);
|
|
5980
|
+
}
|
|
5981
|
+
}
|
|
5982
|
+
} catch {
|
|
5983
|
+
}
|
|
5984
|
+
return empty;
|
|
5985
|
+
})();
|
|
5986
|
+
const code = concat(
|
|
5987
|
+
["", drawFailLine(), bullet(headerLine), ""],
|
|
5988
|
+
buildCodeFrameSection(msgLines, ctx, assertFallback || void 0),
|
|
5989
|
+
[""]
|
|
5990
|
+
);
|
|
5991
|
+
const pretty = buildPrettyDiffSection(assertion.failureDetails || file.failureDetails, msgLines);
|
|
5992
|
+
const hasPretty = pretty.length > 0;
|
|
5993
|
+
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)}`) : [];
|
|
5994
|
+
const message = buildMessageSection(msgLines, details, ctx, {
|
|
5995
|
+
suppressDiff: hasPretty,
|
|
5996
|
+
stackPreview
|
|
5997
|
+
});
|
|
5998
|
+
const httpCard = renderHttpCard({ file, relPath: rel, assertion, assertionEvents, httpSorted });
|
|
5999
|
+
const minimalInfo = msgLines.every((ln) => !ln.trim());
|
|
6000
|
+
const thrown = minimalInfo ? (() => {
|
|
6001
|
+
try {
|
|
6002
|
+
return buildThrownSection(assertion.failureDetails || []);
|
|
6003
|
+
} catch {
|
|
6004
|
+
return empty;
|
|
6005
|
+
}
|
|
6006
|
+
})() : empty;
|
|
6007
|
+
const consoleBlock = buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null));
|
|
6008
|
+
const stackTail = ctx.showStacks && stackPreview.length === 0 ? (() => {
|
|
6009
|
+
const merged = collapseStacks([...msgLines, ...details.stacks]);
|
|
6010
|
+
const tail = collapseStacks(merged).filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
|
|
6011
|
+
return tail.length ? [ansi.dim(" Stack:"), ...tail, ""] : empty;
|
|
6012
|
+
})() : empty;
|
|
6013
|
+
return concat(code, pretty, matcherMsg, message, httpCard, thrown, consoleBlock, stackTail, [
|
|
6014
|
+
drawFailLine(),
|
|
6015
|
+
""
|
|
6016
|
+
]);
|
|
6017
|
+
};
|
|
6018
|
+
var renderFileBlock = (file, env) => {
|
|
6019
|
+
const rel = file.testFilePath.replace(/\\/g, "/").replace(`${env.ctx.cwd}/`, "");
|
|
6020
|
+
const failed = file.testResults.filter((assertion) => assertion.status === "failed");
|
|
6021
|
+
const { http, assertions } = parseBridgeConsole(file.console);
|
|
6022
|
+
const httpSorted = [...http].sort(by((event) => event.timestampMs));
|
|
6023
|
+
return concat(
|
|
6024
|
+
renderPerFileOverviewBlock(rel, file.testResults, env.onlyFailures),
|
|
6025
|
+
renderFileBadge(rel, failed.length, env.onlyFailures),
|
|
6026
|
+
renderFileLevelFailure(file, env.ctx),
|
|
6027
|
+
...failed.map(
|
|
6028
|
+
(assertion) => renderFailedAssertion({
|
|
6029
|
+
file,
|
|
6030
|
+
relPath: rel,
|
|
6031
|
+
assertion,
|
|
6032
|
+
ctx: env.ctx,
|
|
6033
|
+
assertionEvents: assertions,
|
|
6034
|
+
httpSorted
|
|
6035
|
+
})
|
|
6036
|
+
)
|
|
6037
|
+
);
|
|
6038
|
+
};
|
|
5563
6039
|
var vitestFooter = (agg, durationMs) => {
|
|
5564
6040
|
const files = [
|
|
5565
6041
|
agg.numFailedTestSuites ? colorTokens2.fail(`${agg.numFailedTestSuites} failed`) : "",
|
|
@@ -5580,469 +6056,39 @@ var vitestFooter = (agg, durationMs) => {
|
|
|
5580
6056
|
`${ansi.bold("Time")} ${time} ${thread}`
|
|
5581
6057
|
].join("\n");
|
|
5582
6058
|
};
|
|
5583
|
-
var
|
|
5584
|
-
const out = [];
|
|
5585
|
-
const onlyFailures = Boolean(opts?.onlyFailures);
|
|
5586
|
-
if (!onlyFailures) {
|
|
5587
|
-
out.push(`${BackgroundColors.Run(ansi.white(" RUN "))} ${ansi.dim(ctx.cwd)}`, "");
|
|
5588
|
-
}
|
|
5589
|
-
for (const file of data.testResults) {
|
|
5590
|
-
const rel = file.testFilePath.replace(/\\/g, "/").replace(`${ctx.cwd}/`, "");
|
|
5591
|
-
const failed = file.testResults.filter((assertion) => assertion.status === "failed");
|
|
5592
|
-
if (!onlyFailures) {
|
|
5593
|
-
out.push(...buildPerFileOverview(rel, file.testResults));
|
|
5594
|
-
}
|
|
5595
|
-
if (!(onlyFailures && failed.length === 0)) {
|
|
5596
|
-
out.push(buildFileBadgeLine(rel, failed.length));
|
|
5597
|
-
}
|
|
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) {
|
|
5692
|
-
const lines = file.failureMessage.split(/\r?\n/);
|
|
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);
|
|
5705
|
-
out.push(...buildCodeFrameSection(lines, ctx, synthLoc));
|
|
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)}`) : [];
|
|
5710
|
-
out.push(
|
|
5711
|
-
...buildMessageSection(lines, combinedDetails, ctx, {
|
|
5712
|
-
suppressDiff: hasPretty,
|
|
5713
|
-
stackPreview
|
|
5714
|
-
})
|
|
5715
|
-
);
|
|
5716
|
-
out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
|
|
5717
|
-
if (ctx.showStacks && stackPreview.length === 0) {
|
|
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
|
-
}
|
|
5722
|
-
}
|
|
5723
|
-
}
|
|
5724
|
-
for (const assertion of failed) {
|
|
5725
|
-
out.push(drawFailLine());
|
|
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
|
-
})();
|
|
5764
|
-
const mergedForStack = collapseStacks([...messagesArray, ...details.stacks]);
|
|
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}`;
|
|
5769
|
-
return osc8(base, href);
|
|
5770
|
-
})() : void 0;
|
|
5771
|
-
const bullet = (text) => `${Colors.Failure("\xD7")} ${ansi.white(text)}`;
|
|
5772
|
-
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
5773
|
-
out.push(bullet(headerLine));
|
|
5774
|
-
const msgLines = messagesArray.join("\n").split("\n");
|
|
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
|
-
}
|
|
5787
|
-
out.push(
|
|
5788
|
-
...buildMessageSection(msgLines, details, ctx, { suppressDiff: hasPretty, stackPreview })
|
|
5789
|
-
);
|
|
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
|
|
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
|
-
}
|
|
6015
|
-
}
|
|
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(), "");
|
|
6031
|
-
}
|
|
6032
|
-
}
|
|
6059
|
+
var renderFooter = (data) => {
|
|
6033
6060
|
const failedCount = data.aggregated.numFailedTests;
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6061
|
+
return [
|
|
6062
|
+
drawRule(BackgroundColors.Failure(ansi.white(` Failed Tests ${failedCount} `))),
|
|
6063
|
+
"",
|
|
6064
|
+
vitestFooter(data.aggregated)
|
|
6065
|
+
];
|
|
6038
6066
|
};
|
|
6067
|
+
var renderVitestFromJestJSON = (data, ctx, opts) => pipe(
|
|
6068
|
+
concat(
|
|
6069
|
+
renderRunHeader({ ctx, onlyFailures: Boolean(opts?.onlyFailures) }),
|
|
6070
|
+
...data.testResults.map(
|
|
6071
|
+
(file) => renderFileBlock(file, { ctx, onlyFailures: Boolean(opts?.onlyFailures) })
|
|
6072
|
+
),
|
|
6073
|
+
renderFooter(data)
|
|
6074
|
+
),
|
|
6075
|
+
joinLines
|
|
6076
|
+
);
|
|
6077
|
+
|
|
6078
|
+
// src/lib/formatter/bridge/tryBridgeFallback.ts
|
|
6039
6079
|
var tryBridgeFallback = (raw, ctx, opts) => {
|
|
6040
|
-
|
|
6080
|
+
let bridgeJsonPath = extractBridgePath2(raw, ctx.cwd);
|
|
6081
|
+
if (!bridgeJsonPath) {
|
|
6082
|
+
const def = path11.resolve(ctx.cwd, "coverage/jest-run.json").replace(/\\/g, "/");
|
|
6083
|
+
if (fs6.existsSync(def)) {
|
|
6084
|
+
bridgeJsonPath = def;
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6041
6087
|
if (!bridgeJsonPath || !fs6.existsSync(bridgeJsonPath)) {
|
|
6042
6088
|
return null;
|
|
6043
6089
|
}
|
|
6044
6090
|
try {
|
|
6045
|
-
const json =
|
|
6091
|
+
const json = import_json53.default.parse(fs6.readFileSync(bridgeJsonPath, "utf8"));
|
|
6046
6092
|
const bridge = coerceJestJsonToBridge(json);
|
|
6047
6093
|
return renderVitestFromJestJSON(bridge, ctx, opts);
|
|
6048
6094
|
} catch {
|
|
@@ -6060,23 +6106,39 @@ var formatJestOutputVitest = (raw, opts) => pipe(
|
|
|
6060
6106
|
(state) => ({ ...state, chunks: parseChunks(state.raw) }),
|
|
6061
6107
|
(state) => ({
|
|
6062
6108
|
...state,
|
|
6063
|
-
|
|
6109
|
+
native: renderChunks(state.chunks, state.ctx, mkPrettyFns(), {
|
|
6064
6110
|
onlyFailures: Boolean(state.opts?.onlyFailures)
|
|
6065
|
-
})
|
|
6111
|
+
}).text
|
|
6066
6112
|
}),
|
|
6067
|
-
(state) => {
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
}
|
|
6071
|
-
const fallback = tryBridgeFallback(state.raw, state.ctx, {
|
|
6113
|
+
(state) => ({
|
|
6114
|
+
...state,
|
|
6115
|
+
bridge: tryBridgeFallback(state.raw, state.ctx, {
|
|
6072
6116
|
onlyFailures: Boolean(state.opts?.onlyFailures)
|
|
6073
|
-
})
|
|
6074
|
-
|
|
6075
|
-
|
|
6117
|
+
}) || null
|
|
6118
|
+
}),
|
|
6119
|
+
(state) => {
|
|
6120
|
+
const out = [];
|
|
6121
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6122
|
+
const pushUnique = (text) => {
|
|
6123
|
+
if (!text) {
|
|
6124
|
+
return;
|
|
6125
|
+
}
|
|
6126
|
+
for (const line of text.split(/\r?\n/)) {
|
|
6127
|
+
const key = stripAnsiSimple(line);
|
|
6128
|
+
if (!seen.has(key)) {
|
|
6129
|
+
out.push(line);
|
|
6130
|
+
seen.add(key);
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
};
|
|
6134
|
+
pushUnique(state.native);
|
|
6135
|
+
if (state.bridge) {
|
|
6136
|
+
if (out.length) {
|
|
6137
|
+
out.push("");
|
|
6138
|
+
}
|
|
6139
|
+
pushUnique(state.bridge);
|
|
6076
6140
|
}
|
|
6077
|
-
|
|
6078
|
-
return prefix ? `${prefix}
|
|
6079
|
-
${fallback}` : fallback;
|
|
6141
|
+
return out.join("\n");
|
|
6080
6142
|
}
|
|
6081
6143
|
);
|
|
6082
6144
|
|
|
@@ -6123,7 +6185,7 @@ var mergeLcov = async () => {
|
|
|
6123
6185
|
try {
|
|
6124
6186
|
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
6125
6187
|
for (const entry of entries) {
|
|
6126
|
-
const full =
|
|
6188
|
+
const full = path12.join(dir, entry.name);
|
|
6127
6189
|
if (entry.isDirectory()) {
|
|
6128
6190
|
out.push(...collectLcovs(full));
|
|
6129
6191
|
} else if (entry.isFile() && entry.name === "lcov.info") {
|
|
@@ -6135,8 +6197,8 @@ var mergeLcov = async () => {
|
|
|
6135
6197
|
return out;
|
|
6136
6198
|
};
|
|
6137
6199
|
try {
|
|
6138
|
-
const jestRoot =
|
|
6139
|
-
const candidates = [
|
|
6200
|
+
const jestRoot = path12.join("coverage", "jest");
|
|
6201
|
+
const candidates = [path12.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path12.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
|
|
6140
6202
|
for (const filePath of candidates) {
|
|
6141
6203
|
try {
|
|
6142
6204
|
const content = await readOrEmpty(filePath);
|
|
@@ -6176,7 +6238,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6176
6238
|
try {
|
|
6177
6239
|
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
6178
6240
|
for (const entry of entries) {
|
|
6179
|
-
const full =
|
|
6241
|
+
const full = path12.join(dir, entry.name);
|
|
6180
6242
|
if (entry.isDirectory()) {
|
|
6181
6243
|
out.push(...listJsons(full));
|
|
6182
6244
|
} else if (entry.isFile() && entry.name === "coverage-final.json") {
|
|
@@ -6187,11 +6249,11 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6187
6249
|
}
|
|
6188
6250
|
return out;
|
|
6189
6251
|
};
|
|
6190
|
-
const coverageRoot =
|
|
6252
|
+
const coverageRoot = path12.join("coverage", "jest");
|
|
6191
6253
|
const jsonCandidates = [
|
|
6192
|
-
|
|
6254
|
+
path12.join(coverageRoot, "coverage-final.json"),
|
|
6193
6255
|
...listJsons(coverageRoot)
|
|
6194
|
-
].map((candidatePath) =>
|
|
6256
|
+
].map((candidatePath) => path12.resolve(candidatePath)).filter((absolutePath, index, arr) => {
|
|
6195
6257
|
const isFirst = arr.indexOf(absolutePath) === index;
|
|
6196
6258
|
const exists = fsSync3.existsSync(absolutePath);
|
|
6197
6259
|
return isFirst && exists;
|
|
@@ -6253,7 +6315,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6253
6315
|
executedTests: opts.executedTests ?? []
|
|
6254
6316
|
});
|
|
6255
6317
|
const context = LibReport.createContext({
|
|
6256
|
-
dir:
|
|
6318
|
+
dir: path12.resolve("coverage", "merged"),
|
|
6257
6319
|
coverageMap: filteredMap,
|
|
6258
6320
|
defaultSummarizer: "nested"
|
|
6259
6321
|
});
|
|
@@ -6321,8 +6383,8 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6321
6383
|
for (const reporter of reporters) {
|
|
6322
6384
|
reporter.execute(context);
|
|
6323
6385
|
}
|
|
6324
|
-
const textPath =
|
|
6325
|
-
const summaryPath =
|
|
6386
|
+
const textPath = path12.resolve("coverage", "merged", "coverage.txt");
|
|
6387
|
+
const summaryPath = path12.resolve("coverage", "merged", "coverage-summary.txt");
|
|
6326
6388
|
const filesToPrint = [];
|
|
6327
6389
|
if (fsSync3.existsSync(textPath)) {
|
|
6328
6390
|
filesToPrint.push(textPath);
|
|
@@ -6465,13 +6527,13 @@ var program = async () => {
|
|
|
6465
6527
|
const rels2 = Array.from(
|
|
6466
6528
|
/* @__PURE__ */ new Set([...branchDiff, ...stagedNow, ...unstagedNow, ...untrackedNow])
|
|
6467
6529
|
);
|
|
6468
|
-
return rels2.map((rel) =>
|
|
6530
|
+
return rels2.map((rel) => path12.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
6469
6531
|
}
|
|
6470
6532
|
const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
|
|
6471
6533
|
const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
|
|
6472
6534
|
const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
|
|
6473
6535
|
const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
|
|
6474
|
-
return rels.map((rel) =>
|
|
6536
|
+
return rels.map((rel) => path12.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
6475
6537
|
};
|
|
6476
6538
|
const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
|
|
6477
6539
|
const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
|
|
@@ -6496,18 +6558,18 @@ var program = async () => {
|
|
|
6496
6558
|
if (!token) {
|
|
6497
6559
|
continue;
|
|
6498
6560
|
}
|
|
6499
|
-
const isAbs =
|
|
6561
|
+
const isAbs = path12.isAbsolute(token);
|
|
6500
6562
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
6501
6563
|
let candidateFromRoot;
|
|
6502
6564
|
if (token.startsWith("/")) {
|
|
6503
|
-
candidateFromRoot =
|
|
6565
|
+
candidateFromRoot = path12.join(repoRoot, token.slice(1));
|
|
6504
6566
|
} else if (looksLikeRelPath) {
|
|
6505
|
-
candidateFromRoot =
|
|
6567
|
+
candidateFromRoot = path12.join(repoRoot, token);
|
|
6506
6568
|
} else {
|
|
6507
6569
|
candidateFromRoot = void 0;
|
|
6508
6570
|
}
|
|
6509
6571
|
const tryPushIfProd = (absPath) => {
|
|
6510
|
-
const norm =
|
|
6572
|
+
const norm = path12.resolve(absPath).replace(/\\/g, "/");
|
|
6511
6573
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
6512
6574
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
6513
6575
|
results.add(norm);
|
|
@@ -6529,7 +6591,7 @@ var program = async () => {
|
|
|
6529
6591
|
}),
|
|
6530
6592
|
timeoutMs: 4e3
|
|
6531
6593
|
});
|
|
6532
|
-
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) =>
|
|
6594
|
+
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path12.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
|
|
6533
6595
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
6534
6596
|
);
|
|
6535
6597
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -6550,8 +6612,8 @@ var program = async () => {
|
|
|
6550
6612
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
6551
6613
|
const projectConfigs = [];
|
|
6552
6614
|
try {
|
|
6553
|
-
const baseCfg =
|
|
6554
|
-
const tsCfg =
|
|
6615
|
+
const baseCfg = path12.resolve("jest.config.js");
|
|
6616
|
+
const tsCfg = path12.resolve("jest.ts.config.js");
|
|
6555
6617
|
if (fsSync3.existsSync(baseCfg)) {
|
|
6556
6618
|
projectConfigs.push(baseCfg);
|
|
6557
6619
|
}
|
|
@@ -6568,7 +6630,7 @@ var program = async () => {
|
|
|
6568
6630
|
);
|
|
6569
6631
|
const prodSelections2 = expandedProdSelections;
|
|
6570
6632
|
for (const cfg of projectConfigs) {
|
|
6571
|
-
const cfgCwd =
|
|
6633
|
+
const cfgCwd = path12.dirname(cfg);
|
|
6572
6634
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
6573
6635
|
cwd: cfgCwd
|
|
6574
6636
|
});
|
|
@@ -6581,7 +6643,7 @@ var program = async () => {
|
|
|
6581
6643
|
});
|
|
6582
6644
|
} catch (err) {
|
|
6583
6645
|
if (isDebug()) {
|
|
6584
|
-
console.warn(`direct selection failed for project ${
|
|
6646
|
+
console.warn(`direct selection failed for project ${path12.basename(cfg)}: ${String(err)}`);
|
|
6585
6647
|
}
|
|
6586
6648
|
}
|
|
6587
6649
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -6593,7 +6655,7 @@ var program = async () => {
|
|
|
6593
6655
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
6594
6656
|
);
|
|
6595
6657
|
for (const cfg of projectConfigs) {
|
|
6596
|
-
const cfgCwd =
|
|
6658
|
+
const cfgCwd = path12.dirname(cfg);
|
|
6597
6659
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
6598
6660
|
cwd: cfgCwd
|
|
6599
6661
|
});
|
|
@@ -6608,13 +6670,13 @@ var program = async () => {
|
|
|
6608
6670
|
);
|
|
6609
6671
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
6610
6672
|
const absFiles = candidates.map(
|
|
6611
|
-
(candidatePath) =>
|
|
6673
|
+
(candidatePath) => path12.isAbsolute(candidatePath) ? candidatePath : path12.join(repoRootForDiscovery, candidatePath)
|
|
6612
6674
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
6613
6675
|
const onlyOwned = await filterCandidatesForProject(
|
|
6614
6676
|
cfg,
|
|
6615
6677
|
jestDiscoveryArgs,
|
|
6616
6678
|
absFiles,
|
|
6617
|
-
|
|
6679
|
+
path12.dirname(cfg)
|
|
6618
6680
|
);
|
|
6619
6681
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
6620
6682
|
}
|
|
@@ -6626,7 +6688,7 @@ var program = async () => {
|
|
|
6626
6688
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
6627
6689
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
6628
6690
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
6629
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
6691
|
+
const selectionKey = prodSelections.map((absPath) => path12.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
6630
6692
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
6631
6693
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
6632
6694
|
const rgMatches = await cachedRelated2({
|
|
@@ -6656,7 +6718,7 @@ var program = async () => {
|
|
|
6656
6718
|
cfg,
|
|
6657
6719
|
jestDiscoveryArgs,
|
|
6658
6720
|
rgCandidates,
|
|
6659
|
-
|
|
6721
|
+
path12.dirname(cfg)
|
|
6660
6722
|
);
|
|
6661
6723
|
perProjectFromRg.set(cfg, owned);
|
|
6662
6724
|
}
|
|
@@ -6671,9 +6733,9 @@ var program = async () => {
|
|
|
6671
6733
|
} else {
|
|
6672
6734
|
const repoRootForScan = repoRootForDiscovery;
|
|
6673
6735
|
const toSeeds = (abs) => {
|
|
6674
|
-
const rel =
|
|
6736
|
+
const rel = path12.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
6675
6737
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
6676
|
-
const base =
|
|
6738
|
+
const base = path12.basename(withoutExt);
|
|
6677
6739
|
const segs = withoutExt.split("/");
|
|
6678
6740
|
const tail2 = segs.slice(-2).join("/");
|
|
6679
6741
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -6688,8 +6750,8 @@ var program = async () => {
|
|
|
6688
6750
|
}
|
|
6689
6751
|
};
|
|
6690
6752
|
const resolveLocalImport = (fromFile, spec) => {
|
|
6691
|
-
const baseDir =
|
|
6692
|
-
const cand =
|
|
6753
|
+
const baseDir = path12.dirname(fromFile);
|
|
6754
|
+
const cand = path12.resolve(baseDir, spec);
|
|
6693
6755
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
6694
6756
|
for (const ext of exts) {
|
|
6695
6757
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -6698,7 +6760,7 @@ var program = async () => {
|
|
|
6698
6760
|
}
|
|
6699
6761
|
}
|
|
6700
6762
|
for (const ext of exts) {
|
|
6701
|
-
const full =
|
|
6763
|
+
const full = path12.join(cand, `index${ext}`);
|
|
6702
6764
|
if (fsSync3.existsSync(full)) {
|
|
6703
6765
|
return full;
|
|
6704
6766
|
}
|
|
@@ -6752,7 +6814,7 @@ var program = async () => {
|
|
|
6752
6814
|
cfg,
|
|
6753
6815
|
jestDiscoveryArgs,
|
|
6754
6816
|
keptCandidates,
|
|
6755
|
-
|
|
6817
|
+
path12.dirname(cfg)
|
|
6756
6818
|
);
|
|
6757
6819
|
perProjectFromScan.set(cfg, owned);
|
|
6758
6820
|
}
|
|
@@ -6782,7 +6844,7 @@ var program = async () => {
|
|
|
6782
6844
|
try {
|
|
6783
6845
|
const allAcross = [];
|
|
6784
6846
|
for (const cfg of projectConfigs) {
|
|
6785
|
-
const cfgCwd =
|
|
6847
|
+
const cfgCwd = path12.dirname(cfg);
|
|
6786
6848
|
const listed = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
6787
6849
|
cwd: cfgCwd
|
|
6788
6850
|
});
|
|
@@ -6796,9 +6858,9 @@ var program = async () => {
|
|
|
6796
6858
|
}
|
|
6797
6859
|
}
|
|
6798
6860
|
const seeds = prodSelections.map(
|
|
6799
|
-
(abs) =>
|
|
6861
|
+
(abs) => path12.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
6800
6862
|
).flatMap((rel) => {
|
|
6801
|
-
const base =
|
|
6863
|
+
const base = path12.basename(rel);
|
|
6802
6864
|
const segments = rel.split("/");
|
|
6803
6865
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
6804
6866
|
});
|
|
@@ -6811,8 +6873,8 @@ var program = async () => {
|
|
|
6811
6873
|
}
|
|
6812
6874
|
};
|
|
6813
6875
|
const resolveLocalImport = (fromFile, spec) => {
|
|
6814
|
-
const baseDir =
|
|
6815
|
-
const candidate =
|
|
6876
|
+
const baseDir = path12.dirname(fromFile);
|
|
6877
|
+
const candidate = path12.resolve(baseDir, spec);
|
|
6816
6878
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
6817
6879
|
for (const ext of extensions) {
|
|
6818
6880
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -6821,7 +6883,7 @@ var program = async () => {
|
|
|
6821
6883
|
}
|
|
6822
6884
|
}
|
|
6823
6885
|
for (const ext of extensions) {
|
|
6824
|
-
const fullPath =
|
|
6886
|
+
const fullPath = path12.join(candidate, `index${ext}`);
|
|
6825
6887
|
if (fsSync3.existsSync(fullPath)) {
|
|
6826
6888
|
return fullPath;
|
|
6827
6889
|
}
|
|
@@ -6978,10 +7040,10 @@ var program = async () => {
|
|
|
6978
7040
|
};
|
|
6979
7041
|
const prodSeedsForRun = (() => {
|
|
6980
7042
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
6981
|
-
(absPath) =>
|
|
7043
|
+
(absPath) => path12.resolve(absPath).replace(/\\/g, "/")
|
|
6982
7044
|
);
|
|
6983
7045
|
const selAbs = selectionPathsAugmented.map(
|
|
6984
|
-
(pathToken) =>
|
|
7046
|
+
(pathToken) => path12.resolve(pathToken).replace(/\\/g, "/")
|
|
6985
7047
|
);
|
|
6986
7048
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
6987
7049
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
@@ -6996,17 +7058,17 @@ var program = async () => {
|
|
|
6996
7058
|
const cfg = projectsToRun[projIndex];
|
|
6997
7059
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
6998
7060
|
if (files.length === 0) {
|
|
6999
|
-
console.info(`Project ${
|
|
7061
|
+
console.info(`Project ${path12.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
7000
7062
|
continue;
|
|
7001
7063
|
}
|
|
7002
7064
|
files.forEach(
|
|
7003
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
7065
|
+
(absTestPath) => executedTestFilesSet.add(path12.resolve(absTestPath).replace(/\\/g, "/"))
|
|
7004
7066
|
);
|
|
7005
|
-
const outJson =
|
|
7067
|
+
const outJson = path12.join(
|
|
7006
7068
|
os3.tmpdir(),
|
|
7007
7069
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
7008
7070
|
);
|
|
7009
|
-
const reporterPath =
|
|
7071
|
+
const reporterPath = path12.resolve("scripts/jest-vitest-bridge.cjs");
|
|
7010
7072
|
try {
|
|
7011
7073
|
const needsWrite = (() => {
|
|
7012
7074
|
try {
|
|
@@ -7017,10 +7079,10 @@ var program = async () => {
|
|
|
7017
7079
|
}
|
|
7018
7080
|
})();
|
|
7019
7081
|
if (needsWrite) {
|
|
7020
|
-
fsSync3.mkdirSync(
|
|
7082
|
+
fsSync3.mkdirSync(path12.dirname(reporterPath), { recursive: true });
|
|
7021
7083
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
7022
7084
|
}
|
|
7023
|
-
const envPath =
|
|
7085
|
+
const envPath = path12.resolve("scripts/jest-bridge-env.cjs");
|
|
7024
7086
|
try {
|
|
7025
7087
|
const existingEnv = fsSync3.readFileSync(envPath, "utf8");
|
|
7026
7088
|
if (existingEnv !== JEST_BRIDGE_ENV_SOURCE) {
|
|
@@ -7028,7 +7090,7 @@ var program = async () => {
|
|
|
7028
7090
|
}
|
|
7029
7091
|
} catch {
|
|
7030
7092
|
try {
|
|
7031
|
-
fsSync3.mkdirSync(
|
|
7093
|
+
fsSync3.mkdirSync(path12.dirname(envPath), { recursive: true });
|
|
7032
7094
|
} catch {
|
|
7033
7095
|
}
|
|
7034
7096
|
fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
|
|
@@ -7036,7 +7098,7 @@ var program = async () => {
|
|
|
7036
7098
|
} catch (ensureReporterError) {
|
|
7037
7099
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
7038
7100
|
}
|
|
7039
|
-
const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) =>
|
|
7101
|
+
const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path12.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
|
|
7040
7102
|
const coverageFromArgs = [];
|
|
7041
7103
|
for (const relPath2 of selectedFilesForCoverage) {
|
|
7042
7104
|
coverageFromArgs.push("--collectCoverageFrom", relPath2);
|
|
@@ -7054,11 +7116,11 @@ var program = async () => {
|
|
|
7054
7116
|
`--reporters=${reporterPath}`,
|
|
7055
7117
|
"--colors",
|
|
7056
7118
|
"--env",
|
|
7057
|
-
|
|
7119
|
+
path12.resolve("scripts/jest-bridge-env.cjs"),
|
|
7058
7120
|
...sanitizedJestRunArgs,
|
|
7059
7121
|
...collectCoverage ? [
|
|
7060
7122
|
"--coverageDirectory",
|
|
7061
|
-
|
|
7123
|
+
path12.join("coverage", "jest", path12.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
7062
7124
|
] : [],
|
|
7063
7125
|
...coverageFromArgs,
|
|
7064
7126
|
"--passWithNoTests",
|
|
@@ -7184,10 +7246,10 @@ ${stripFooter(rawAlso)}`.trimEnd();
|
|
|
7184
7246
|
try {
|
|
7185
7247
|
const prodSeeds = (() => {
|
|
7186
7248
|
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
7187
|
-
(absPath) =>
|
|
7249
|
+
(absPath) => path12.resolve(absPath).replace(/\\/g, "/")
|
|
7188
7250
|
);
|
|
7189
7251
|
const selAbs = selectionPathsAugmented.map(
|
|
7190
|
-
(pathToken) =>
|
|
7252
|
+
(pathToken) => path12.resolve(pathToken).replace(/\\/g, "/")
|
|
7191
7253
|
);
|
|
7192
7254
|
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
7193
7255
|
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|