93 lines
2.8 KiB
React
93 lines
2.8 KiB
React
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { vi } from "vitest";
|
|
import PaymentForm from "./PaymentForm";
|
|
import i18n from "../i18n";
|
|
|
|
vi.mock("../api/client", () => ({
|
|
apiPost: vi.fn(),
|
|
}));
|
|
|
|
const { apiPost } = await import("../api/client");
|
|
|
|
describe("PaymentForm", () => {
|
|
beforeEach(async () => {
|
|
vi.clearAllMocks();
|
|
await i18n.changeLanguage("en");
|
|
Object.defineProperty(globalThis, "crypto", {
|
|
value: { randomUUID: () => "uuid-1" },
|
|
configurable: true,
|
|
});
|
|
});
|
|
|
|
it("validates source details for stc pay", async () => {
|
|
render(<PaymentForm bookingId="12" />);
|
|
fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
|
|
expect(
|
|
await screen.findByText("Mobile number is required for stc pay.")
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("reuses idempotency key on retry", async () => {
|
|
apiPost.mockRejectedValueOnce(new Error("fail"));
|
|
apiPost.mockResolvedValueOnce({ id: "ok" });
|
|
render(<PaymentForm bookingId="12" />);
|
|
|
|
fireEvent.change(screen.getByLabelText("Source value"), {
|
|
target: { value: "+966500000000" },
|
|
});
|
|
fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
|
|
await screen.findByText("fail");
|
|
|
|
fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
|
|
await waitFor(() => {
|
|
expect(apiPost).toHaveBeenCalledTimes(2);
|
|
});
|
|
const firstPayload = apiPost.mock.calls[0][1];
|
|
const secondPayload = apiPost.mock.calls[1][1];
|
|
expect(firstPayload.idempotency_key).toBe("uuid-1");
|
|
expect(secondPayload.idempotency_key).toBe("uuid-1");
|
|
});
|
|
|
|
it("redirects when response includes redirect_url", async () => {
|
|
const assign = vi.fn();
|
|
Object.defineProperty(window.location, "assign", {
|
|
value: assign,
|
|
configurable: true,
|
|
});
|
|
apiPost.mockResolvedValueOnce({ redirect_url: "https://pay.test/redirect" });
|
|
render(<PaymentForm bookingId="12" />);
|
|
|
|
fireEvent.change(screen.getByLabelText("Source value"), {
|
|
target: { value: "+966500000000" },
|
|
});
|
|
fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
|
|
|
|
await waitFor(() => {
|
|
expect(assign).toHaveBeenCalledWith("https://pay.test/redirect");
|
|
});
|
|
});
|
|
|
|
it("disables submit while loading", async () => {
|
|
let resolveRequest;
|
|
apiPost.mockImplementationOnce(
|
|
() =>
|
|
new Promise((resolve) => {
|
|
resolveRequest = resolve;
|
|
})
|
|
);
|
|
render(<PaymentForm bookingId="12" />);
|
|
|
|
fireEvent.change(screen.getByLabelText("Source value"), {
|
|
target: { value: "+966500000000" },
|
|
});
|
|
const button = screen.getByRole("button", { name: "Pay now" });
|
|
fireEvent.click(button);
|
|
expect(button).toBeDisabled();
|
|
|
|
resolveRequest({ id: "done" });
|
|
await waitFor(() => {
|
|
expect(button).not.toBeDisabled();
|
|
});
|
|
});
|
|
});
|