import { expect, test } from "bun:test"; import { razorpayGateway } from "../src/adapters.ts"; test("Razorpay refunds use the provider idempotency header and preserve failed status", async () => { const gateway = razorpayGateway({ keyId: "fixture", keySecret: "fixture-secret", webhookSecret: "fixture-webhook", transport: (async (input: RequestInfo | URL, init?: RequestInit) => { expect(String(input)).toBe("https://api.razorpay.com/v1/payments/pay_fixture/refund"); expect(new Headers(init?.headers).get("X-Refund-Idempotency")).toBe("refund-fixture-key"); expect(new Headers(init?.headers).has("X-Razorpay-Idempotency")).toBe(false); expect(JSON.parse(String(init?.body))).toEqual({ amount: 100, notes: { reason: "Customer cancellation" }, }); return Response.json({ id: "rfnd_fixture", amount: 100, status: "failed" }); }) as typeof fetch, }); expect( ( await gateway.refund({ intentRef: "pay_fixture", idempotencyKey: "refund-fixture-key", amount: 100, currency: "INR", reason: "Customer cancellation", }) ).status, ).toBe("failed"); }); test("Razorpay transports remain private to concurrent tenant gateway instances", async () => { const original = globalThis.fetch; const make = (id: string) => razorpayGateway({ keyId: id, keySecret: "fixture-secret", webhookSecret: "fixture-webhook", transport: (async (input: RequestInfo | URL, init?: RequestInit) => { expect(String(input)).toBe("https://api.razorpay.com/v1/orders"); expect((init!.headers as Record).authorization).toBe( "Basic " + btoa(id + ":fixture-secret"), ); const value = JSON.parse(String(init!.body)); return Response.json({ id: "order_" + id, amount: value.amount, currency: value.currency }); }) as typeof fetch, }); const input = { id: "fixture-order", subject: "fixture", amount: 100, currency: "INR", idempotencyKey: "fixture-idempotency", }; const [a, b] = await Promise.all([ make("tenant_a").createIntent(input), make("tenant_b").createIntent(input), ]); expect(a.ref).toBe("order_tenant_a"); expect(b.ref).toBe("order_tenant_b"); expect(globalThis.fetch).toBe(original); });