test: add action-helper, send-currency, permission-ranks, catalog-tree, and audit test suites (77 files, 405 tests)
This commit is contained in:
1 parent
2e9db75eca
commit
ac3c42f308
4 files changed
+398
-75
No files matched your search
@@ -0,0 +1,158 @@
|
||||
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||
|
||||
const findUnique = vi.hoisted(() => vi.fn());
|
||||
const findMany = vi.hoisted(() => vi.fn());
|
||||
const update = vi.hoisted(() => vi.fn());
|
||||
const create = vi.hoisted(() => vi.fn());
|
||||
const queryRaw = vi.hoisted(() => vi.fn());
|
||||
const executeRaw = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("@/lib/prisma", () => ({
|
||||
prisma: {
|
||||
catalogPages: { findUnique, findMany, update, create },
|
||||
$queryRaw: queryRaw,
|
||||
$executeRaw: executeRaw,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("@/env", () => ({ env: {} }));
|
||||
|
||||
import { buildNestedTree, toInt, movePage, deletePage, getAncestors, createPage } from "./catalog-tree";
|
||||
import type { TreeNode } from "@/types/catalog";
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("toInt", () => {
|
||||
it("converts valid numbers", () => {
|
||||
expect(toInt(42)).toBe(42);
|
||||
expect(toInt("42")).toBe(42);
|
||||
});
|
||||
|
||||
it("uses fallback for invalid", () => {
|
||||
expect(toInt("abc", -1)).toBe(-1);
|
||||
expect(toInt(NaN, 0)).toBe(0);
|
||||
});
|
||||
|
||||
it("defaults fallback to 0", () => {
|
||||
expect(toInt("abc")).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildNestedTree", () => {
|
||||
const flat: TreeNode[] = [
|
||||
{ id: 1, caption: "Root", parentId: -1, depth: 0, orderNum: 1, enabled: "1", visible: "1", iconImage: 0, iconColor: 0, pageLayout: "default_3x3", childCount: 2, itemCount: 0 },
|
||||
{ id: 2, caption: "Child", parentId: 1, depth: 1, orderNum: 1, enabled: "1", visible: "1", iconImage: 0, iconColor: 0, pageLayout: "default_3x3", childCount: 1, itemCount: 5 },
|
||||
{ id: 3, caption: "Grandchild", parentId: 2, depth: 2, orderNum: 1, enabled: "1", visible: "1", iconImage: 0, iconColor: 0, pageLayout: "default_3x3", childCount: 0, itemCount: 0 },
|
||||
];
|
||||
|
||||
it("builds nested tree from flat nodes", () => {
|
||||
const tree = buildNestedTree(flat);
|
||||
expect(tree).toHaveLength(1);
|
||||
expect(tree[0].id).toBe(1);
|
||||
expect(tree[0].children).toHaveLength(1);
|
||||
expect(tree[0].children[0].children[0].id).toBe(3);
|
||||
});
|
||||
|
||||
it("returns empty array for empty input", () => {
|
||||
expect(buildNestedTree([])).toEqual([]);
|
||||
});
|
||||
|
||||
it("uses custom rootParentId", () => {
|
||||
expect(buildNestedTree(flat, 999)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createPage", () => {
|
||||
it("creates page with default values", async () => {
|
||||
create.mockResolvedValue({ id: 1 });
|
||||
await createPage({ parentId: 0, caption: "Test" });
|
||||
|
||||
const data = create.mock.calls[0][0].data;
|
||||
expect(data.caption).toBe("Test");
|
||||
expect(data.pageLayout).toBe("default_3x3");
|
||||
expect(data.visible).toBe("1");
|
||||
expect(data.enabled).toBe("1");
|
||||
expect(data.clubOnly).toBe("0");
|
||||
expect(data.minRank).toBe(1);
|
||||
});
|
||||
|
||||
it("truncates captionSave to 25 chars", async () => {
|
||||
create.mockResolvedValue({ id: 1 });
|
||||
await createPage({ parentId: 0, caption: "a".repeat(50) });
|
||||
|
||||
expect(create.mock.calls[0][0].data.captionSave).toBe("a".repeat(25));
|
||||
});
|
||||
|
||||
it("converts boolean visible/enabled to string", async () => {
|
||||
create.mockResolvedValue({ id: 1 });
|
||||
await createPage({ parentId: 0, caption: "x", visible: false, enabled: false });
|
||||
expect(create.mock.calls[0][0].data.visible).toBe("0");
|
||||
expect(create.mock.calls[0][0].data.enabled).toBe("0");
|
||||
});
|
||||
});
|
||||
|
||||
describe("movePage", () => {
|
||||
it("throws on circular hierarchy", async () => {
|
||||
findUnique.mockResolvedValue({ parentId: 1 });
|
||||
await expect(movePage(1, 2)).rejects.toThrow("circular hierarchy");
|
||||
});
|
||||
|
||||
it("allows valid move to root", async () => {
|
||||
update.mockResolvedValue({});
|
||||
await movePage(1, 0);
|
||||
expect(update).toHaveBeenCalledWith({
|
||||
where: { id: 1 },
|
||||
data: { parentId: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("allows valid move to other parent", async () => {
|
||||
findUnique.mockResolvedValue({ parentId: 0 });
|
||||
update.mockResolvedValue({});
|
||||
await movePage(1, 2);
|
||||
expect(update).toHaveBeenCalledWith({
|
||||
where: { id: 1 },
|
||||
data: { parentId: 2 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAncestors", () => {
|
||||
it("returns breadcrumb from root to page", async () => {
|
||||
findUnique
|
||||
.mockResolvedValueOnce({ id: 3, caption: "Grandchild", parentId: 2 })
|
||||
.mockResolvedValueOnce({ id: 2, caption: "Child", parentId: 1 })
|
||||
.mockResolvedValueOnce({ id: 1, caption: "Root", parentId: 0 });
|
||||
|
||||
const ancestors = await getAncestors(3);
|
||||
expect(ancestors).toHaveLength(3);
|
||||
expect(ancestors[0].caption).toBe("Root");
|
||||
expect(ancestors[1].caption).toBe("Child");
|
||||
expect(ancestors[2].caption).toBe("Grandchild");
|
||||
});
|
||||
|
||||
it("stops when page not found", async () => {
|
||||
findUnique.mockResolvedValue(null);
|
||||
expect(await getAncestors(999)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("deletePage", () => {
|
||||
it("reparent mode moves children to parent", async () => {
|
||||
findUnique.mockResolvedValue({ parentId: 1 });
|
||||
const deleteFn = vi.fn().mockResolvedValue({});
|
||||
const updateMany = vi.fn().mockResolvedValue({ count: 2 });
|
||||
const prisma = await import("@/lib/prisma").then((m) => m.prisma as any);
|
||||
prisma.catalogPages.delete = deleteFn;
|
||||
prisma.catalogPages.updateMany = updateMany;
|
||||
|
||||
const result = await deletePage(5, "reparent");
|
||||
expect(result).toEqual({ deletedPages: 1, movedChildren: 2 });
|
||||
expect(updateMany).toHaveBeenCalledWith({
|
||||
where: { parentId: 5 },
|
||||
data: { parentId: 1 },
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user