ccqa 1.57.1 → 1.57.3
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/bin/ccqa.mjs +317 -158
- package/dist/{evidence-constants-BkPzGtzI.cjs → evidence-constants-BNe7Q305.cjs} +2 -2
- package/dist/{evidence-constants-BLXD0LRY.mjs → evidence-constants-WMpQPI8P.mjs} +2 -2
- package/dist/hub-client/index.d.cts +4 -4
- package/dist/hub-client/index.d.mts +4 -4
- package/dist/package.json +1 -1
- package/dist/runtime/step-evidence.cjs +1 -1
- package/dist/runtime/step-evidence.mjs +1 -1
- package/dist/runtime/test-helpers.cjs +1 -1
- package/dist/runtime/test-helpers.mjs +1 -1
- package/package.json +1 -1
package/dist/bin/ccqa.mjs
CHANGED
|
@@ -8154,19 +8154,19 @@ function aliasCandidates(specifier, tsconfig) {
|
|
|
8154
8154
|
}
|
|
8155
8155
|
/** A path → the file it names: itself, `<path><ext>`, or `<path>/index<ext>`. */
|
|
8156
8156
|
async function resolveFile(pathAbs) {
|
|
8157
|
-
if (await isFile(pathAbs)) return pathAbs;
|
|
8157
|
+
if (await isFile$1(pathAbs)) return pathAbs;
|
|
8158
8158
|
const rewritten = pathAbs.replace(/\.(js|mjs|cjs)$/, "");
|
|
8159
8159
|
if (rewritten !== pathAbs) {
|
|
8160
|
-
for (const ext of EXTENSIONS) if (await isFile(rewritten + ext)) return rewritten + ext;
|
|
8160
|
+
for (const ext of EXTENSIONS) if (await isFile$1(rewritten + ext)) return rewritten + ext;
|
|
8161
8161
|
}
|
|
8162
|
-
for (const ext of EXTENSIONS) if (await isFile(pathAbs + ext)) return pathAbs + ext;
|
|
8162
|
+
for (const ext of EXTENSIONS) if (await isFile$1(pathAbs + ext)) return pathAbs + ext;
|
|
8163
8163
|
for (const ext of EXTENSIONS) {
|
|
8164
8164
|
const indexed = join(pathAbs, `index${ext}`);
|
|
8165
|
-
if (await isFile(indexed)) return indexed;
|
|
8165
|
+
if (await isFile$1(indexed)) return indexed;
|
|
8166
8166
|
}
|
|
8167
8167
|
return null;
|
|
8168
8168
|
}
|
|
8169
|
-
function isFile(pathAbs) {
|
|
8169
|
+
function isFile$1(pathAbs) {
|
|
8170
8170
|
return stat(pathAbs).then((s) => s.isFile(), () => false);
|
|
8171
8171
|
}
|
|
8172
8172
|
/** `export const NAME` / `export function NAME` / `export class NAME`, and `export { A, B }`. */
|
|
@@ -9338,8 +9338,8 @@ function mergeFindings(undecided, fromModel) {
|
|
|
9338
9338
|
*
|
|
9339
9339
|
* Several producers write the `<id>.png` + `<id>.json` pairs —
|
|
9340
9340
|
* `abStepEvidence()` / `captureFailureEvidence()` in `test-helpers.ts`
|
|
9341
|
-
* (agent-browser replays), `targets/playwright/trace-capture.ts` (
|
|
9342
|
-
*
|
|
9341
|
+
* (agent-browser replays), `targets/playwright/trace-capture.ts` (snapshots
|
|
9342
|
+
* rendered from a run's Playwright trace), and `ccqaStepBefore`/`ccqaStepAfter` in
|
|
9343
9343
|
* `step-evidence.ts` for tests generated before the capture calls left the
|
|
9344
9344
|
* committed file — and one consumer reads them back (`loadEvidenceForSpec` in
|
|
9345
9345
|
* `report/evidence.ts`). They agree only on the contract here, so it is kept
|
|
@@ -13712,10 +13712,10 @@ function emptySpecRow(args) {
|
|
|
13712
13712
|
*
|
|
13713
13713
|
* Producer-agnostic on purpose. Very different writers fill these directories
|
|
13714
13714
|
* — `abStepEvidence()` during an agent-browser replay, and, for a Playwright
|
|
13715
|
-
* target,
|
|
13715
|
+
* target, snapshots rendered from the run's trace once the command has exited
|
|
13716
13716
|
* — and they only have to agree on the file-pair convention documented here,
|
|
13717
13717
|
* not on how or when the screenshot was taken. `pngFile` names the image
|
|
13718
|
-
* whatever its format: a trace
|
|
13718
|
+
* whatever its format: the ones rendered from a trace are JPEG.
|
|
13719
13719
|
*/
|
|
13720
13720
|
/** `<reportDir>/evidence/<feature>/<spec>` — one directory per spec. */
|
|
13721
13721
|
function specEvidenceDir(reportDir, feature, spec) {
|
|
@@ -13864,20 +13864,21 @@ function readLocalEntryData(buf, offset, method, compressedSize) {
|
|
|
13864
13864
|
return null;
|
|
13865
13865
|
}
|
|
13866
13866
|
/**
|
|
13867
|
-
* The
|
|
13867
|
+
* The calls one trace holds, each runner-side call with the DOM at its two
|
|
13868
|
+
* boundaries: the before-snapshot of the first Playwright call inside it and the
|
|
13869
|
+
* after-snapshot of the last, whatever kind of call (action, wait, assertion).
|
|
13870
|
+
* Nothing the test did not itself wait for is shown — a step ending in a click
|
|
13871
|
+
* shows the DOM right after the click. Calls count at any depth, so a step
|
|
13872
|
+
* nested in another counts toward both.
|
|
13868
13873
|
*
|
|
13869
|
-
* A trace is JSON Lines
|
|
13870
|
-
*
|
|
13871
|
-
*
|
|
13872
|
-
* `
|
|
13873
|
-
* both are folded into the same `TraceStep` shape here so callers never see
|
|
13874
|
-
* the version skew.
|
|
13874
|
+
* A trace is JSON Lines; a corrupt or truncated line must not sink the whole
|
|
13875
|
+
* read, so parsing is best-effort per line. A browser call points at the
|
|
13876
|
+
* runner call it ran in through `stepId`; the runner calls chain through
|
|
13877
|
+
* `parentId`.
|
|
13875
13878
|
*/
|
|
13876
|
-
function
|
|
13877
|
-
const
|
|
13878
|
-
const
|
|
13879
|
-
const pendingByCallId = /* @__PURE__ */ new Map();
|
|
13880
|
-
let maxTimestamp = -Infinity;
|
|
13879
|
+
function parseTraceSteps(jsonl) {
|
|
13880
|
+
const calls = /* @__PURE__ */ new Map();
|
|
13881
|
+
const viewports = /* @__PURE__ */ new Map();
|
|
13881
13882
|
for (const line of jsonl.split("\n")) {
|
|
13882
13883
|
if (line.trim() === "") continue;
|
|
13883
13884
|
let parsed;
|
|
@@ -13888,58 +13889,72 @@ function parseTraceEvents(jsonl) {
|
|
|
13888
13889
|
}
|
|
13889
13890
|
if (typeof parsed !== "object" || parsed === null) continue;
|
|
13890
13891
|
const event = parsed;
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
}
|
|
13899
|
-
const type = event.type;
|
|
13900
|
-
if (type === "screencast-frame") {
|
|
13901
|
-
if (typeof event.sha1 === "string" && typeof event.timestamp === "number") frames.push({
|
|
13902
|
-
sha1: event.sha1,
|
|
13903
|
-
timestamp: event.timestamp
|
|
13892
|
+
const callId = event.callId;
|
|
13893
|
+
if (event.type === "frame-snapshot") {
|
|
13894
|
+
const snapshot = event.snapshot;
|
|
13895
|
+
const viewport = snapshot?.viewport;
|
|
13896
|
+
if (typeof snapshot?.snapshotName === "string" && snapshot.isMainFrame !== false && typeof viewport?.width === "number" && typeof viewport.height === "number" && !viewports.has(snapshot.snapshotName)) viewports.set(snapshot.snapshotName, {
|
|
13897
|
+
width: viewport.width,
|
|
13898
|
+
height: viewport.height
|
|
13904
13899
|
});
|
|
13905
|
-
} else if (type === "action") {
|
|
13906
|
-
if (typeof event.
|
|
13900
|
+
} else if ((event.type === "before" || event.type === "action") && typeof callId === "string") {
|
|
13901
|
+
if (typeof event.startTime !== "number") continue;
|
|
13902
|
+
const parent = (typeof event.stepId === "string" && event.stepId !== callId ? event.stepId : void 0) ?? (typeof event.parentId === "string" ? event.parentId : void 0);
|
|
13903
|
+
calls.set(callId, {
|
|
13907
13904
|
title: titleOf$1(event),
|
|
13908
13905
|
startTime: event.startTime,
|
|
13909
|
-
|
|
13910
|
-
...
|
|
13911
|
-
|
|
13912
|
-
} else if (type === "before") {
|
|
13913
|
-
if (typeof event.callId === "string" && typeof event.startTime === "number") pendingByCallId.set(event.callId, {
|
|
13914
|
-
title: titleOf$1(event),
|
|
13915
|
-
startTime: event.startTime
|
|
13906
|
+
...parent !== void 0 ? { parent } : {},
|
|
13907
|
+
...typeof event.pageId === "string" ? { pageId: event.pageId } : {},
|
|
13908
|
+
...typeof event.beforeSnapshot === "string" ? { beforeSnapshot: event.beforeSnapshot } : {}
|
|
13916
13909
|
});
|
|
13917
|
-
}
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
endTime: event.endTime,
|
|
13925
|
-
...errorOf(event)
|
|
13926
|
-
});
|
|
13927
|
-
}
|
|
13928
|
-
}
|
|
13910
|
+
}
|
|
13911
|
+
if ((event.type === "after" || event.type === "action") && typeof callId === "string") {
|
|
13912
|
+
const call = calls.get(callId);
|
|
13913
|
+
if (call === void 0) continue;
|
|
13914
|
+
if (typeof event.endTime === "number") call.endTime = event.endTime;
|
|
13915
|
+
if (typeof event.afterSnapshot === "string") call.afterSnapshot = event.afterSnapshot;
|
|
13916
|
+
Object.assign(call, errorOf(event));
|
|
13929
13917
|
}
|
|
13930
13918
|
}
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13919
|
+
const steps = /* @__PURE__ */ new Map();
|
|
13920
|
+
for (const call of calls.values()) {
|
|
13921
|
+
if (call.pageId !== void 0) continue;
|
|
13922
|
+
steps.set(call, {
|
|
13923
|
+
title: call.title,
|
|
13924
|
+
...call.error !== void 0 ? { error: call.error } : {}
|
|
13925
|
+
});
|
|
13926
|
+
}
|
|
13927
|
+
for (const call of calls.values()) {
|
|
13928
|
+
if (call.pageId === void 0) continue;
|
|
13929
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13930
|
+
for (let id = call.parent; id !== void 0 && !seen.has(id); id = calls.get(id)?.parent) {
|
|
13931
|
+
seen.add(id);
|
|
13932
|
+
const step = steps.get(calls.get(id));
|
|
13933
|
+
if (step === void 0) continue;
|
|
13934
|
+
if (call.beforeSnapshot !== void 0 && (!step.first || call.startTime < step.first.startTime)) step.first = call;
|
|
13935
|
+
if (call.afterSnapshot !== void 0 && call.endTime !== void 0 && (!step.last || call.endTime > step.last.endTime)) step.last = call;
|
|
13936
|
+
}
|
|
13937
|
+
}
|
|
13938
|
+
const ref = (call, name) => {
|
|
13939
|
+
const viewport = viewports.get(name);
|
|
13940
|
+
return {
|
|
13941
|
+
pageId: call.pageId,
|
|
13942
|
+
name,
|
|
13943
|
+
...viewport ? { viewport } : {}
|
|
13944
|
+
};
|
|
13940
13945
|
};
|
|
13946
|
+
return [...steps.entries()].sort(([a], [b]) => a.startTime - b.startTime).map(([, { first, last, ...step }]) => ({
|
|
13947
|
+
...step,
|
|
13948
|
+
...first ? { before: ref(first, first.beforeSnapshot) } : {},
|
|
13949
|
+
...last ? { after: ref(last, last.afterSnapshot) } : {}
|
|
13950
|
+
}));
|
|
13951
|
+
}
|
|
13952
|
+
/** The joined `.trace` members of an archive: the runner's steps and the browser's calls are separate files. */
|
|
13953
|
+
async function readTraceJsonl(archive) {
|
|
13954
|
+
const entries = await readZip(archive);
|
|
13955
|
+
return entries.names.filter((name) => name.endsWith(".trace")).map((name) => entries.read(name)?.toString("utf8") ?? "").join("\n");
|
|
13941
13956
|
}
|
|
13942
|
-
/** The
|
|
13957
|
+
/** The call's failure message, in whichever shape the trace recorded it. */
|
|
13943
13958
|
function errorOf(event) {
|
|
13944
13959
|
const error = event.error;
|
|
13945
13960
|
if (typeof error === "string") return { error };
|
|
@@ -13954,14 +13969,131 @@ function titleOf$1(event) {
|
|
|
13954
13969
|
if (typeof event.title === "string") return event.title;
|
|
13955
13970
|
return "";
|
|
13956
13971
|
}
|
|
13972
|
+
//#endregion
|
|
13973
|
+
//#region src/targets/playwright/resolve-playwright.ts
|
|
13957
13974
|
/**
|
|
13958
|
-
* The
|
|
13959
|
-
*
|
|
13960
|
-
*
|
|
13961
|
-
*
|
|
13975
|
+
* The consumer's Playwright, not a dependency of ccqa's: its browser and its
|
|
13976
|
+
* trace viewer have to match the version the tests run with.
|
|
13977
|
+
*
|
|
13978
|
+
* Under pnpm's isolation `playwright-core` may only be reachable through
|
|
13979
|
+
* `@playwright/test` → `playwright`, so each link is resolved from the one
|
|
13980
|
+
* before, skipping links a project does not have. `dirs` are tried in order —
|
|
13981
|
+
* nearest first, since in a monorepo only the e2e package may have Playwright.
|
|
13962
13982
|
*/
|
|
13963
|
-
function
|
|
13964
|
-
|
|
13983
|
+
async function loadPlaywright(dirs) {
|
|
13984
|
+
for (const dir of dirs) {
|
|
13985
|
+
const coreDir = resolveCoreDir(dir);
|
|
13986
|
+
if (coreDir === null) continue;
|
|
13987
|
+
const mod = await import(pathToFileURL(createRequire(join(coreDir, "package.json")).resolve("playwright-core")).href);
|
|
13988
|
+
const chromium = mod.chromium ?? mod.default?.chromium;
|
|
13989
|
+
if (chromium !== void 0) return {
|
|
13990
|
+
coreDir,
|
|
13991
|
+
chromium
|
|
13992
|
+
};
|
|
13993
|
+
}
|
|
13994
|
+
throw new Error(`Playwright is not installed in ${dirs.join(" or ")}`);
|
|
13995
|
+
}
|
|
13996
|
+
function resolveCoreDir(dir) {
|
|
13997
|
+
let from = dir;
|
|
13998
|
+
for (const name of [
|
|
13999
|
+
"@playwright/test",
|
|
14000
|
+
"playwright",
|
|
14001
|
+
"playwright-core"
|
|
14002
|
+
]) try {
|
|
14003
|
+
from = dirname(createRequire(join(from, "package.json")).resolve(`${name}/package.json`));
|
|
14004
|
+
if (name === "playwright-core") return from;
|
|
14005
|
+
} catch {}
|
|
14006
|
+
return null;
|
|
14007
|
+
}
|
|
14008
|
+
//#endregion
|
|
14009
|
+
//#region src/targets/playwright/trace-snapshot.ts
|
|
14010
|
+
/** A snapshot that never settles must not hold the run's report hostage. */
|
|
14011
|
+
const RENDER_TIMEOUT_MS = 15e3;
|
|
14012
|
+
const LAUNCH_TIMEOUT_MS = 3e4;
|
|
14013
|
+
const TRACE_PATH = "trace.zip";
|
|
14014
|
+
const CONTENT_TYPES = {
|
|
14015
|
+
".html": "text/html; charset=utf-8",
|
|
14016
|
+
".js": "text/javascript",
|
|
14017
|
+
".css": "text/css",
|
|
14018
|
+
".svg": "image/svg+xml",
|
|
14019
|
+
".ttf": "font/ttf",
|
|
14020
|
+
".zip": "application/zip"
|
|
14021
|
+
};
|
|
14022
|
+
/**
|
|
14023
|
+
* A renderer over one trace archive, using the first Playwright `dirs`
|
|
14024
|
+
* resolves. Throws when that Playwright, its viewer, or its Chromium is missing.
|
|
14025
|
+
*/
|
|
14026
|
+
async function openSnapshotRenderer(dirs, archive) {
|
|
14027
|
+
const { coreDir, chromium } = await loadPlaywright(dirs);
|
|
14028
|
+
const viewerDir = join(coreDir, "lib", "vite", "traceViewer");
|
|
14029
|
+
if (!isFile(join(viewerDir, "snapshot.html"))) throw new Error(`the installed Playwright has no trace viewer at ${viewerDir}`);
|
|
14030
|
+
const server = await serve(viewerDir, archive);
|
|
14031
|
+
const base = `http://127.0.0.1:${server.address().port}/`;
|
|
14032
|
+
const browser = await chromium.launch({ timeout: LAUNCH_TIMEOUT_MS }).catch(async (err) => {
|
|
14033
|
+
await closeServer(server);
|
|
14034
|
+
throw err;
|
|
14035
|
+
});
|
|
14036
|
+
const close = async () => {
|
|
14037
|
+
try {
|
|
14038
|
+
await browser.close();
|
|
14039
|
+
} finally {
|
|
14040
|
+
await closeServer(server);
|
|
14041
|
+
}
|
|
14042
|
+
};
|
|
14043
|
+
try {
|
|
14044
|
+
const page = await browser.newPage();
|
|
14045
|
+
page.setDefaultTimeout(RENDER_TIMEOUT_MS);
|
|
14046
|
+
await page.goto(`${base}snapshot.html?trace=${TRACE_PATH}`);
|
|
14047
|
+
await page.waitForFunction("!!navigator.serviceWorker.controller");
|
|
14048
|
+
if (await page.evaluate(`fetch("contexts?trace=${TRACE_PATH}").then((r) => r.ok)`) !== true) throw new Error("the trace viewer could not load the trace");
|
|
14049
|
+
return {
|
|
14050
|
+
async render(snapshot) {
|
|
14051
|
+
if (snapshot.viewport) await page.setViewportSize(snapshot.viewport);
|
|
14052
|
+
const url = `${base}snapshot/${snapshot.pageId}?trace=${TRACE_PATH}&name=${encodeURIComponent(snapshot.name)}`;
|
|
14053
|
+
await page.goto(`${base}snapshot.html?trace=${TRACE_PATH}&r=${encodeURIComponent(url)}`);
|
|
14054
|
+
const frame = await (await page.waitForSelector("iframe")).contentFrame();
|
|
14055
|
+
if (frame === null) throw new Error("the trace viewer showed no snapshot frame");
|
|
14056
|
+
await frame.waitForURL(/\/snapshot\//, { waitUntil: "load" });
|
|
14057
|
+
await frame.waitForFunction("document.fonts.status === 'loaded' && Array.from(document.images).every((i) => i.complete)");
|
|
14058
|
+
return await frame.evaluate("!document.body || (document.body.childElementCount === 0 && document.body.textContent.trim() === '')") === false ? page.screenshot({ type: "jpeg" }) : null;
|
|
14059
|
+
},
|
|
14060
|
+
close
|
|
14061
|
+
};
|
|
14062
|
+
} catch (err) {
|
|
14063
|
+
await close().catch(() => {});
|
|
14064
|
+
throw err;
|
|
14065
|
+
}
|
|
14066
|
+
}
|
|
14067
|
+
/** The viewer's files and the one archive, on loopback only. */
|
|
14068
|
+
async function serve(viewerDir, archive) {
|
|
14069
|
+
const root = resolve(viewerDir);
|
|
14070
|
+
const server = createServer((req, res) => {
|
|
14071
|
+
const path = new URL(req.url ?? "/", "http://127.0.0.1").pathname;
|
|
14072
|
+
const file = path === `/${TRACE_PATH}` ? archive : resolve(root, `.${path}`);
|
|
14073
|
+
if (file !== archive && !file.startsWith(root + sep) || !isFile(file)) {
|
|
14074
|
+
res.statusCode = 404;
|
|
14075
|
+
res.end();
|
|
14076
|
+
return;
|
|
14077
|
+
}
|
|
14078
|
+
res.setHeader("Content-Type", CONTENT_TYPES[extname(file)] ?? "application/octet-stream");
|
|
14079
|
+
createReadStream(file).on("error", () => res.destroy()).pipe(res);
|
|
14080
|
+
});
|
|
14081
|
+
await new Promise((done, fail) => {
|
|
14082
|
+
server.once("error", fail);
|
|
14083
|
+
server.listen(0, "127.0.0.1", done);
|
|
14084
|
+
});
|
|
14085
|
+
return server;
|
|
14086
|
+
}
|
|
14087
|
+
function isFile(path) {
|
|
14088
|
+
try {
|
|
14089
|
+
return statSync(path).isFile();
|
|
14090
|
+
} catch {
|
|
14091
|
+
return false;
|
|
14092
|
+
}
|
|
14093
|
+
}
|
|
14094
|
+
function closeServer(server) {
|
|
14095
|
+
server.closeAllConnections();
|
|
14096
|
+
return new Promise((done) => server.close(() => done()));
|
|
13965
14097
|
}
|
|
13966
14098
|
//#endregion
|
|
13967
14099
|
//#region src/targets/playwright/trace-capture.ts
|
|
@@ -13972,15 +14104,11 @@ function frameAt(frames, time) {
|
|
|
13972
14104
|
* `test.step` blocks and there is no capture call to place a screenshot at
|
|
13973
14105
|
* either boundary. So the screenshots are not taken during the run at all —
|
|
13974
14106
|
* ccqa asks Playwright for a trace on the invocations it owns, and afterwards
|
|
13975
|
-
*
|
|
13976
|
-
* the consumer's repository changes, and nothing ccqa does here can
|
|
13977
|
-
* passing test red: the whole path runs after the command has exited,
|
|
13978
|
-
* trace it cannot read costs the report its pictures and says
|
|
13979
|
-
*
|
|
13980
|
-
* The frames are the trace's own screencast, which Playwright records
|
|
13981
|
-
* downscaled — they are the filmstrip a reviewer already sees in the trace
|
|
13982
|
-
* viewer, not `page.screenshot()` output. That is the price of taking the
|
|
13983
|
-
* capture code out of the committed file.
|
|
14107
|
+
* renders the DOM snapshots the trace took around each step's browser calls.
|
|
14108
|
+
* Nothing in the consumer's repository changes, and nothing ccqa does here can
|
|
14109
|
+
* turn a passing test red: the whole path runs after the command has exited,
|
|
14110
|
+
* and a trace it cannot read or render costs the report its pictures and says
|
|
14111
|
+
* so.
|
|
13984
14112
|
*/
|
|
13985
14113
|
/** Shell characters that would hand an appended flag to a different program. */
|
|
13986
14114
|
const SHELL_OPERATORS = /[|;&<>`$]/;
|
|
@@ -14022,82 +14150,124 @@ function amendForTrace(command, outputDir) {
|
|
|
14022
14150
|
const flags = [/(^|\s)--trace[=\s]/.test(command) ? "" : "--trace=on", directsOutput ? "" : `--output=${quoteForShell(outputDir)}`].filter(Boolean);
|
|
14023
14151
|
return { command: flags.length > 0 ? `${command} ${flags.join(" ")}` : command };
|
|
14024
14152
|
}
|
|
14153
|
+
/** Rendering one archive stops here, so a slow viewer cannot stall the report. */
|
|
14154
|
+
const ARCHIVE_BUDGET_MS = 6e4;
|
|
14025
14155
|
/**
|
|
14026
|
-
* Make sure `evidenceDir` holds the spec's per-step screenshots,
|
|
14027
|
-
* trace the run left in `artifactsDir` when nothing else wrote them.
|
|
14028
|
-
* null when the directory has evidence in it, and otherwise the reason
|
|
14029
|
-
* is nothing to show.
|
|
14156
|
+
* Make sure `evidenceDir` holds the spec's per-step screenshots, rendering them
|
|
14157
|
+
* from the trace the run left in `artifactsDir` when nothing else wrote them.
|
|
14158
|
+
* Returns null when the directory has evidence in it, and otherwise the reason
|
|
14159
|
+
* there is nothing to show. A step that gets no picture is reported through
|
|
14160
|
+
* `warn` and costs only its own row.
|
|
14030
14161
|
*
|
|
14031
14162
|
* A spec generated before the capture calls left the committed file writes its
|
|
14032
|
-
* own
|
|
14033
|
-
*
|
|
14034
|
-
* Every step of every trace found is written, not just the first archive's: a
|
|
14035
|
-
* retried test leaves one archive per attempt, and the later one overwrites
|
|
14036
|
-
* the earlier, which is the attempt the row reports.
|
|
14163
|
+
* own screenshots as it runs; those are the test's own and are left alone.
|
|
14037
14164
|
*/
|
|
14038
14165
|
async function captureStepEvidence(args) {
|
|
14039
14166
|
if ((await readdir(args.evidenceDir).catch(() => [])).length > 0) return null;
|
|
14040
|
-
const archives = (await walkFiles$1(args.artifactsDir)).filter(isTraceArchive)
|
|
14167
|
+
const archives = lastAttempts((await walkFiles$1(args.artifactsDir)).filter(isTraceArchive)).map((rel) => join(args.artifactsDir, ...rel.split("/")));
|
|
14041
14168
|
if (archives.length === 0) return "the run left no Playwright trace, so there are no per-step screenshots to read — the generated test's `test.step` blocks are what ccqa reads them from";
|
|
14042
14169
|
let written = 0;
|
|
14043
|
-
let
|
|
14044
|
-
|
|
14170
|
+
let named = 0;
|
|
14171
|
+
let firstError;
|
|
14045
14172
|
for (const archive of archives) try {
|
|
14046
|
-
const archived = await writeArchiveEvidence(archive, args
|
|
14173
|
+
const archived = await writeArchiveEvidence(archive, args);
|
|
14047
14174
|
written += archived.written;
|
|
14048
|
-
|
|
14175
|
+
named += archived.named;
|
|
14176
|
+
firstError ??= archived.firstError;
|
|
14049
14177
|
} catch (err) {
|
|
14050
|
-
|
|
14178
|
+
firstError ??= errMessage(err);
|
|
14051
14179
|
}
|
|
14052
14180
|
if (written > 0) return null;
|
|
14053
|
-
if (
|
|
14054
|
-
if (
|
|
14055
|
-
return "the run's Playwright trace holds no
|
|
14181
|
+
if (firstError !== void 0) return `ccqa could not render the trace's snapshots: ${firstError}`;
|
|
14182
|
+
if (named === 0) return "the run's Playwright trace holds no step the case names — a rewrite pass may have reshaped the `test.step` titles the draft wrote; re-run `ccqa generate` for this spec";
|
|
14183
|
+
return "the run's Playwright trace holds no DOM snapshot for any step — Playwright records them only while the trace's `snapshots` option is on (`--trace=on` asks for it; a `trace` option in the project's config can turn it off)";
|
|
14056
14184
|
}
|
|
14057
|
-
/**
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14061
|
-
|
|
14185
|
+
/**
|
|
14186
|
+
* Each test's last attempt: a retry leaves `<dir>-retry<n>` beside the first
|
|
14187
|
+
* attempt's `<dir>`, and the attempt the row reports is the last one.
|
|
14188
|
+
*/
|
|
14189
|
+
function lastAttempts(archives) {
|
|
14190
|
+
const last = /* @__PURE__ */ new Map();
|
|
14191
|
+
for (const archive of archives) {
|
|
14192
|
+
const match = /^(.*)-retry(\d+)$/.exec(dirname(archive));
|
|
14193
|
+
const test = match ? match[1] : dirname(archive);
|
|
14194
|
+
const attempt = match ? Number(match[2]) : 0;
|
|
14195
|
+
if ((last.get(test)?.attempt ?? -1) < attempt) last.set(test, {
|
|
14196
|
+
archive,
|
|
14197
|
+
attempt
|
|
14198
|
+
});
|
|
14199
|
+
}
|
|
14200
|
+
return [...last.values()].map((v) => v.archive).sort();
|
|
14201
|
+
}
|
|
14202
|
+
/** One archive's steps, written as evidence; how many steps the case named; the first render error. */
|
|
14203
|
+
async function writeArchiveEvidence(archive, args) {
|
|
14204
|
+
const steps = parseTraceSteps(await readTraceJsonl(archive)).flatMap((step) => {
|
|
14205
|
+
const label = parseStepLabel(step.title);
|
|
14206
|
+
return label === null ? [] : [{
|
|
14207
|
+
...step,
|
|
14208
|
+
label
|
|
14209
|
+
}];
|
|
14210
|
+
});
|
|
14211
|
+
if (!steps.some((step) => step.after !== void 0)) return {
|
|
14062
14212
|
written: 0,
|
|
14063
|
-
|
|
14213
|
+
named: steps.length
|
|
14064
14214
|
};
|
|
14065
|
-
await
|
|
14215
|
+
const renderer = await (args.openRenderer ?? openSnapshotRenderer)(args.playwrightFrom, archive);
|
|
14216
|
+
const deadline = Date.now() + ARCHIVE_BUDGET_MS;
|
|
14066
14217
|
let written = 0;
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
14218
|
+
let firstError;
|
|
14219
|
+
const render = async (snapshot, stepId, end) => {
|
|
14220
|
+
let failure;
|
|
14221
|
+
try {
|
|
14222
|
+
const image = await renderer.render(snapshot);
|
|
14223
|
+
if (image !== null || end === "before") return image;
|
|
14224
|
+
failure = "snapshot rendered blank";
|
|
14225
|
+
} catch (err) {
|
|
14226
|
+
failure = errMessage(err);
|
|
14227
|
+
}
|
|
14228
|
+
firstError ??= failure;
|
|
14229
|
+
args.warn(`${stepId}: no ${end} screenshot — rendering ${snapshot.name} failed (${failure})`);
|
|
14230
|
+
return null;
|
|
14231
|
+
};
|
|
14232
|
+
try {
|
|
14233
|
+
await mkdir(args.evidenceDir, { recursive: true });
|
|
14234
|
+
for (const [index, step] of steps.entries()) {
|
|
14235
|
+
if (Date.now() > deadline) {
|
|
14236
|
+
args.warn(`stopped rendering after ${ARCHIVE_BUDGET_MS / 1e3}s — ${steps.length - index} step(s) left without screenshots`);
|
|
14237
|
+
break;
|
|
14238
|
+
}
|
|
14239
|
+
const { stepId, source } = step.label;
|
|
14240
|
+
if (step.after === void 0) {
|
|
14241
|
+
args.warn(`${stepId}: no screenshot — the trace holds no DOM snapshot of a browser call in this step`);
|
|
14242
|
+
continue;
|
|
14243
|
+
}
|
|
14244
|
+
const stem = sanitizeStepId(stepId);
|
|
14245
|
+
const after = await render(step.after, stepId, "after");
|
|
14246
|
+
if (after === null) continue;
|
|
14247
|
+
await writeFile(join(args.evidenceDir, `${stem}.jpeg`), after);
|
|
14248
|
+
const before = step.before ? await render(step.before, stepId, "before") : null;
|
|
14249
|
+
if (before !== null) await writeFile(join(args.evidenceDir, `${stem}.before.jpeg`), before);
|
|
14250
|
+
await writeFile(join(args.evidenceDir, `${stem}.json`), `${JSON.stringify({
|
|
14251
|
+
stepId,
|
|
14252
|
+
source,
|
|
14253
|
+
pngFile: `${stem}.jpeg`,
|
|
14254
|
+
...before !== null ? { beforePngFile: `${stem}.before.jpeg` } : {},
|
|
14255
|
+
...step.error !== void 0 ? { failureSummary: step.error } : {},
|
|
14256
|
+
url: null,
|
|
14257
|
+
title: null,
|
|
14258
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14259
|
+
}, null, 2)}\n`, "utf8");
|
|
14260
|
+
written += 1;
|
|
14261
|
+
}
|
|
14262
|
+
} finally {
|
|
14263
|
+
await renderer.close().catch((err) => args.warn(`could not close the trace viewer (${errMessage(err)})`));
|
|
14085
14264
|
}
|
|
14086
14265
|
return {
|
|
14087
14266
|
written,
|
|
14088
|
-
|
|
14267
|
+
named: steps.length,
|
|
14268
|
+
...firstError !== void 0 ? { firstError } : {}
|
|
14089
14269
|
};
|
|
14090
14270
|
}
|
|
14091
|
-
/** The frame on screen at `time`, written under `stem`. Null when there is none. */
|
|
14092
|
-
async function writeFrame(entries, frames, time, evidenceDir, stem) {
|
|
14093
|
-
const frame = frameAt(frames, time);
|
|
14094
|
-
if (frame === null) return null;
|
|
14095
|
-
const data = entries.read(`resources/${frame.sha1}`) ?? entries.read(`resources/${frame.sha1}.jpeg`);
|
|
14096
|
-
if (data === void 0) return null;
|
|
14097
|
-
const file = `${stem}.jpeg`;
|
|
14098
|
-
await writeFile(join(evidenceDir, file), data);
|
|
14099
|
-
return file;
|
|
14100
|
-
}
|
|
14101
14271
|
//#endregion
|
|
14102
14272
|
//#region src/targets/run-command-runner.ts
|
|
14103
14273
|
/**
|
|
@@ -14292,6 +14462,8 @@ async function runOneSpec(ref, opts) {
|
|
|
14292
14462
|
evidence,
|
|
14293
14463
|
artifactsDir,
|
|
14294
14464
|
testCase,
|
|
14465
|
+
caseKey: `${featureName}/${specName}`,
|
|
14466
|
+
playwrightFrom: [dirname(resolve(opts.cwd, testFile)), opts.cwd],
|
|
14295
14467
|
...traceUnavailable !== void 0 ? { traceUnavailable } : {}
|
|
14296
14468
|
});
|
|
14297
14469
|
if (outcome.exitCode === 0) return {
|
|
@@ -14346,7 +14518,9 @@ async function loadStepEvidence(args) {
|
|
|
14346
14518
|
const evidenceDir = args.evidence.dir;
|
|
14347
14519
|
const reason = args.traceUnavailable ?? await captureStepEvidence({
|
|
14348
14520
|
artifactsDir: args.artifactsDir,
|
|
14349
|
-
evidenceDir
|
|
14521
|
+
evidenceDir,
|
|
14522
|
+
playwrightFrom: args.playwrightFrom,
|
|
14523
|
+
warn: (message) => warn(`${args.caseKey}: ${message}`)
|
|
14350
14524
|
});
|
|
14351
14525
|
const descriptions = stepCaptions(args.testCase);
|
|
14352
14526
|
const evidence = await loadEvidenceForSpec(evidenceDir, opts.reportDir, descriptions);
|
|
@@ -14842,7 +15016,9 @@ async function verifyRun(p, state, runCommand, attempt, captures) {
|
|
|
14842
15016
|
if (evidenceDir && result.exitCode === 0) {
|
|
14843
15017
|
const unavailable = traceUnavailable ?? await captureStepEvidence({
|
|
14844
15018
|
artifactsDir,
|
|
14845
|
-
evidenceDir
|
|
15019
|
+
evidenceDir,
|
|
15020
|
+
playwrightFrom: [...testFiles.map((f) => dirname(join(p.ctx.cwd, f))), p.ctx.cwd],
|
|
15021
|
+
warn: (message) => warn(`${p.ctx.ref.id}: ${message}`)
|
|
14846
15022
|
});
|
|
14847
15023
|
if (unavailable) warn(unavailable);
|
|
14848
15024
|
}
|
|
@@ -15683,7 +15859,7 @@ const CONFIG_NAMES = [
|
|
|
15683
15859
|
];
|
|
15684
15860
|
async function acquirePlaywrightBrowser(ctx) {
|
|
15685
15861
|
await sweepStaleWrappersOnce(ctx.cwd);
|
|
15686
|
-
const chromium = await
|
|
15862
|
+
const { chromium } = await loadPlaywright([ctx.cwd]);
|
|
15687
15863
|
const port = await freePort();
|
|
15688
15864
|
const server = await chromium.launchServer({ args: [`--remote-debugging-port=${port}`] });
|
|
15689
15865
|
let wrapperPath;
|
|
@@ -15741,25 +15917,6 @@ async function sweepStaleWrappers(cwd) {
|
|
|
15741
15917
|
function shellQuote(s) {
|
|
15742
15918
|
return `'${s.replaceAll("'", `'\\''`)}'`;
|
|
15743
15919
|
}
|
|
15744
|
-
/**
|
|
15745
|
-
* The consumer's Playwright, not a dependency of ccqa's: their tests speak
|
|
15746
|
-
* their version's protocol, and the server has to be the same animal. Their
|
|
15747
|
-
* `runCommand` runs `playwright test`, so the package is present — but under
|
|
15748
|
-
* pnpm's isolation it may only be resolvable through `@playwright/test`.
|
|
15749
|
-
*/
|
|
15750
|
-
async function resolveChromium(cwd) {
|
|
15751
|
-
const fromProject = createRequire(join(cwd, "package.json"));
|
|
15752
|
-
const origins = [];
|
|
15753
|
-
try {
|
|
15754
|
-
origins.push(fromProject.resolve("@playwright/test/package.json"));
|
|
15755
|
-
} catch {}
|
|
15756
|
-
for (const name of ["playwright", "playwright-core"]) for (const origin of [null, ...origins]) try {
|
|
15757
|
-
const mod = await import(pathToFileURL((origin === null ? fromProject : createRequire(origin)).resolve(name)).href);
|
|
15758
|
-
const chromium = mod.chromium ?? mod.default?.chromium;
|
|
15759
|
-
if (chromium !== void 0) return chromium;
|
|
15760
|
-
} catch {}
|
|
15761
|
-
throw new Error(`could not resolve Playwright from ${cwd} — the playwright target's --coverage launches the browser with the project's own Playwright, which must be installed`);
|
|
15762
|
-
}
|
|
15763
15920
|
async function writeWrapperConfig(ctx) {
|
|
15764
15921
|
const existing = CONFIG_NAMES.find((name) => existsSync(join(ctx.cwd, name)));
|
|
15765
15922
|
const wrapperName = `ccqa-coverage.${slug(ctx.featureName)}--${slug(ctx.specName)}.playwright.config.ts`;
|
|
@@ -27331,7 +27488,7 @@ const evidenceCommand = addLanguageOption(new Command("evidence").argument("<cas
|
|
|
27331
27488
|
anchors = await findSourceAnchors(sourceNeedles([...recording.actions, ...recording.cleanup ?? []]), roots);
|
|
27332
27489
|
}
|
|
27333
27490
|
const out = resolve(cwd, opts.out ?? join(testCase.ref.dir, "evidence.md"));
|
|
27334
|
-
|
|
27491
|
+
const markdown = renderEvidence({
|
|
27335
27492
|
testCase,
|
|
27336
27493
|
recording,
|
|
27337
27494
|
test: {
|
|
@@ -27344,7 +27501,9 @@ const evidenceCommand = addLanguageOption(new Command("evidence").argument("<cas
|
|
|
27344
27501
|
...resolved.targetConfig.allowExpectInCleanup ? {} : { cleanupUnchecked: testCase.cleanupExpectations },
|
|
27345
27502
|
...review ? { review } : {},
|
|
27346
27503
|
...anchors ? { anchors } : {}
|
|
27347
|
-
})
|
|
27504
|
+
});
|
|
27505
|
+
await mkdir(dirname(out), { recursive: true });
|
|
27506
|
+
await writeFile(out, scrubEnvValues(markdown, buildProseEnvScrubMap([], [])), "utf8");
|
|
27348
27507
|
process.stdout.write(`${relative(cwd, out) || out}\n`);
|
|
27349
27508
|
hint("paste it into the pull request, or attach it — ccqa writes the table, not the body");
|
|
27350
27509
|
}));
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Several producers write the `<id>.png` + `<id>.json` pairs —
|
|
7
7
|
* `abStepEvidence()` / `captureFailureEvidence()` in `test-helpers.ts`
|
|
8
|
-
* (agent-browser replays), `targets/playwright/trace-capture.ts` (
|
|
9
|
-
*
|
|
8
|
+
* (agent-browser replays), `targets/playwright/trace-capture.ts` (snapshots
|
|
9
|
+
* rendered from a run's Playwright trace), and `ccqaStepBefore`/`ccqaStepAfter` in
|
|
10
10
|
* `step-evidence.ts` for tests generated before the capture calls left the
|
|
11
11
|
* committed file — and one consumer reads them back (`loadEvidenceForSpec` in
|
|
12
12
|
* `report/evidence.ts`). They agree only on the contract here, so it is kept
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Several producers write the `<id>.png` + `<id>.json` pairs —
|
|
7
7
|
* `abStepEvidence()` / `captureFailureEvidence()` in `test-helpers.ts`
|
|
8
|
-
* (agent-browser replays), `targets/playwright/trace-capture.ts` (
|
|
9
|
-
*
|
|
8
|
+
* (agent-browser replays), `targets/playwright/trace-capture.ts` (snapshots
|
|
9
|
+
* rendered from a run's Playwright trace), and `ccqaStepBefore`/`ccqaStepAfter` in
|
|
10
10
|
* `step-evidence.ts` for tests generated before the capture calls left the
|
|
11
11
|
* committed file — and one consumer reads them back (`loadEvidenceForSpec` in
|
|
12
12
|
* `report/evidence.ts`). They agree only on the contract here, so it is kept
|
|
@@ -35,9 +35,9 @@ declare const RunSchema: z.ZodObject<{
|
|
|
35
35
|
running: "running";
|
|
36
36
|
}>;
|
|
37
37
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
38
|
+
record: "record";
|
|
38
39
|
run: "run";
|
|
39
40
|
drift: "drift";
|
|
40
|
-
record: "record";
|
|
41
41
|
}>>;
|
|
42
42
|
drift: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
43
43
|
specs: z.ZodNumber;
|
|
@@ -652,8 +652,8 @@ declare const ReportSpecResultSchema: z.ZodObject<{
|
|
|
652
652
|
title: z.ZodNullable<z.ZodString>;
|
|
653
653
|
target: z.ZodOptional<z.ZodString>;
|
|
654
654
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
655
|
-
deterministic: "deterministic";
|
|
656
655
|
live: "live";
|
|
656
|
+
deterministic: "deterministic";
|
|
657
657
|
}>>;
|
|
658
658
|
status: z.ZodEnum<{
|
|
659
659
|
passed: "passed";
|
|
@@ -831,9 +831,9 @@ type ReportSpecResult = z.infer<typeof ReportSpecResultSchema>;
|
|
|
831
831
|
declare const RunReportDataSchema: z.ZodObject<{
|
|
832
832
|
schemaVersion: z.ZodLiteral<1>;
|
|
833
833
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
834
|
+
record: "record";
|
|
834
835
|
run: "run";
|
|
835
836
|
drift: "drift";
|
|
836
|
-
record: "record";
|
|
837
837
|
}>>;
|
|
838
838
|
createdAt: z.ZodString;
|
|
839
839
|
runId: z.ZodNullable<z.ZodString>;
|
|
@@ -874,8 +874,8 @@ declare const RunReportDataSchema: z.ZodObject<{
|
|
|
874
874
|
title: z.ZodNullable<z.ZodString>;
|
|
875
875
|
target: z.ZodOptional<z.ZodString>;
|
|
876
876
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
877
|
-
deterministic: "deterministic";
|
|
878
877
|
live: "live";
|
|
878
|
+
deterministic: "deterministic";
|
|
879
879
|
}>>;
|
|
880
880
|
status: z.ZodEnum<{
|
|
881
881
|
passed: "passed";
|
|
@@ -35,9 +35,9 @@ declare const RunSchema: z.ZodObject<{
|
|
|
35
35
|
running: "running";
|
|
36
36
|
}>;
|
|
37
37
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
38
|
+
record: "record";
|
|
38
39
|
run: "run";
|
|
39
40
|
drift: "drift";
|
|
40
|
-
record: "record";
|
|
41
41
|
}>>;
|
|
42
42
|
drift: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
43
43
|
specs: z.ZodNumber;
|
|
@@ -652,8 +652,8 @@ declare const ReportSpecResultSchema: z.ZodObject<{
|
|
|
652
652
|
title: z.ZodNullable<z.ZodString>;
|
|
653
653
|
target: z.ZodOptional<z.ZodString>;
|
|
654
654
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
655
|
-
deterministic: "deterministic";
|
|
656
655
|
live: "live";
|
|
656
|
+
deterministic: "deterministic";
|
|
657
657
|
}>>;
|
|
658
658
|
status: z.ZodEnum<{
|
|
659
659
|
passed: "passed";
|
|
@@ -831,9 +831,9 @@ type ReportSpecResult = z.infer<typeof ReportSpecResultSchema>;
|
|
|
831
831
|
declare const RunReportDataSchema: z.ZodObject<{
|
|
832
832
|
schemaVersion: z.ZodLiteral<1>;
|
|
833
833
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
834
|
+
record: "record";
|
|
834
835
|
run: "run";
|
|
835
836
|
drift: "drift";
|
|
836
|
-
record: "record";
|
|
837
837
|
}>>;
|
|
838
838
|
createdAt: z.ZodString;
|
|
839
839
|
runId: z.ZodNullable<z.ZodString>;
|
|
@@ -874,8 +874,8 @@ declare const RunReportDataSchema: z.ZodObject<{
|
|
|
874
874
|
title: z.ZodNullable<z.ZodString>;
|
|
875
875
|
target: z.ZodOptional<z.ZodString>;
|
|
876
876
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
877
|
-
deterministic: "deterministic";
|
|
878
877
|
live: "live";
|
|
878
|
+
deterministic: "deterministic";
|
|
879
879
|
}>>;
|
|
880
880
|
status: z.ZodEnum<{
|
|
881
881
|
passed: "passed";
|
package/dist/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_evidence_constants = require("../evidence-constants-
|
|
2
|
+
const require_evidence_constants = require("../evidence-constants-BNe7Q305.cjs");
|
|
3
3
|
let node_fs = require("node:fs");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
//#region src/runtime/step-evidence.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as sanitizeStepId, t as EVIDENCE_DIR_ENV } from "../evidence-constants-
|
|
1
|
+
import { i as sanitizeStepId, t as EVIDENCE_DIR_ENV } from "../evidence-constants-WMpQPI8P.mjs";
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
//#region src/runtime/step-evidence.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_evidence_constants = require("../evidence-constants-
|
|
2
|
+
const require_evidence_constants = require("../evidence-constants-BNe7Q305.cjs");
|
|
3
3
|
let node_fs = require("node:fs");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
let node_child_process = require("node:child_process");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as sanitizeStepId, n as FAILURE_SOURCE, r as FAILURE_STEP_ID, t as EVIDENCE_DIR_ENV } from "../evidence-constants-
|
|
1
|
+
import { i as sanitizeStepId, n as FAILURE_SOURCE, r as FAILURE_STEP_ID, t as EVIDENCE_DIR_ENV } from "../evidence-constants-WMpQPI8P.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|