WFDASH-WEBAPP/src/components/supplier-form.test.tsx
Dave 7555196166 feat(audit): implement audit trail for delivery notes and orders
- 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.
2026-09-30 01:48:44 +02:00

118 lines
3.8 KiB
TypeScript

import { cleanup, fireEvent, render, screen, waitFor, within } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { SupplierForm } from "./supplier-form";
/**
* Tests for the SupplierForm's duplicate-detection flow. There was no
* prior supplier-form test file, so this also covers the basic save
* path that the company/customer tests already exercise — we want
* the same shape of safety net for every entity that grew the dup
* check.
*/
const { createMock, findSupplierDuplicatesMock } = vi.hoisted(() => ({
createMock: vi.fn(),
findSupplierDuplicatesMock: vi.fn(),
}));
vi.mock("@/lib/pocketbase", () => ({
__esModule: true,
default: () => ({
collection: () => ({
create: createMock,
update: vi.fn(),
}),
}),
}));
vi.mock("sonner", () => ({
toast: { error: vi.fn(), success: vi.fn() },
}));
vi.mock("@/lib/pb-helpers", () => ({
findSupplierDuplicates: findSupplierDuplicatesMock,
}));
beforeEach(() => {
// Default for every debounced duplicate check. Tests layer
// mockResolvedValueOnce on top; later keystrokes fall back to [].
findSupplierDuplicatesMock.mockResolvedValue([]);
});
afterEach(() => {
// Unmount first so the 300ms duplicate-check debounce is cleared
// before the mocks are reset (otherwise it fires into a bare mock).
cleanup();
vi.clearAllMocks();
});
describe("SupplierForm", () => {
it("blocks save when an existing supplier has the same name and lets the operator override", async () => {
// Form is filling out "West Rand". PB returns an existing row
// with the same name (case-insensitive). Submit should pop the
// duplicate dialog instead of writing.
findSupplierDuplicatesMock.mockResolvedValueOnce([
{ id: "sup-existing", suppliername: "West Rand" } as never,
]);
createMock.mockResolvedValue({ id: "sup1" });
render(
<SupplierForm
open
onOpenChange={() => undefined}
onSaved={() => undefined}
/>
);
const form = screen.getByRole("dialog").querySelector("form")!;
fireEvent.change(within(form).getByPlaceholderText("e.g. West Rand Industrial"), {
target: { value: "west rand" },
});
fireEvent.click(within(form).getByRole("button", { name: "Create Supplier" }));
// Wait for the dialog to show the existing match.
await waitFor(() => {
expect(screen.getByText("West Rand")).toBeInTheDocument();
});
// The write was NOT performed yet.
expect(createMock).not.toHaveBeenCalled();
// "Save anyway" should land the write with the typed value.
fireEvent.click(screen.getByRole("button", { name: /save anyway/i }));
await waitFor(() => {
expect(createMock).toHaveBeenCalledWith(
expect.objectContaining({ suppliername: "west rand" })
);
});
});
it("excludes the current record from the duplicate check in edit mode", async () => {
// Bound to an existing supplier; typing the same name shouldn't
// flag itself. We assert the helper was called with the record's
// id as the excludeId.
const existing = { id: "sup-self", suppliername: "West Rand" };
findSupplierDuplicatesMock.mockResolvedValue([]);
render(
<SupplierForm
open
onOpenChange={() => undefined}
onSaved={() => undefined}
supplier={existing as never}
/>
);
const form = screen.getByRole("dialog").querySelector("form")!;
fireEvent.change(within(form).getByPlaceholderText("e.g. West Rand Industrial"), {
target: { value: "West Rand" },
});
// Live check debounces by 300ms — wait for the helper call.
await waitFor(() => {
expect(findSupplierDuplicatesMock).toHaveBeenCalledWith(
"West Rand",
"sup-self"
);
});
});
});