test(polls): cover merged partial updates

This commit is contained in:
Simo committed 2026-09-01 22:29:16 +02:00
1 parent abb04f8362
commit e69633b753
1 file changed
+122
+122
View File
@@ -0,0 +1,122 @@
// @ts-nocheck
import { beforeEach, describe, expect, it, vi } from "vitest";
const { selectLimit, updateSet, updateWhere } = vi.hoisted(() => ({
selectLimit: vi.fn(),
updateSet: vi.fn(() => ({ where: updateWhere })),
updateWhere: vi.fn(),
}));
vi.mock("@/lib/db", () => ({
db: {
select: vi.fn(() => ({
from: vi.fn(() => ({
where: vi.fn(() => ({ limit: selectLimit })),
})),
})),
update: vi.fn(() => ({ set: updateSet })),
},
WebsitePoll: {
id: "id",
title: "title",
description: "description",
status: "status",
showResults: "showResults",
multipleChoice: "multipleChoice",
startsAt: "startsAt",
endsAt: "endsAt",
},
WebsitePollQuestion: {
id: "id",
pollId: "pollId",
question: "question",
type: "type",
sortOrder: "sortOrder",
options: "options",
},
WebsitePollVote: { id: "id", questionId: "questionId", userId: "userId" },
}));
vi.mock("@/lib/permissions", () => ({ PERMS: { POLLS_EDIT: "polls.edit" } }));
vi.mock("@/lib/services/audit", () => ({ logAudit: vi.fn() }));
vi.mock("next/cache", () => ({ revalidatePath: vi.fn() }));
vi.mock("@/lib/safe-action", () => ({
adminAction: (options, handler) => async (input) => {
const parsed = options.schema.safeParse(input);
if (!parsed.success) return { ok: false, error: "Validation failed" };
try {
return await handler({
data: parsed.data,
session: { user: { id: "1" } },
});
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error.message : "Internal server error",
};
}
},
authAction: vi.fn(),
}));
vi.mock("@/lib/safe-action-shared", () => ({
actionOk: (data) => ({ ok: true, data: data ?? {} }),
actionError: (error) => ({ ok: false, error }),
ActionError: class ActionError extends Error {
constructor(message) {
super(message);
this.name = "ActionError";
}
},
}));
import { updatePoll, updatePollQuestion } from "./polls";
beforeEach(() => {
vi.clearAllMocks();
selectLimit.mockReset();
updateSet.mockClear();
updateWhere.mockClear();
});
describe("poll update merge validation", () => {
it("rejects a partial end time before the persisted start without updating", async () => {
selectLimit.mockResolvedValueOnce([
{
id: 1,
title: "Schedule",
description: null,
status: "draft",
showResults: 1,
multipleChoice: 0,
startsAt: new Date("2026-09-02T12:00:00.000Z"),
endsAt: null,
},
]);
const result = await updatePoll({
id: 1,
endsAt: "2026-09-02T11:59:00.000Z",
});
expect(result).toEqual({ ok: false, error: "Invalid poll schedule" });
expect(updateSet).not.toHaveBeenCalled();
});
it("rejects a partial options patch for a persisted text question without updating", async () => {
selectLimit.mockResolvedValueOnce([
{
pollId: 1,
question: "Why?",
type: "text",
sortOrder: 0,
options: "",
},
]);
const result = await updatePollQuestion({ id: 1, options: "Not allowed" });
expect(result).toEqual({ ok: false, error: "Invalid poll question" });
expect(updateSet).not.toHaveBeenCalled();
});
});