feat: add inspection task lifecycle controls
This commit is contained in:
119
server/inspectionTask.test.ts
Normal file
119
server/inspectionTask.test.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { appRouter } from "./routers";
|
||||
import * as db from "./db";
|
||||
import type { TrpcContext } from "./_core/context";
|
||||
|
||||
vi.mock("./db", () => ({
|
||||
findInspectionTaskByModelAndName: vi.fn(async () => undefined),
|
||||
createInspectionTask: vi.fn(async (data) => ({
|
||||
id: 1,
|
||||
modelId: data.modelId,
|
||||
name: data.name,
|
||||
inspector: data.inspector ?? null,
|
||||
notes: data.notes ?? null,
|
||||
status: data.status,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
completedAt: null,
|
||||
})),
|
||||
}));
|
||||
|
||||
type AuthenticatedUser = NonNullable<TrpcContext["user"]>;
|
||||
|
||||
function createAuthContext(): TrpcContext {
|
||||
const user: AuthenticatedUser = {
|
||||
id: 1,
|
||||
openId: "test-user",
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
loginMethod: "manus",
|
||||
role: "user",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
lastSignedIn: new Date(),
|
||||
};
|
||||
|
||||
return {
|
||||
user,
|
||||
req: {
|
||||
protocol: "https",
|
||||
headers: {},
|
||||
} as TrpcContext["req"],
|
||||
res: {
|
||||
clearCookie: vi.fn(),
|
||||
} as unknown as TrpcContext["res"],
|
||||
};
|
||||
}
|
||||
|
||||
describe("inspection task router", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(db.findInspectionTaskByModelAndName).mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
it("trims name and creates a task in created status", async () => {
|
||||
const ctx = createAuthContext();
|
||||
const caller = appRouter.createCaller(ctx);
|
||||
|
||||
const result = await caller.inspectionTask.create({
|
||||
modelId: 1,
|
||||
name: " 首检任务 ",
|
||||
});
|
||||
|
||||
expect(result.status).toBe("created");
|
||||
expect(db.findInspectionTaskByModelAndName).toHaveBeenCalledWith(1, "首检任务");
|
||||
expect(db.createInspectionTask).toHaveBeenCalledWith({
|
||||
modelId: 1,
|
||||
name: "首检任务",
|
||||
inspector: null,
|
||||
notes: null,
|
||||
status: "created",
|
||||
});
|
||||
});
|
||||
|
||||
it("returns CONFLICT when the same model already has the task name", async () => {
|
||||
vi.mocked(db.findInspectionTaskByModelAndName).mockResolvedValueOnce({
|
||||
id: 1,
|
||||
modelId: 1,
|
||||
name: "首检任务",
|
||||
inspector: null,
|
||||
notes: null,
|
||||
status: "created",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
completedAt: null,
|
||||
});
|
||||
|
||||
const ctx = createAuthContext();
|
||||
const caller = appRouter.createCaller(ctx);
|
||||
|
||||
await expect(caller.inspectionTask.create({
|
||||
modelId: 1,
|
||||
name: "首检任务",
|
||||
})).rejects.toMatchObject({
|
||||
code: "CONFLICT",
|
||||
message: "该车型下已存在同名检测任务。",
|
||||
});
|
||||
|
||||
expect(db.createInspectionTask).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns CONFLICT when the database unique key rejects a concurrent duplicate", async () => {
|
||||
vi.mocked(db.createInspectionTask).mockRejectedValueOnce({
|
||||
code: "ER_DUP_ENTRY",
|
||||
errno: 1062,
|
||||
message: "Duplicate entry '1-首检任务' for key 'uk_inspection_tasks_model_name'",
|
||||
});
|
||||
|
||||
const ctx = createAuthContext();
|
||||
const caller = appRouter.createCaller(ctx);
|
||||
|
||||
await expect(caller.inspectionTask.create({
|
||||
modelId: 1,
|
||||
name: "首检任务",
|
||||
})).rejects.toMatchObject({
|
||||
code: "CONFLICT",
|
||||
message: "该车型下已存在同名检测任务。",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user