doc-detective 4.32.0 → 4.34.0
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/common/src/schemas/schemas.json +2688 -126
- package/dist/common/src/types/generated/record_v3.d.ts +48 -2
- package/dist/common/src/types/generated/record_v3.d.ts.map +1 -1
- package/dist/common/src/types/generated/step_v3.d.ts +48 -2
- package/dist/common/src/types/generated/step_v3.d.ts.map +1 -1
- package/dist/common/src/types/generated/test_v3.d.ts +96 -4
- package/dist/common/src/types/generated/test_v3.d.ts.map +1 -1
- package/dist/core/tests/ffmpegRecorder.d.ts +12 -1
- package/dist/core/tests/ffmpegRecorder.d.ts.map +1 -1
- package/dist/core/tests/ffmpegRecorder.js +141 -3
- package/dist/core/tests/ffmpegRecorder.js.map +1 -1
- package/dist/core/tests/recordingCheckpoints.d.ts +76 -0
- package/dist/core/tests/recordingCheckpoints.d.ts.map +1 -0
- package/dist/core/tests/recordingCheckpoints.js +335 -0
- package/dist/core/tests/recordingCheckpoints.js.map +1 -0
- package/dist/core/tests/saveScreenshot.d.ts +5 -1
- package/dist/core/tests/saveScreenshot.d.ts.map +1 -1
- package/dist/core/tests/saveScreenshot.js +46 -12
- package/dist/core/tests/saveScreenshot.js.map +1 -1
- package/dist/core/tests/startRecording.d.ts.map +1 -1
- package/dist/core/tests/startRecording.js +26 -10
- package/dist/core/tests/startRecording.js.map +1 -1
- package/dist/core/tests/stopRecording.d.ts.map +1 -1
- package/dist/core/tests/stopRecording.js +381 -15
- package/dist/core/tests/stopRecording.js.map +1 -1
- package/dist/core/tests.d.ts.map +1 -1
- package/dist/core/tests.js +54 -37
- package/dist/core/tests.js.map +1 -1
- package/dist/hints/context.d.ts +1 -0
- package/dist/hints/context.d.ts.map +1 -1
- package/dist/hints/context.js +9 -0
- package/dist/hints/context.js.map +1 -1
- package/dist/hints/hints.d.ts.map +1 -1
- package/dist/hints/hints.js +15 -0
- package/dist/hints/hints.js.map +1 -1
- package/dist/hints/types.d.ts +8 -0
- package/dist/hints/types.d.ts.map +1 -1
- package/dist/index.cjs +3464 -325
- package/package.json +1 -1
package/dist/core/tests.js
CHANGED
|
@@ -24,6 +24,7 @@ import { typeKeys } from "./tests/typeKeys.js";
|
|
|
24
24
|
import { swipeSurface } from "./tests/swipe.js";
|
|
25
25
|
import { wait } from "./tests/wait.js";
|
|
26
26
|
import { saveScreenshot } from "./tests/saveScreenshot.js";
|
|
27
|
+
import { capPathSegment, stepArtifactFileName, resolveCheckpointsConfig, captureRecordingCheckpoints, } from "./tests/recordingCheckpoints.js";
|
|
27
28
|
import { startRecording } from "./tests/startRecording.js";
|
|
28
29
|
import { stopRecording } from "./tests/stopRecording.js";
|
|
29
30
|
import { browserCaptureTitle, browserDownloadDir, coerceRecordContextBrowser, jobIsFfmpegRecording, computeEffectiveConcurrency, jobExclusiveResources, checkSystemBinary, xvfbDisplay, startXvfb, XVFB_SCREEN_SIZE, isRecordingActive, recordStepName, detectRecordingNameConflict, getFfmpegPath, ffmpegPathEnv, } from "./tests/ffmpegRecorder.js";
|
|
@@ -50,7 +51,7 @@ import { dragAndDropElement } from "./tests/dragAndDrop.js";
|
|
|
50
51
|
import { createSessionRegistry, registerSession, activeDriver, sweepSessions, } from "./tests/browserSessions.js";
|
|
51
52
|
import path from "node:path";
|
|
52
53
|
import { spawn } from "node:child_process";
|
|
53
|
-
import { randomUUID
|
|
54
|
+
import { randomUUID } from "node:crypto";
|
|
54
55
|
import { setAppiumHome } from "./appium.js";
|
|
55
56
|
import { contentHash } from "../common/src/detectTests.js";
|
|
56
57
|
import { resolveExpression } from "./expressions.js";
|
|
@@ -2908,28 +2909,6 @@ function buildAutoRecordStep({ config, spec, test, context, }) {
|
|
|
2908
2909
|
__autoRecord: true,
|
|
2909
2910
|
};
|
|
2910
2911
|
}
|
|
2911
|
-
// Directory/file segments built from IDs are capped so deeply nested doc
|
|
2912
|
-
// trees can't push the full path past Windows' MAX_PATH. The default cap is
|
|
2913
|
-
// 32: the REST artifact tree nests several id segments
|
|
2914
|
-
// (specs/<id>/tests/<id>/contexts/<id>/…), so a larger default could exceed
|
|
2915
|
-
// MAX_PATH on Windows.
|
|
2916
|
-
//
|
|
2917
|
-
// Plain tail truncation alone is unsafe: two distinct ids that share the same
|
|
2918
|
-
// trailing `max` characters (e.g. mirror directory trees that differ only in a
|
|
2919
|
-
// long prefix) would collapse into the same path segment, so one context's
|
|
2920
|
-
// screenshots/recording could overwrite another's and the reported relative
|
|
2921
|
-
// path would resolve to the wrong artifact. When a segment exceeds the cap,
|
|
2922
|
-
// prepend a short deterministic hash of the *full* segment so distinct ids stay
|
|
2923
|
-
// distinct, and keep the trailing chars (where generated ids carry their
|
|
2924
|
-
// content hash) for human correlation. Deterministic — the same id maps to the
|
|
2925
|
-
// same segment every run, preserving run-over-run comparison.
|
|
2926
|
-
function capPathSegment(segment, max = 32) {
|
|
2927
|
-
if (segment.length <= max)
|
|
2928
|
-
return segment;
|
|
2929
|
-
const hash = createHash("sha1").update(segment).digest("hex").slice(0, 8);
|
|
2930
|
-
const tail = segment.slice(segment.length - (max - hash.length - 1));
|
|
2931
|
-
return `${hash}-${tail}`;
|
|
2932
|
-
}
|
|
2933
2912
|
// Capture a post-step screenshot for `autoScreenshot` runs. The relative
|
|
2934
2913
|
// path follows the REST resource tree — stable IDs (spec/test/context) as
|
|
2935
2914
|
// nested collections plus the step's order, action, and ID (e.g.
|
|
@@ -2940,21 +2919,14 @@ function capPathSegment(segment, max = 32) {
|
|
|
2940
2919
|
// missed capture must not fail the step it documents.
|
|
2941
2920
|
async function captureAutoScreenshot({ config, driver, spec, test, context, step, stepIndex, stepCount, }) {
|
|
2942
2921
|
try {
|
|
2943
|
-
const action = driverActions.find((key) => typeof step[key] !== "undefined") || "step";
|
|
2944
|
-
const sanitizedTestId = sanitizeFilesystemName(String(test.testId ?? ""), "test");
|
|
2945
2922
|
const runDir = getRunOutputDir(config);
|
|
2946
|
-
const dir = path.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
// Zero-pad the step ordinal to the width of the context's step count
|
|
2954
|
-
// (min 2), so file listings sort naturally even past 99 steps (100 would
|
|
2955
|
-
// otherwise sort before 11).
|
|
2956
|
-
const pad = Math.max(2, String(stepCount).length);
|
|
2957
|
-
const fileName = `${String(stepIndex + 1).padStart(pad, "0")}-${action}-${stepRef}.png`;
|
|
2923
|
+
const dir = path.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizeFilesystemName(String(test.testId ?? ""), "test")), "contexts", capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context")), "screenshots");
|
|
2924
|
+
const fileName = stepArtifactFileName({
|
|
2925
|
+
step,
|
|
2926
|
+
stepIndex,
|
|
2927
|
+
stepCount,
|
|
2928
|
+
testId: test.testId,
|
|
2929
|
+
});
|
|
2958
2930
|
const screenshotStep = {
|
|
2959
2931
|
stepId: `${step.stepId}_auto`,
|
|
2960
2932
|
description: "Automatic post-step screenshot",
|
|
@@ -3951,6 +3923,35 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
|
|
|
3951
3923
|
if (capturedPath)
|
|
3952
3924
|
stepReport.autoScreenshot = capturedPath;
|
|
3953
3925
|
}
|
|
3926
|
+
// Recording checkpoints (ADR 01075): while a checkpoint-enabled
|
|
3927
|
+
// recording is active, capture a compare-only screenshot per handle
|
|
3928
|
+
// after every step (final attempt only, same placement rationale as
|
|
3929
|
+
// autoScreenshot — retry frames would poison the staged captures).
|
|
3930
|
+
// The record step's own post-step capture is the opening bookend.
|
|
3931
|
+
// The host is the ACTIVE session's driver — the same driver runStep
|
|
3932
|
+
// pushed the handle onto — falling back to the app session's host for
|
|
3933
|
+
// app-only contexts (which skip capture inside the helper: no browser
|
|
3934
|
+
// driver to capture with).
|
|
3935
|
+
// Recordings live per SESSION, so sweep every live session driver the
|
|
3936
|
+
// way stopAllRecordings does — not just the active one. A span started
|
|
3937
|
+
// on a second browser surface keeps its handle on that session's
|
|
3938
|
+
// driver; checking only the active session would silently capture
|
|
3939
|
+
// nothing for it. Each driver is both the host (whose recordings we
|
|
3940
|
+
// read) and the capture source, so a checkpoint always photographs the
|
|
3941
|
+
// surface its own recording is filming.
|
|
3942
|
+
for (const checkpointDriver of sessionDrivers(browserSessions, driver)) {
|
|
3943
|
+
await captureRecordingCheckpoints({
|
|
3944
|
+
config,
|
|
3945
|
+
driver: checkpointDriver,
|
|
3946
|
+
recordingHost: checkpointDriver,
|
|
3947
|
+
step,
|
|
3948
|
+
stepStatus: stepReport.result,
|
|
3949
|
+
stepIndex,
|
|
3950
|
+
stepCount: context.steps.length,
|
|
3951
|
+
testId: test.testId,
|
|
3952
|
+
appSession,
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3954
3955
|
pushStepReport(stepReport);
|
|
3955
3956
|
// Apply the terminal routing decision. `continue` runs the next step; a
|
|
3956
3957
|
// `stop` halts the remaining steps in this context (`spec`/`run` scope —
|
|
@@ -4262,6 +4263,22 @@ async function runStep({ config = {}, context = {}, step, driver, metaValues = {
|
|
|
4262
4263
|
const handle = actionResult.recording;
|
|
4263
4264
|
handle.id = handle.id ?? randomUUID();
|
|
4264
4265
|
handle.name = handle.name ?? recordStepName(step.record);
|
|
4266
|
+
// Recording checkpoints (ADR 01075): resolve the step's `checkpoints`
|
|
4267
|
+
// field once, here, where the handle and its target path are both at
|
|
4268
|
+
// hand — the post-step hook and stopRecord read the resolved config
|
|
4269
|
+
// off the handle. resolveCheckpointsConfig returns null for every
|
|
4270
|
+
// record form without a checkpoints field (string/boolean included),
|
|
4271
|
+
// so `null` is the single "disabled" encoding. `overwrite` rides along
|
|
4272
|
+
// for stopRecord's aboveVariation staging/promote decision (ADR 01078).
|
|
4273
|
+
handle.overwrite = step.record?.overwrite;
|
|
4274
|
+
handle.verify = step.record?.verify;
|
|
4275
|
+
if (handle.targetPath) {
|
|
4276
|
+
handle.checkpoints = resolveCheckpointsConfig({
|
|
4277
|
+
record: step.record,
|
|
4278
|
+
targetPath: handle.targetPath,
|
|
4279
|
+
handleId: handle.id,
|
|
4280
|
+
});
|
|
4281
|
+
}
|
|
4265
4282
|
if (step.__autoRecord) {
|
|
4266
4283
|
handle.synthetic = true;
|
|
4267
4284
|
// Desktop app-only context: no window exists yet to crop to. Mark the
|