mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-05 00:12:09 +00:00
* fix(work-orders): address wizard create review findings
[recover] remove malicious eslint payload (was 166c63e4)
* fix(work-orders): remove legacy completedDate EditWorkorder path
[recover] remove malicious eslint payload (was f4e6132b)
* fix(work-orders): use local calendar day for completedDate
Restore todayIso() after parent merge reintroduced UTC slice, and keep the wizard-date-utils regression test.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(work-orders): send wizard status and clear POC notes on site change
Map draft.status to lifecycleStatus on board create, and reset pocNotes with POC fields when the wizard site changes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(query): scope broadcast channel per account and clear on auth
Isolate TanStack Query broadcast by userId, dispose and clear on
logout/401, and extract vendor filter drawers for governance.
* feat(work-orders): board wizard create with service notes
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(work-orders): enforce single-service wizard create per SH-118
Use single service selection in the wizard and omit extraServices from board create.
* fix(vendors): restore filter drawer labels for e2e and visual CI
Use VendorFilterOptions again and keep the Apply filters footer label expected
by vendor Playwright specs and the committed visual baseline.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
62 lines
2.3 KiB
TypeScript
62 lines
2.3 KiB
TypeScript
import { fireEvent, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { useState } from "react";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import { SignatureCapture } from "@/components/common/signature-capture";
|
|
import { renderWithProviders } from "@/test/test-utils";
|
|
|
|
/**
|
|
* Mirrors how a consumer wires `isPending` from a mutation: the flag flips to
|
|
* `true` synchronously once `onSave` fires and only clears when the caller
|
|
* decides to (e.g. on mutation settle), never inside `SignatureCapture` itself.
|
|
*/
|
|
function SignatureCaptureHarness({ onSave }: { onSave: () => void }) {
|
|
const [isPending, setIsPending] = useState(false);
|
|
|
|
return (
|
|
<SignatureCapture
|
|
title="Customer Sign-off"
|
|
isPending={isPending}
|
|
onClose={vi.fn()}
|
|
onSave={() => {
|
|
setIsPending(true);
|
|
onSave();
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
async function fillTypedSignature(user: ReturnType<typeof userEvent.setup>) {
|
|
await user.type(screen.getByPlaceholderText("Enter signer's full name"), "Jane Doe");
|
|
await user.click(screen.getByRole("tab", { name: "Type" }));
|
|
await user.type(screen.getByPlaceholderText("Type your name"), "Jane Doe");
|
|
}
|
|
|
|
describe("SignatureCapture", () => {
|
|
it("disables Save Signature and closing controls while isPending", () => {
|
|
renderWithProviders(
|
|
<SignatureCapture title="Vendor Sign-off" isPending onClose={vi.fn()} onSave={vi.fn()} />,
|
|
{ withAuth: false },
|
|
);
|
|
|
|
expect(screen.getByRole("button", { name: "Saving…" })).toBeDisabled();
|
|
expect(screen.getByRole("button", { name: "Cancel" })).toBeDisabled();
|
|
expect(screen.getByRole("button", { name: "Close" })).toBeDisabled();
|
|
});
|
|
|
|
it("calls onSave exactly once when Save Signature is double-clicked before the mutation settles", async () => {
|
|
const user = userEvent.setup();
|
|
const handleSave = vi.fn();
|
|
renderWithProviders(<SignatureCaptureHarness onSave={handleSave} />, { withAuth: false });
|
|
|
|
await fillTypedSignature(user);
|
|
|
|
const saveButton = screen.getByRole("button", { name: "Save Signature" });
|
|
fireEvent.click(saveButton);
|
|
fireEvent.click(saveButton);
|
|
|
|
expect(handleSave).toHaveBeenCalledTimes(1);
|
|
expect(screen.getByRole("button", { name: "Saving…" })).toBeDisabled();
|
|
});
|
|
});
|