feat(diagnostics): the debug recorder — start, the pill, steps, screenshots, stop (E16 S2)
- the start dialog is the consent: level (Részletes/Teljes), what is recorded, retention and the cap (now served as diagnostics.session_minutes) - the pill docks under the toasts: elapsed time, Step (an optional label, its own Escape layer), Screenshot (tab capture where the browser has it), Stop; compact on a phone - while recording, lib/log tags every event and every request path (req, beacon, uploadReq via one identityHeaders) names the session; applyDiagnostics raises the level for the session's run and never lowers a raised one, and lapses at whichever ends first - Stop sends what is waiting before the server closes the session; the cap says so and opens the composer - Settings → Diagnosztika and the command palette start/step/stop it - the evidence leaves the log upload's own request lines out - the step shortcut is deliberately palette-only: the keymap's D1 rule bars a new modifier chord, and a bare letter collides with the players'
This commit is contained in:
@@ -22,7 +22,9 @@ vi.mock("../activeAccount", () => ({
|
||||
pinActiveAccount: () => {},
|
||||
}));
|
||||
|
||||
import { setDebugSession } from "../log";
|
||||
import {
|
||||
beacon,
|
||||
req,
|
||||
uploadReq,
|
||||
setUnauthorizedHandler,
|
||||
@@ -310,3 +312,32 @@ describe("req — what it has already put in front of the user", () => {
|
||||
expect(remove).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
// E16: while a debug session records, every request path names it — the server tags ITS lines of
|
||||
// that request with it. A path that forgot the header would leave holes in the evidence exactly
|
||||
// where the upload (XHR) or the unload beacon happened.
|
||||
describe("the debug session a tab records into", () => {
|
||||
const sentHeaders = () => {
|
||||
const init = vi.mocked(globalThis.fetch).mock.lastCall?.[1] as RequestInit;
|
||||
return new Headers(init.headers as HeadersInit);
|
||||
};
|
||||
|
||||
it("rides every request path while it records, and none once it stops", async () => {
|
||||
vi.spyOn(globalThis, "fetch").mockImplementation(() =>
|
||||
Promise.resolve(new Response("{}", { status: 200 })),
|
||||
);
|
||||
setDebugSession("0123456789abcdef");
|
||||
try {
|
||||
await req("/api/x");
|
||||
expect(sentHeaders().get("X-Debug-Session")).toBe("0123456789abcdef");
|
||||
beacon("/api/y", {});
|
||||
expect(sentHeaders().get("X-Debug-Session")).toBe("0123456789abcdef");
|
||||
void uploadReq("/u", form());
|
||||
expect(FakeXHR.last.headers["X-Debug-Session"]).toBe("0123456789abcdef");
|
||||
} finally {
|
||||
setDebugSession(null);
|
||||
}
|
||||
await req("/api/x");
|
||||
expect(sentHeaders().has("X-Debug-Session")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user