94 lines
4.3 KiB
TypeScript
94 lines
4.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const requireCommissionUser = vi.fn();
|
|
const limitRequest = vi.fn();
|
|
const validateCommissionCatalog = vi.fn();
|
|
const promptPayConfig = vi.fn();
|
|
const transaction = vi.fn();
|
|
const forUpdate = vi.fn();
|
|
const returning = vi.fn();
|
|
const insert = vi.fn();
|
|
const values = vi.fn();
|
|
|
|
vi.mock("@/lib/commission/server", () => ({ requireCommissionUser }));
|
|
vi.mock("@/lib/security/rate-limit", () => ({ limitRequest }));
|
|
vi.mock("@/lib/commission/catalog", () => ({ validateCommissionCatalog }));
|
|
vi.mock("@/lib/commission/payment", () => ({ promptPayConfig }));
|
|
vi.mock("@/db", () => ({ getDb: () => ({ transaction }) }));
|
|
|
|
const { POST } = await import("./route");
|
|
|
|
function request(customStats?: string) {
|
|
return new Request("https://guide.sudloh.com/api/commission/checkouts", {
|
|
method: "POST", headers: { Origin: "https://guide.sudloh.com", "Content-Type": "application/json" },
|
|
body: JSON.stringify({ teams: customStats === undefined ? [] : [{ members: ["a", "b", "c", "d"].map((characterKey, index) => ({
|
|
characterKey, weaponKey: "w1", artifactKey: "artifact", customStats: index === 0 ? customStats : undefined,
|
|
})) }], weapons: [{ characterKey: "c", weaponKeys: ["w1", "w2"] }],
|
|
constellations: [] }),
|
|
});
|
|
}
|
|
|
|
describe("commission checkout availability", () => {
|
|
beforeEach(() => {
|
|
process.env.BETTER_AUTH_URL = "https://guide.sudloh.com";
|
|
vi.clearAllMocks();
|
|
requireCommissionUser.mockResolvedValue({ id: "customer-1" });
|
|
limitRequest.mockResolvedValue(undefined);
|
|
validateCommissionCatalog.mockResolvedValue(true);
|
|
promptPayConfig.mockReturnValue({ identifier: "test" });
|
|
transaction.mockImplementation((callback) => callback({
|
|
select: () => ({ from: () => ({ where: () => ({ for: forUpdate }) }) }),
|
|
insert,
|
|
}));
|
|
insert.mockReturnValue({ values });
|
|
values.mockReturnValue({ returning });
|
|
returning.mockResolvedValue([{ id: "checkout-1" }]);
|
|
});
|
|
|
|
it("rejects a stale form submission after closure", async () => {
|
|
forUpdate.mockResolvedValue([{ isOpen: false }]);
|
|
const response = await POST(request());
|
|
expect(response.status).toBe(409);
|
|
expect(await response.json()).toEqual({ error: "commission-closed" });
|
|
expect(insert).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("creates a checkout while open", async () => {
|
|
forUpdate.mockResolvedValue([{ isOpen: true }]);
|
|
const response = await POST(request());
|
|
expect(response.status).toBe(201);
|
|
expect(await response.json()).toEqual({ checkoutId: "checkout-1" });
|
|
expect(insert).toHaveBeenCalledOnce();
|
|
expect(values).toHaveBeenCalledWith(expect.objectContaining({ amountBaht: 140 }));
|
|
});
|
|
it("stores custom stats and charges twice the total on the server", async () => {
|
|
forUpdate.mockResolvedValue([{ isOpen: true }]);
|
|
const response = await POST(request("ATK 2000"));
|
|
expect(response.status).toBe(201);
|
|
expect(values).toHaveBeenCalledWith(expect.objectContaining({
|
|
amountBaht: 280, request: expect.objectContaining({ teams: [{ members: [
|
|
expect.objectContaining({ characterKey: "a", customStats: "ATK 2000" }),
|
|
expect.objectContaining({ characterKey: "b" }), expect.objectContaining({ characterKey: "c" }),
|
|
expect.objectContaining({ characterKey: "d" }),
|
|
] }] }),
|
|
}));
|
|
});
|
|
it("charges twice the total for custom stats on either comparison type without a team", async () => {
|
|
forUpdate.mockResolvedValue([{ isOpen: true }]);
|
|
for (const kind of ["weapons", "constellations"]) {
|
|
values.mockClear();
|
|
const body = { teams: [], weapons: [], constellations: [], [kind]: kind === "weapons"
|
|
? [{ characterKey: "a", weaponKeys: ["one", "two"], customStats: "ATK 2000" }]
|
|
: [{ characterKey: "a", levels: [0, 1], customStats: "ER 180%" }] };
|
|
const response = await POST(new Request("https://guide.sudloh.com/api/commission/checkouts", {
|
|
method: "POST", headers: { Origin: "https://guide.sudloh.com", "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
}));
|
|
expect(response.status).toBe(201);
|
|
expect(values).toHaveBeenCalledWith(expect.objectContaining({ amountBaht: 280,
|
|
request: expect.objectContaining({ [kind]: expect.arrayContaining([expect.objectContaining({ customStats: body[kind][0].customStats })]) }),
|
|
}));
|
|
}
|
|
});
|
|
});
|