fix: surface webprobe performance evidence mode
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { test } from "bun:test";
|
||||
|
||||
import { nodeWebObserveCollectViewNodeScript } from "../hwlab-node-web-observe-collect";
|
||||
|
||||
function shellQuote(value: string): string {
|
||||
return `'${value.replace(/'/g, `'\\''`)}'`;
|
||||
}
|
||||
|
||||
test("performance-summary labels LoAF-only evidence when CPU profile capture is pending", async () => {
|
||||
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-performance-"));
|
||||
await mkdir(join(stateDir, "analysis"), { recursive: true });
|
||||
await mkdir(join(stateDir, "commands", "pending"), { recursive: true });
|
||||
await writeFile(join(stateDir, "manifest.json"), JSON.stringify({ jobId: "webobs-perf-test", status: "failed" }) + "\n");
|
||||
await writeFile(join(stateDir, "heartbeat.json"), JSON.stringify({ status: "failed", updatedAt: "2026-07-02T12:08:06Z" }) + "\n");
|
||||
await writeFile(join(stateDir, "performance-events.jsonl"), [
|
||||
JSON.stringify({
|
||||
type: "performance-event",
|
||||
ts: "2026-07-02T12:07:00Z",
|
||||
performance: { kind: "long-animation-frame", duration: 2083.8 },
|
||||
}),
|
||||
].join("\n") + "\n");
|
||||
await writeFile(join(stateDir, "commands", "pending", "cmd-perf.json"), JSON.stringify({
|
||||
id: "cmd-perf",
|
||||
type: "performanceCapture",
|
||||
createdAt: "2026-07-02T12:08:00Z",
|
||||
}) + "\n");
|
||||
await writeFile(join(stateDir, "analysis", "report.json"), JSON.stringify({
|
||||
manifest: { status: "failed" },
|
||||
heartbeat: { status: "failed", updatedAt: "2026-07-02T12:08:06Z" },
|
||||
frontendPerformance: {
|
||||
summary: {
|
||||
eventCount: 1,
|
||||
longTaskCount: 0,
|
||||
longAnimationFrameCount: 1,
|
||||
eventLoopGapCount: 0,
|
||||
captureCount: 0,
|
||||
scriptHotspotCount: 1,
|
||||
maxLongAnimationFrameMs: 2083.8,
|
||||
longAnimationFrameRedMs: 200,
|
||||
cpuProfileStatus: "missing",
|
||||
attributionMode: "loaf-only-no-cpu-profile",
|
||||
noCpuProfile: true,
|
||||
loafOnly: true,
|
||||
valuesRedacted: true,
|
||||
},
|
||||
scriptHotspots: [{
|
||||
sourceFunctionName: "Response.json.then",
|
||||
sourceURL: "https://hwlab.example.test/app.js",
|
||||
totalDurationMs: 2108,
|
||||
count: 2,
|
||||
valuesRedacted: true,
|
||||
}],
|
||||
profileHotspots: [],
|
||||
profileStacks: [],
|
||||
captures: [],
|
||||
longAnimationFrames: [{ ts: "2026-07-02T12:07:00Z", kind: "long-animation-frame", durationMs: 2083.8, sampleSeq: 42, pageRole: "control", scriptCount: 1 }],
|
||||
},
|
||||
findings: [{
|
||||
id: "frontend-performance-loaf-only-no-cpu-profile",
|
||||
severity: "amber",
|
||||
summary: "frontend performance evidence is LoAF/LongTask/event-loop only because no completed CPU profile capture is present",
|
||||
count: 1,
|
||||
}, {
|
||||
id: "tool-pending-commands-unconsumed",
|
||||
severity: "red",
|
||||
summary: "web-probe observe has pending/processing control commands that were not consumed by the runner",
|
||||
count: 1,
|
||||
}],
|
||||
}) + "\n");
|
||||
|
||||
const script = nodeWebObserveCollectViewNodeScript({
|
||||
maxFiles: 100,
|
||||
view: "performance-summary",
|
||||
traceId: null,
|
||||
sampleSeq: null,
|
||||
timestamp: null,
|
||||
turn: null,
|
||||
commandId: null,
|
||||
windowMs: null,
|
||||
});
|
||||
const result = spawnSync("bash", ["-lc", `state_dir=${shellQuote(stateDir)}\n${script}`], {
|
||||
cwd: join(import.meta.dir, "../../.."),
|
||||
encoding: "utf8",
|
||||
});
|
||||
assert.equal(result.status, 0, result.stderr || result.stdout);
|
||||
|
||||
const output = JSON.parse(result.stdout);
|
||||
const text = String(output.renderedText ?? "");
|
||||
const debug = JSON.stringify({ summary: output.summary, evidenceMode: output.evidenceMode, text }, null, 2);
|
||||
assert.equal(output.evidenceMode.attributionMode, "loaf-only-no-cpu-profile", debug);
|
||||
assert.equal(output.evidenceMode.cpuProfileStatus, "pending-command-no-cpu-profile");
|
||||
assert.equal(output.evidenceMode.pendingPerformanceCapture, true);
|
||||
assert.match(text, /LoAF-only \/ no CPU profile/u);
|
||||
assert.match(text, /pending performanceCapture: cmd-perf\(pending\)/u);
|
||||
assert.match(text, /runner state: not-running\/failed/u);
|
||||
assert.match(text, /no CPU profile hotspots; no completed performanceCapture artifact/u);
|
||||
}, 20_000);
|
||||
Reference in New Issue
Block a user