* refactor: apply biome formatting to packages/features (batch 1 - small subdirs) Format small subdirectories in packages/features: di, flags, holidays, oauth, settings, users, assignment-reason, selectedCalendar, hashedLink, host, form, form-builder, availability, data-table, pbac, schedules, troubleshooter, eventtypes, calendar-subscription, and root-level files. Also includes straggler apps/web BookEventForm.tsx. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 2 - medium subdirs) Format medium subdirectories in packages/features: auth, credentials, calendars, routing-forms, routing-trace, attributes, watchlist, calAIPhone, tasker, and webhooks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 3 - bookings + insights) Format bookings and insights subdirectories in packages/features. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 4 - ee) Format packages/features/ee subdirectory covering billing, workflows, organizations, teams, managed-event-types, round-robin, dsync, integration-attribute-sync, and payments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 5 - booking-audit part 1) Format booking-audit di, actions, common, dto, repository, and types subdirectories in packages/features/booking-audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 6 - booking-audit part 2) Format booking-audit service subdirectory in packages/features/booking-audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
import { buffer } from "micro";
|
|
import type { NextApiRequest } from "next";
|
|
import { createMocks } from "node-mocks-http";
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
import stripe from "@calcom/features/ee/payments/server/stripe";
|
|
|
|
import { stripeWebhookHandler, HttpCode } from "./__handler";
|
|
|
|
vi.mock("micro", () => ({
|
|
buffer: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@calcom/features/ee/payments/server/stripe", () => ({
|
|
default: {
|
|
webhooks: {
|
|
constructEvent: vi.fn(),
|
|
},
|
|
},
|
|
}));
|
|
|
|
const STRIPE_WEBHOOK_SECRET_BILLING = "whsec_test_secret";
|
|
|
|
describe("stripeWebhookHandler", () => {
|
|
beforeEach(() => {
|
|
vi.stubEnv("STRIPE_WEBHOOK_SECRET_BILLING", STRIPE_WEBHOOK_SECRET_BILLING);
|
|
});
|
|
|
|
const mockRequest = (headers: Record<string, string>, body: string): NextApiRequest =>
|
|
({
|
|
headers,
|
|
body,
|
|
}) as unknown as NextApiRequest;
|
|
|
|
it("should throw an error if stripe-signature header is missing", async () => {
|
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
|
method: "POST",
|
|
});
|
|
|
|
const handler = stripeWebhookHandler({});
|
|
await expect(handler(req)).rejects.toThrow(new HttpCode(400, "Missing stripe-signature"));
|
|
});
|
|
|
|
it("should throw an error if STRIPE_WEBHOOK_SECRET_BILLING is missing", async () => {
|
|
vi.stubEnv("STRIPE_WEBHOOK_SECRET_BILLING", "");
|
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
|
method: "POST",
|
|
headers: {
|
|
"stripe-signature": "test_signature",
|
|
},
|
|
});
|
|
const handler = stripeWebhookHandler({});
|
|
await expect(handler(req)).rejects.toThrow(new HttpCode(500, "Missing STRIPE_WEBHOOK_SECRET"));
|
|
});
|
|
|
|
it("should return success false if event type is unhandled", async () => {
|
|
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
|
method: "POST",
|
|
headers: {
|
|
"stripe-signature": "test_signature",
|
|
},
|
|
});
|
|
// const req = mockRequest({ "stripe-signature": "test_signature" }, "test_payload");
|
|
(buffer as any).mockResolvedValueOnce(Buffer.from("test_payload"));
|
|
(stripe.webhooks.constructEvent as any).mockReturnValueOnce({ type: "unhandled_event" });
|
|
|
|
const handler = stripeWebhookHandler({});
|
|
const response = await handler(req);
|
|
expect(response).toEqual({
|
|
success: false,
|
|
message: "Unhandled Stripe Webhook event type unhandled_event",
|
|
});
|
|
});
|
|
|
|
it("should call the appropriate handler for a valid event", async () => {
|
|
const req = mockRequest({ "stripe-signature": "test_signature" }, "test_payload");
|
|
(buffer as any).mockResolvedValueOnce(Buffer.from("test_payload"));
|
|
(stripe.webhooks.constructEvent as any).mockReturnValueOnce({
|
|
type: "payment_intent.succeeded",
|
|
data: "test_data",
|
|
});
|
|
|
|
const mockHandler = vi.fn().mockResolvedValueOnce("handler_response");
|
|
const handlers = {
|
|
"payment_intent.succeeded": () => Promise.resolve({ default: mockHandler }),
|
|
};
|
|
|
|
const handler = stripeWebhookHandler(handlers);
|
|
const response = await handler(req);
|
|
|
|
expect(mockHandler).toHaveBeenCalledWith("test_data");
|
|
expect(response).toBe("handler_response");
|
|
});
|
|
});
|