import { describe, expect, it } from "vitest"; import { commissionPrice, commissionRequestSchema } from "./request"; const request = { teams: [{ members: ["a", "b", "c", "d"].map((characterKey) => ({ characterKey, weaponKey: `weapon-${characterKey}`, artifactKey: "artifact", })) }], weapons: [{ characterKey: "a", weaponKeys: ["weapon-a", "weapon-b", "weapon-c"] }], constellations: [{ characterKey: "a", levels: [0, 2] }], }; describe("commission request pricing and shape", () => { it("doubles weapon and constellation comparisons including the base fee", () => { for (const kind of ["weapons", "constellations"] as const) { const standard = commissionRequestSchema.parse({ teams: [], weapons: [], constellations: [], [kind]: request[kind] }); const custom = commissionRequestSchema.parse({ ...standard, [kind]: standard[kind].map((set) => ({ ...set, customStats: " ER 180% " })) }); expect(custom[kind][0].customStats).toBe("ER 180%"); expect(commissionPrice(custom)).toBe(commissionPrice(standard) * 2); delete custom[kind][0].customStats; expect(commissionPrice(custom)).toBe(commissionPrice(standard)); for (const customStats of ["", " ", "a".repeat(4001)]) expect(commissionRequestSchema.safeParse({ ...standard, [kind]: standard[kind].map((set) => ({ ...set, customStats })) }).success).toBe(false); } }); it("applies the multiplier once when teams and both comparison types have custom stats", () => { const custom = commissionRequestSchema.parse({ ...request, teams: request.teams.map((team) => ({ members: team.members.map((member) => ({ ...member, customStats: "ATK 2000" })) })), weapons: request.weapons.map((set) => ({ ...set, customStats: "CRIT Rate 70%" })), constellations: request.constellations.map((set) => ({ ...set, customStats: "ER 180%" })), }); expect(commissionPrice(custom)).toBe(400); }); it("doubles the entire subtotal once when any team character has custom stats", () => { const standard = commissionRequestSchema.parse(request); for (const count of [1, 2, 4]) { const custom = commissionRequestSchema.parse({ ...request, teams: [{ members: request.teams[0].members.map((member, index) => index < count ? { ...member, customStats: ` ATK ${2000 + index} ` } : member) }] }); expect(commissionPrice(custom)).toBe(commissionPrice(standard) * 2); expect(custom.teams[0].members[0].customStats).toBe("ATK 2000"); expect(custom.teams[0].members[1].customStats).toBe(count > 1 ? "ATK 2001" : undefined); } const custom = commissionRequestSchema.parse({ teams: request.teams.concat([{ members: request.teams[0].members.map((member, index) => index === 3 ? { ...member, customStats: "ER 180%" } : member) }]), weapons: [], constellations: [] }); expect(commissionPrice(custom)).toBe(400); delete custom.teams[1].members[3].customStats; expect(commissionPrice(custom)).toBe(200); }); it("requires nonblank, bounded custom stats for each selected character", () => { for (const customStats of ["", " ", "a".repeat(4001), true]) { expect(commissionRequestSchema.safeParse({ ...request, teams: [{ members: request.teams[0].members.map((member, index) => index === 0 ? { ...member, customStats } : member) }] }).success).toBe(false); } }); it("accepts one complete team without either comparison type", () => { const teamOnly = { teams: request.teams, weapons: [], constellations: [] }; const parsed = commissionRequestSchema.safeParse(teamOnly); expect(parsed.success).toBe(true); if (parsed.success) { expect(commissionPrice(parsed.data)).toBe(100); expect(parsed.data.teams[0].members[0]).toMatchObject({ constellation: "0", refinement: "1" }); } }); it("keeps selected team constellation and refinement ranges", () => { const selected = { ...request, teams: [{ members: request.teams[0].members.map((member, index) => index === 0 ? { ...member, constellation: "0-6", refinement: "1-5" } : member) }] }; expect(commissionRequestSchema.parse(selected).teams[0].members[0]).toMatchObject({ constellation: "0-6", refinement: "1-5", }); expect(commissionRequestSchema.safeParse({ ...selected, teams: [{ members: selected.teams[0].members.map((member, index) => index === 0 ? { ...member, refinement: "6" } : member) }] }).success).toBe(false); }); it("keeps each compared weapon's refinement and defaults older requests to R1", () => { const selected = { ...request, weapons: [{ characterKey: "a", weaponKeys: ["weapon-a", "weapon-b"], refinements: { "weapon-a": "5", "weapon-b": "2" } }] }; expect(commissionRequestSchema.parse(selected).weapons[0].refinements).toEqual({ "weapon-a": "5", "weapon-b": "2", }); expect(commissionPrice(commissionRequestSchema.parse(selected))).toBe(180); expect(commissionRequestSchema.parse(request).weapons[0].refinements).toBeUndefined(); expect(commissionRequestSchema.safeParse({ ...selected, weapons: [{ ...selected.weapons[0], refinements: { "weapon-a": "6" } }] }).success).toBe(false); expect(commissionRequestSchema.safeParse({ ...selected, weapons: [{ ...selected.weapons[0], refinements: { "weapon-c": "3" } }] }).success).toBe(false); }); it("prices independent request types together", () => { expect(commissionPrice(commissionRequestSchema.parse(request))).toBe(200); expect(commissionPrice(commissionRequestSchema.parse({ teams: [], weapons: [], constellations: [{ characterKey: "a", levels: [0, 1] }] }))).toBe(140); expect(commissionPrice(commissionRequestSchema.parse({ teams: [], weapons: [], constellations: [{ characterKey: "a", levels: [0] }] }))).toBe(120); expect(commissionPrice(commissionRequestSchema.parse({ teams: [], weapons: [ { characterKey: "a", weaponKeys: ["weapon-a", "weapon-b"] }, ], constellations: [] }))).toBe(140); expect(commissionPrice({ teams: [], weapons: [{ characterKey: "a", weaponKeys: ["weapon-a", "", ""] }], constellations: [] })).toBe(120); expect(commissionPrice(commissionRequestSchema.parse({ teams: request.teams.concat(request.teams), weapons: [], constellations: [] }))).toBe(200); expect(commissionPrice({ teams: [], weapons: [], constellations: [] })).toBe(0); }); it("requires four distinct team characters and valid comparison choices", () => { expect(commissionRequestSchema.safeParse({ ...request, teams: [{ members: [ ...request.teams[0].members.slice(0, 3), request.teams[0].members[0], ] }] }).success).toBe(false); expect(commissionRequestSchema.safeParse({ ...request, weapons: [{ characterKey: "a", weaponKeys: ["weapon-a"] }] }).success).toBe(false); expect(commissionRequestSchema.safeParse({ ...request, constellations: [{ characterKey: "a", levels: [0, 0] }] }).success).toBe(false); expect(commissionRequestSchema.safeParse({ ...request, constellations: [{ characterKey: "a", levels: [] }] }).success).toBe(false); }); });