import { test, expect, seed, loginAs, api } from "./fixtures"; // Pays into a real PayFast sandbox account, so it needs one: // E2E_PAYFAST_MERCHANT_ID, E2E_PAYFAST_MERCHANT_KEY, E2E_PAYFAST_PASSPHRASE // (from the Sandbox dashboard). Skipped when they aren't set, e.g. in CI. const PF = { merchantId: process.env.E2E_PAYFAST_MERCHANT_ID || "", merchantKey: process.env.E2E_PAYFAST_MERCHANT_KEY || "", passphrase: process.env.E2E_PAYFAST_PASSPHRASE || "", }; type EventWithOptions = { eventOptions: { id: string; isMainTicket: boolean }[] }; type Registration = { id: string }; type Checkout = { checkoutId: string; redirectUrl: string; provider: string | null }; test.describe("PayFast", () => { test.skip(!PF.merchantId, "Set E2E_PAYFAST_* to test against a PayFast sandbox account"); test("choose PayFast on the pay page and land on PayFast's payment page", async ({ page }) => { await api(page, "admin", "PUT", "/api/payfast/config", { ...PF, mode: "sandbox" }); try { await api(page, "admin", "PUT", "/api/payments/providers/settings", { providers: [{ id: "yoco", enabled: true }, { id: "payfast", enabled: true }] }); // A booking for the paid conference, then an online checkout for it const event = await api(page, "staff", "GET", `/api/events/${seed().events.paid}`); const option = event.eventOptions.find((o) => o.isMainTicket)!; const reg = await api(page, "staff", "POST", "/api/registrations", { eventId: seed().events.paid, options: [{ eventOptionId: option.id, quantity: 1 }] }); const origin = new URL(page.url() === "about:blank" ? "http://localhost:3100" : page.url()).origin; const checkout = await api(page, "staff", "POST", "/api/payments/checkout", { registrationId: reg.id, successUrl: `${origin}/payment/success`, cancelUrl: `${origin}/payment/cancel`, failureUrl: `${origin}/payment/failure`, }); // Yoco and PayFast are both on, so the payer chooses expect(checkout.provider).toBeNull(); expect(checkout.redirectUrl).toContain(`/pay/${checkout.checkoutId}`); await loginAs(page, "staff"); await page.goto(new URL(checkout.redirectUrl).pathname); await expect(page.getByText("R150.00")).toBeVisible(); await expect(page.getByRole("button", { name: "Pay with Yoco" })).toBeVisible(); await page.getByRole("button", { name: "Pay with PayFast" }).click(); // The browser posts the signed form to the sandbox, which shows its payment page await page.waitForURL(/sandbox\.payfast\.co\.za/, { timeout: 30_000 }); await expect(page.locator("body")).not.toContainText(/signature/i); await expect(page.locator("body")).toContainText(/150[.,]00/); } finally { await api(page, "admin", "PUT", "/api/payments/providers/settings", { providers: [{ id: "yoco", enabled: true }, { id: "payfast", enabled: false }] }); await api(page, "admin", "PUT", "/api/payfast/config", { merchantId: "", merchantKey: "", passphrase: "" }); } }); });