- Added an audit trail feature that logs every create, update, and delete action on delivery notes and orders, capturing detailed changes per field. - Introduced the `AuditTimeline` component to display the history of changes for delivery notes and orders, enhancing traceability. - Updated the `page.tsx` files for delivery notes and orders to fetch and display audit logs, ensuring users can view the history of modifications. - Enhanced the `package.json` with a new migration script for setting up the audit log functionality. This feature improves accountability and transparency in the management of delivery notes and orders.
90 lines
2.8 KiB
TypeScript
90 lines
2.8 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
filenameFromDisposition,
|
|
reportFileName,
|
|
safeFilePart,
|
|
} from "./download";
|
|
|
|
describe("reportFileName", () => {
|
|
it("is date range plus subject", () => {
|
|
expect(reportFileName("2026-09-01", "2026-09-30", "Gary")).toBe(
|
|
"2026-09-01 - 2026-09-30 - Gary.pdf",
|
|
);
|
|
});
|
|
|
|
it("keeps a two-word name intact", () => {
|
|
expect(reportFileName("2026-08-01", "2026-08-31", "David Els")).toBe(
|
|
"2026-08-01 - 2026-08-31 - David Els.pdf",
|
|
);
|
|
});
|
|
|
|
it("strips path separators so the name can't escape the download folder", () => {
|
|
expect(reportFileName("2026-09-01", "2026-09-30", "../../etc/passwd")).not.toContain("/");
|
|
});
|
|
});
|
|
|
|
describe("safeFilePart", () => {
|
|
it("drops characters that are illegal on Windows or awkward on macOS", () => {
|
|
expect(safeFilePart('a/b\\c:d*e?f"g<h>i|j')).not.toMatch(/[/\\:*?"<>|]/);
|
|
});
|
|
|
|
it("collapses runs of whitespace", () => {
|
|
expect(safeFilePart(" L & L Equip ")).toBe("L & L Equip");
|
|
});
|
|
|
|
it("keeps ampersands, hyphens, dots and parentheses used in real names", () => {
|
|
expect(safeFilePart("Harmony - Gold Mining (Pty) Ltd.")).toBe(
|
|
"Harmony - Gold Mining (Pty) Ltd.",
|
|
);
|
|
});
|
|
|
|
it("falls back when nothing usable survives", () => {
|
|
expect(safeFilePart("///", "report")).toBe("report");
|
|
});
|
|
});
|
|
|
|
describe("filenameFromDisposition", () => {
|
|
const target = "2026-09-01 - 2026-09-30 - Gary.pdf";
|
|
|
|
it("reads a quoted filename", () => {
|
|
expect(
|
|
filenameFromDisposition(`attachment; filename="${target}"`, "fallback.pdf"),
|
|
).toBe(target);
|
|
});
|
|
|
|
it("reads an unquoted filename", () => {
|
|
expect(filenameFromDisposition(`attachment; filename=${target}`, "fallback.pdf")).toBe(
|
|
target,
|
|
);
|
|
});
|
|
|
|
it("prefers filename* when present", () => {
|
|
const header =
|
|
`attachment; filename="fallback.pdf"; filename*=UTF-8''` +
|
|
encodeURIComponent(target);
|
|
expect(filenameFromDisposition(header, "x.pdf")).toBe(target);
|
|
});
|
|
|
|
it("survives a malformed filename* and uses the plain form", () => {
|
|
expect(
|
|
filenameFromDisposition(`attachment; filename="${target}"; filename*=UTF-8''%E0%A4%A`, "x.pdf"),
|
|
).toBe(target);
|
|
});
|
|
|
|
it("falls back when there is no header at all (4xx JSON responses)", () => {
|
|
expect(filenameFromDisposition(null, "fallback.pdf")).toBe("fallback.pdf");
|
|
});
|
|
|
|
it("falls back when the header carries no filename", () => {
|
|
expect(filenameFromDisposition("attachment", "fallback.pdf")).toBe("fallback.pdf");
|
|
});
|
|
|
|
it("still returns a .pdf name for a team report", () => {
|
|
expect(
|
|
filenameFromDisposition(
|
|
'attachment; filename="2026-09-01 - 2026-09-30 - All Reps.pdf"',
|
|
"x.pdf",
|
|
),
|
|
).toBe("2026-09-01 - 2026-09-30 - All Reps.pdf");
|
|
});
|
|
});
|