Files
EpicNext-Cms/src/actions/article-recovery.test.ts
T
Simo c389c3893d
CI / check (push) Successful in 52s
CI / deploy (push) Successful in 2m10s
CI / publish-container (push) Failing after 1m18s
feat(cms): improve catalog, editorial recovery and operations
2026-09-09 19:36:15 +02:00

84 lines
2.6 KiB
TypeScript

import { beforeEach, expect, it, vi } from "vitest";
const state = vi.hoisted(() => ({
version: 0,
update: vi.fn(),
insert: vi.fn(),
permission: vi.fn(),
}));
vi.mock("@/lib/admin/guard", () => ({ requirePermission: state.permission }));
vi.mock("@/lib/permissions", () => ({ PERMS: { NEWS_EDIT: "news.edit" } }));
vi.mock("@/lib/db", async () => {
const tx = {
insert: (table: unknown) => ({
values: (value: unknown) => {
state.insert(table, value);
return { onDuplicateKeyUpdate: async () => {} };
},
}),
select: () => ({
from: () => ({
where: () => ({ for: async () => [{ version: state.version }] }),
}),
}),
update: (table: unknown) => ({
set: (value: unknown) => {
state.update(table, value);
return { where: async () => {} };
},
}),
};
return {
...(await import("@/db/schema")),
db: { transaction: async (fn: (value: typeof tx) => unknown) => fn(tx) },
};
});
import { ArticleDrafts } from "@/db/article-editor";
import { autosaveArticle } from "./article-recovery";
function draft() {
const form = new FormData();
form.set("title", "Incomplete title");
form.set("status", "published");
form.set("fullStory", "Work in progress");
return form;
}
beforeEach(() => {
vi.clearAllMocks();
state.version = 0;
state.permission.mockResolvedValue({ id: 17 });
});
it("stores incomplete editor content only in a private draft table even when publication is selected", async () => {
expect(await autosaveArticle("new", 0, draft())).toEqual({
ok: true,
version: 1,
});
expect(state.permission).toHaveBeenCalledWith("news.edit");
expect(state.insert).toHaveBeenCalledWith(
ArticleDrafts,
expect.objectContaining({ userId: 17, articleKey: "new" }),
);
expect(state.update).toHaveBeenCalledOnce();
expect(state.update).toHaveBeenCalledWith(
ArticleDrafts,
expect.objectContaining({ version: 1 }),
);
});
it("does not replace a more recent draft from another tab", async () => {
state.version = 4;
expect(await autosaveArticle("new", 3, draft())).toEqual({ ok: false });
expect(state.update).not.toHaveBeenCalled();
});
it("does not access storage when the editor permission is denied", async () => {
state.permission.mockRejectedValue(new Error("denied"));
await expect(autosaveArticle("new", 0, draft())).rejects.toThrow("denied");
expect(state.insert).not.toHaveBeenCalled();
});
it("rejects excessive article content before writing", async () => {
const form = draft();
form.set("fullStory", "x".repeat(500_001));
await expect(autosaveArticle("new", 0, form)).rejects.toThrow("draftInvalid");
expect(state.insert).not.toHaveBeenCalled();
});