feat : custom stats with double price in commission
CI / Verify (push) Successful in 1m49s
CI / Build immutable images and deploy (push) Successful in 2m14s

This commit is contained in:
2026-10-10 05:08:06 +07:00 Unverified
parent 0e813a0a3e
commit 6fc4427ae1
10 changed files with 186 additions and 10 deletions
+37 -3
View File
@@ -8,6 +8,7 @@ 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 }));
@@ -17,10 +18,12 @@ vi.mock("@/db", () => ({ getDb: () => ({ transaction }) }));
const { POST } = await import("./route");
function request() {
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: [], weapons: [{ characterKey: "c", weaponKeys: ["w1", "w2"] }],
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: [] }),
});
}
@@ -37,7 +40,8 @@ describe("commission checkout availability", () => {
select: () => ({ from: () => ({ where: () => ({ for: forUpdate }) }) }),
insert,
}));
insert.mockReturnValue({ values: () => ({ returning }) });
insert.mockReturnValue({ values });
values.mockReturnValue({ returning });
returning.mockResolvedValue([{ id: "checkout-1" }]);
});
@@ -55,5 +59,35 @@ describe("commission checkout availability", () => {
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 })]) }),
}));
}
});
});