Skip to content

Commit 6c3262d

Browse files
committed
feat: add tests for checkoutDonation function and update Jest configuration
1 parent 5366079 commit 6c3262d

2 files changed

Lines changed: 103 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* @jest-environment node
3+
*/
4+
import { checkoutDonation } from "./actions";
5+
6+
const createSession = jest.fn();
7+
const retrieveProduct = jest.fn();
8+
const getUser = jest.fn();
9+
const getOrCreateStripeCustomer = jest.fn();
10+
const headersGet = jest.fn();
11+
12+
jest.mock("@/lib/stripe", () => ({
13+
stripe: {
14+
checkout: { sessions: { create: (...args: unknown[]) => createSession(...args) } },
15+
products: { retrieve: (...args: unknown[]) => retrieveProduct(...args) },
16+
},
17+
getOrCreateStripeCustomer: (...args: unknown[]) =>
18+
getOrCreateStripeCustomer(...args),
19+
}));
20+
21+
jest.mock("@/utils/supabase/server", () => ({
22+
createClient: async () => ({ auth: { getUser } }),
23+
}));
24+
25+
jest.mock("next/headers", () => ({
26+
headers: async () => ({ get: (...args: unknown[]) => headersGet(...args) }),
27+
}));
28+
29+
const authedUser = {
30+
data: { user: { id: "user-1", email: "donor@test.com" } },
31+
};
32+
33+
beforeEach(() => {
34+
jest.clearAllMocks();
35+
process.env.STRIPE_DONATION_PRODUCT_ID = "prod_test123";
36+
getUser.mockResolvedValue(authedUser);
37+
getOrCreateStripeCustomer.mockResolvedValue("cus_123");
38+
retrieveProduct.mockResolvedValue({ default_price: "price_donation" });
39+
createSession.mockResolvedValue({ url: "https://stripe.test/session" });
40+
headersGet.mockReturnValue("https://app.test");
41+
});
42+
43+
describe("checkoutDonation", () => {
44+
it("requires an authenticated user", async () => {
45+
getUser.mockResolvedValue({ data: { user: null } });
46+
const result = await checkoutDonation();
47+
expect(result).toEqual({ error: "Not authenticated" });
48+
expect(createSession).not.toHaveBeenCalled();
49+
});
50+
51+
it("returns an error when the donation product env var is not set", async () => {
52+
delete process.env.STRIPE_DONATION_PRODUCT_ID;
53+
const result = await checkoutDonation();
54+
expect(result).toEqual({ error: "Donation product not configured" });
55+
expect(createSession).not.toHaveBeenCalled();
56+
});
57+
58+
it("creates a checkout session using the donation product's default price", async () => {
59+
const result = await checkoutDonation();
60+
61+
expect(retrieveProduct).toHaveBeenCalledWith("prod_test123");
62+
expect(getOrCreateStripeCustomer).toHaveBeenCalledWith(
63+
"user-1",
64+
"donor@test.com",
65+
);
66+
expect(createSession).toHaveBeenCalledWith(
67+
expect.objectContaining({
68+
customer: "cus_123",
69+
mode: "payment",
70+
metadata: { type: "donation" },
71+
line_items: [{ price: "price_donation", quantity: 1 }],
72+
}),
73+
);
74+
expect(result).toEqual({ url: "https://stripe.test/session" });
75+
});
76+
77+
it("derives success/cancel URLs from the request origin", async () => {
78+
await checkoutDonation();
79+
expect(createSession).toHaveBeenCalledWith(
80+
expect.objectContaining({
81+
success_url: "https://app.test/checkout/success",
82+
cancel_url: "https://app.test/checkout/cancel",
83+
}),
84+
);
85+
});
86+
87+
it("returns an error when Stripe omits the checkout URL", async () => {
88+
createSession.mockResolvedValue({ url: null });
89+
const result = await checkoutDonation();
90+
expect(result).toEqual({ error: "Stripe did not return a checkout URL" });
91+
});
92+
93+
it("throws when the request origin is missing", async () => {
94+
headersGet.mockReturnValue(null);
95+
await expect(checkoutDonation()).rejects.toThrow(
96+
"Missing request origin",
97+
);
98+
expect(createSession).not.toHaveBeenCalled();
99+
});
100+
});

jest.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ const createJestConfig = nextJest({
77
/** @type {import('jest').Config} */
88
const customJestConfig = {
99
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
10+
moduleNameMapper: {
11+
"^@/(.*)$": "<rootDir>/$1",
12+
},
1013
testEnvironment: "jest-environment-jsdom",
1114
modulePathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
1215
testMatch: ["**/*.test.[jt]s?(x)"],

0 commit comments

Comments
 (0)