tests: add coverage for src/actions/ (15 files) and src/lib/{admin,auth} (3 files)

- src/actions coverage: 2.4% -> 13.55%
- src/lib/admin coverage: 44.3% -> 84.81%
- src/lib/auth coverage: 90.52%
- vitest.config.ts: exclude .next.prev/ from test discovery
This commit is contained in:
openhands committed 2026-07-30 18:48:51 +02:00
1 parent c433e5a52f
commit ea7d861e69
19 files changed
+1262 -1

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { requirePermission } from "@/lib/admin/guard";
import { logger } from "@/lib/logger";
import { PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { ActionError } from "@/lib/safe-action-shared";
import { logStaffActivity } from "@/lib/services/staff-activity";
import { createAd, deleteAd, deleteAdForm, updateAd } from "./admin-ads";
vi.mock("@/lib/admin/guard", () => ({ requirePermission: vi.fn() }));
vi.mock("@/lib/permissions", () => ({ PERMS: { PAGES_EDIT: "pages.edit" } }));
vi.mock("@/lib/prisma", () => ({
prisma: { websiteAds: { create: vi.fn(), update: vi.fn(), delete: vi.fn() } },
}));
vi.mock("@/lib/logger", () => ({ logger: { error: vi.fn() } }));
vi.mock("@/lib/safe-action", () => ({
adminAction: vi.fn((_opts: unknown, fn: Function) => fn),
}));
vi.mock("@/lib/safe-action-shared", () => ({
ActionError: class extends Error {},
actionOk: vi.fn(() => "ok"),
}));
vi.mock("@/lib/services/staff-activity", () => ({ logStaffActivity: vi.fn() }));
vi.mock("next/cache", () => ({ revalidatePath: vi.fn() }));
vi.mock("next/navigation", () => ({ redirect: vi.fn() }));
const staff = { id: 1, rank: 7, username: "admin" };
const fakeForm = (data: Record<string, string>) => ({
get: (key: string) => data[key] ?? null,
});
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(requirePermission).mockResolvedValue(staff as never);
});
describe("createAd", () => {
it("creates an ad and redirects", async () => {
vi.mocked(prisma.websiteAds.create).mockResolvedValue({
id: BigInt(1),
} as never);
await createAd(
fakeForm({ image: "https://example.com/ad.png" }) as unknown as FormData,
);
expect(prisma.websiteAds.create).toHaveBeenCalledWith({
data: expect.objectContaining({ image: "https://example.com/ad.png" }),
});
expect(logStaffActivity).toHaveBeenCalled();
expect(redirect).toHaveBeenCalledWith("/admin/ads");
});
it("returns early when image is empty", async () => {
await createAd(fakeForm({ image: "" }) as unknown as FormData);
expect(prisma.websiteAds.create).not.toHaveBeenCalled();
});
it("logs error and revalidates on db failure", async () => {
vi.mocked(prisma.websiteAds.create).mockRejectedValue(new Error("DB down"));
await createAd(fakeForm({ image: "x" }) as unknown as FormData);
expect(logger.error).toHaveBeenCalled();
expect(revalidatePath).toHaveBeenCalledWith("/admin/ads");
});
});
describe("deleteAd", () => {
it("deletes an ad via adminAction", async () => {
const handler = deleteAd as unknown as (ctx: {
data: { id: bigint };
session: { user: { id: string } };
}) => Promise<string>;
vi.mocked(prisma.websiteAds.delete).mockResolvedValue({} as never);
const result = await handler({
data: { id: BigInt(99) },
session: { user: { id: "1" } },
});
expect(prisma.websiteAds.delete).toHaveBeenCalledWith({
where: { id: BigInt(99) },
});
expect(result).toBe("ok");
});
});