57 lines
2.4 KiB
TypeScript
57 lines
2.4 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// The zip export is the one api method that reads a RAW response instead of a parsed answer, so it
|
|
// carries contract of its own: the bytes, and the name the server picked. The composer's DOM test
|
|
// mocks this method wholesale, so without this the blob and the filename parse ship untested — and
|
|
// a broken header regex would silently save every report under the fallback name.
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
vi.mock("../errorDialog", () => ({ reportError: vi.fn() }));
|
|
vi.mock("../notifications", async (importOriginal) => ({
|
|
...(await importOriginal<typeof import("../notifications")>()),
|
|
notify: vi.fn(() => 1),
|
|
remove: vi.fn(),
|
|
getActiveToasts: vi.fn((): { id: number }[] => []),
|
|
}));
|
|
vi.mock("../../i18n", () => ({ default: { t: (k: string) => k, language: "en" } }));
|
|
|
|
import { debugSessionsApi } from "./diagnostics";
|
|
|
|
const zip = (disposition?: string) =>
|
|
new Response("PK", {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/zip",
|
|
...(disposition ? { "content-disposition": disposition } : {}),
|
|
},
|
|
});
|
|
|
|
beforeEach(() => vi.restoreAllMocks());
|
|
|
|
describe("debugExport", () => {
|
|
it("hands back the bytes and the name the server chose", async () => {
|
|
vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
|
zip('attachment; filename="siftlode-debug-20260919-1402-abc123.zip"'),
|
|
);
|
|
|
|
const out = await debugSessionsApi.debugExport("0123456789abcdef");
|
|
|
|
expect(out.name).toBe("siftlode-debug-20260919-1402-abc123.zip");
|
|
// The body is read as bytes, not parsed: `r.json()` on a zip would throw on its first one.
|
|
// Brand, not `toBeInstanceOf(Blob)` — that asks which realm built the body: under jsdom the
|
|
// ambient `Blob` is jsdom's class, while `Response.blob()` returns node's own on Node 22 and
|
|
// jsdom's on Node 24, so the instance check passed locally and failed on the server gate.
|
|
expect(Object.prototype.toString.call(out.blob)).toBe("[object Blob]");
|
|
expect(out.blob.size).toBe(4);
|
|
});
|
|
|
|
it("names the file itself when the answer does not", async () => {
|
|
// A proxy that strips the header must not leave the browser saving something called "export".
|
|
vi.spyOn(globalThis, "fetch").mockResolvedValue(zip());
|
|
|
|
const out = await debugSessionsApi.debugExport("0123456789abcdef");
|
|
|
|
expect(out.name).toBe("siftlode-debug-0123456789abcdef.zip");
|
|
});
|
|
});
|