3ccd1262f9
基于 Vitest 搭建测试基础设施,覆盖后端纯函数、API 路由、 前端 hooks、UI 组件和页面级集成测试。
100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import { prismaMock, resetPrismaMock } from "@/__tests__/helpers/prisma-mock";
|
|
import { createRequest, parseJsonResponse } from "@/__tests__/helpers/api-test-utils";
|
|
import { TEST_USER } from "@/__tests__/helpers/fixtures";
|
|
|
|
vi.mock("@/lib/blindbox", () => ({
|
|
requireMembership: vi.fn().mockResolvedValue({}),
|
|
}));
|
|
|
|
import { POST } from "./route";
|
|
|
|
const mockCtx = { params: Promise.resolve({}) };
|
|
|
|
beforeEach(() => {
|
|
resetPrismaMock();
|
|
});
|
|
|
|
describe("POST /api/blindbox/draw", () => {
|
|
it("draws a random idea", async () => {
|
|
prismaMock.$transaction.mockImplementation(async (fn: (tx: unknown) => Promise<unknown>) => {
|
|
const tx = {
|
|
blindBoxIdea: {
|
|
findMany: vi.fn().mockResolvedValue([{ id: "idea-1" }]),
|
|
updateMany: vi.fn().mockResolvedValue({ count: 1 }),
|
|
findUnique: vi.fn().mockResolvedValue({
|
|
id: "idea-1",
|
|
content: "去公园",
|
|
createdAt: new Date(),
|
|
user: { id: "user-2", username: "submitter", avatar: "🐶" },
|
|
drawnBy: { id: "user-1", username: "drawer", avatar: "🐱" },
|
|
}),
|
|
},
|
|
};
|
|
return fn(tx);
|
|
});
|
|
|
|
const req = createRequest("/api/blindbox/draw", {
|
|
method: "POST",
|
|
body: { roomId: "bb-room-1", userId: "user-1" },
|
|
});
|
|
const res = await POST(req, mockCtx);
|
|
const { status, data } = await parseJsonResponse(res);
|
|
|
|
expect(status).toBe(200);
|
|
expect(data.id).toBe("idea-1");
|
|
expect(data.content).toBe("去公园");
|
|
expect(data.submitter).toBeDefined();
|
|
expect(data.drawnBy).toBeDefined();
|
|
});
|
|
|
|
it("returns 404 when pool is empty", async () => {
|
|
prismaMock.$transaction.mockImplementation(async (fn: (tx: unknown) => Promise<unknown>) => {
|
|
const tx = {
|
|
blindBoxIdea: {
|
|
findMany: vi.fn().mockResolvedValue([]),
|
|
updateMany: vi.fn(),
|
|
findUnique: vi.fn(),
|
|
},
|
|
};
|
|
return fn(tx);
|
|
});
|
|
|
|
const req = createRequest("/api/blindbox/draw", {
|
|
method: "POST",
|
|
body: { roomId: "bb-room-1", userId: "user-1" },
|
|
});
|
|
const res = await POST(req, mockCtx);
|
|
expect(res.status).toBe(404);
|
|
});
|
|
|
|
it("returns 409 on race condition (count=0)", async () => {
|
|
prismaMock.$transaction.mockImplementation(async (fn: (tx: unknown) => Promise<unknown>) => {
|
|
const tx = {
|
|
blindBoxIdea: {
|
|
findMany: vi.fn().mockResolvedValue([{ id: "idea-1" }]),
|
|
updateMany: vi.fn().mockResolvedValue({ count: 0 }),
|
|
findUnique: vi.fn(),
|
|
},
|
|
};
|
|
return fn(tx);
|
|
});
|
|
|
|
const req = createRequest("/api/blindbox/draw", {
|
|
method: "POST",
|
|
body: { roomId: "bb-room-1", userId: "user-1" },
|
|
});
|
|
const res = await POST(req, mockCtx);
|
|
expect(res.status).toBe(409);
|
|
});
|
|
|
|
it("returns 400 when roomId is missing", async () => {
|
|
const req = createRequest("/api/blindbox/draw", {
|
|
method: "POST",
|
|
body: { userId: "user-1" },
|
|
});
|
|
const res = await POST(req, mockCtx);
|
|
expect(res.status).toBe(400);
|
|
});
|
|
});
|