mirror of
https://github.com/Since-3/Kuma.git
synced 2026-10-12 20:51:18 +00:00
129 lines
4.4 KiB
TypeScript
129 lines
4.4 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||
import { POST } from "@/src/app/api/stripe/checkout/course/route";
|
||
|
||
vi.mock("@/src/lib/auth/getUser", () => ({
|
||
getUserData: vi.fn(),
|
||
isUser: vi.fn(),
|
||
}));
|
||
|
||
vi.mock("@/src/lib/auth/account-role-by-email", () => ({
|
||
isManagerOrEmployeeEmail: vi.fn(),
|
||
}));
|
||
|
||
vi.mock("@/src/lib/prisma", () => ({
|
||
prisma: {
|
||
course: { findUnique: vi.fn() },
|
||
courseBooking: { findUnique: vi.fn() },
|
||
},
|
||
}));
|
||
|
||
vi.mock("@/src/lib/stripe", () => ({
|
||
stripe: { checkout: { sessions: { create: vi.fn() } } },
|
||
calculatePlatformFeeCents: vi.fn().mockReturnValue(100),
|
||
eurosToCents: vi.fn().mockReturnValue(2900),
|
||
}));
|
||
|
||
import { getUserData, isUser } from "@/src/lib/auth/getUser";
|
||
import { isManagerOrEmployeeEmail } from "@/src/lib/auth/account-role-by-email";
|
||
import { prisma } from "@/src/lib/prisma";
|
||
import { stripe } from "@/src/lib/stripe";
|
||
|
||
let ipCounter = 0;
|
||
|
||
function makeRequest(body: Record<string, unknown>) {
|
||
// Jede Anfrage aus einer eigenen IP, damit der In-Memory-Rate-Limiter
|
||
// (10/Minute/IP) die Tests nicht gegenseitig beeinflusst.
|
||
ipCounter += 1;
|
||
return new Request("http://localhost/api/stripe/checkout/course", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"x-forwarded-for": `10.0.0.${ipCounter}`,
|
||
},
|
||
body: JSON.stringify(body),
|
||
}) as never;
|
||
}
|
||
|
||
const publishedCourse = {
|
||
id: "course-1",
|
||
name: "Yoga",
|
||
status: "published",
|
||
price: 29,
|
||
date: new Date("2099-01-01"),
|
||
timeFrom: "10:00",
|
||
maxParticipants: 20,
|
||
_count: { bookings: 0 },
|
||
business: {
|
||
id: "biz-1",
|
||
name: "Studio",
|
||
stripeAccountId: "acct_123",
|
||
stripeAccountStatus: "active",
|
||
},
|
||
};
|
||
|
||
beforeEach(() => {
|
||
vi.mocked(getUserData).mockReset();
|
||
vi.mocked(isUser).mockReset();
|
||
vi.mocked(isManagerOrEmployeeEmail).mockReset();
|
||
vi.mocked(prisma.course.findUnique).mockReset();
|
||
vi.mocked(prisma.courseBooking.findUnique).mockReset();
|
||
vi.mocked(stripe.checkout.sessions.create).mockReset();
|
||
|
||
vi.mocked(stripe.checkout.sessions.create).mockResolvedValue({
|
||
url: "https://checkout.stripe.com/session",
|
||
} as never);
|
||
vi.mocked(prisma.course.findUnique).mockResolvedValue(publishedCourse as never);
|
||
});
|
||
|
||
describe("POST /api/stripe/checkout/course – Gast mit Team-Account-E-Mail (Ticket 6)", () => {
|
||
it("lehnt eine Gast-Buchung mit Manager/Employee-E-Mail mit 403 ab, ohne Stripe-Session", async () => {
|
||
vi.mocked(getUserData).mockResolvedValue(null as never);
|
||
vi.mocked(isManagerOrEmployeeEmail).mockResolvedValue(true);
|
||
|
||
const res = await POST(makeRequest({ courseId: "course-1", guestEmail: "Manager@Studio.de" }));
|
||
|
||
expect(res.status).toBe(403);
|
||
const data = await res.json();
|
||
expect(data.error).toMatch(/Team-Account/i);
|
||
expect(isManagerOrEmployeeEmail).toHaveBeenCalledWith("manager@studio.de");
|
||
expect(stripe.checkout.sessions.create).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it("lässt eine normale Gast-Buchung durch, wenn die E-Mail zu keinem Team-Account gehört", async () => {
|
||
vi.mocked(getUserData).mockResolvedValue(null as never);
|
||
vi.mocked(isManagerOrEmployeeEmail).mockResolvedValue(false);
|
||
vi.mocked(prisma.courseBooking.findUnique).mockResolvedValue(null as never);
|
||
|
||
const res = await POST(makeRequest({ courseId: "course-1", guestEmail: "gast@example.com" }));
|
||
|
||
expect(res.status).toBe(200);
|
||
const data = await res.json();
|
||
expect(data.url).toBe("https://checkout.stripe.com/session");
|
||
expect(stripe.checkout.sessions.create).toHaveBeenCalledOnce();
|
||
});
|
||
|
||
it("prüft die Team-Account-E-Mail nicht für eingeloggte Kunden-Accounts", async () => {
|
||
vi.mocked(getUserData).mockResolvedValue({
|
||
id: "user-1",
|
||
email: "kunde@example.com",
|
||
} as never);
|
||
vi.mocked(isUser).mockReturnValue(true);
|
||
vi.mocked(prisma.courseBooking.findUnique).mockResolvedValue(null as never);
|
||
|
||
const res = await POST(makeRequest({ courseId: "course-1" }));
|
||
|
||
expect(res.status).toBe(200);
|
||
expect(isManagerOrEmployeeEmail).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it("weist eine ungültige Gast-E-Mail weiterhin vor der Team-Account-Prüfung mit 400 ab", async () => {
|
||
vi.mocked(getUserData).mockResolvedValue(null as never);
|
||
|
||
const res = await POST(makeRequest({ courseId: "course-1", guestEmail: "keine-email" }));
|
||
|
||
expect(res.status).toBe(400);
|
||
const data = await res.json();
|
||
expect(data.isGuestRequired).toBe(true);
|
||
expect(isManagerOrEmployeeEmail).not.toHaveBeenCalled();
|
||
});
|
||
});
|