feat: added initial implementation
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user