fix(news): restore publication flow and deduplicate dashboard friends
This commit is contained in:
1 parent
ef94646d60
commit
9b0ea2fb16
22 files changed
+638
-195
No files matched your search
@@ -0,0 +1,116 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const state = vi.hoisted(() => ({
|
||||
rows: [] as unknown[][],
|
||||
insert: vi.fn(),
|
||||
update: vi.fn(),
|
||||
invalidate: vi.fn(),
|
||||
log: vi.fn(() => "news-error-1"),
|
||||
notify: vi.fn(),
|
||||
}));
|
||||
vi.mock("@/lib/admin/guard", () => ({
|
||||
requirePermission: async () => ({ id: 1, username: "staff" }),
|
||||
}));
|
||||
vi.mock("@/lib/permissions", () => ({ PERMS: { NEWS_EDIT: "news.edit" } }));
|
||||
vi.mock("@/lib/services/webhook", () => ({ notify: state.notify }));
|
||||
vi.mock("@/lib/services/news-cache", () => ({
|
||||
invalidateNewsCache: state.invalidate,
|
||||
}));
|
||||
vi.mock("@/lib/logger", () => ({ logger: { error: state.log } }));
|
||||
vi.mock("next-intl/server", () => ({
|
||||
getTranslations: async () => (key: string, args?: { reference: string }) =>
|
||||
key + (args?.reference ?? ""),
|
||||
}));
|
||||
vi.mock("next/cache", () => ({ revalidatePath: vi.fn() }));
|
||||
vi.mock("next/navigation", () => ({
|
||||
redirect: (url: string) => {
|
||||
throw Error(`redirect ${url}`);
|
||||
},
|
||||
}));
|
||||
vi.mock("@/lib/db", async () => ({
|
||||
...(await import("@/db/schema")),
|
||||
db: {
|
||||
select: () => ({
|
||||
from: () => ({
|
||||
where: () => ({ limit: async () => state.rows.shift() ?? [] }),
|
||||
}),
|
||||
}),
|
||||
insert: () => ({ values: state.insert }),
|
||||
update: () => ({
|
||||
set: (value: unknown) => {
|
||||
state.update(value);
|
||||
return { where: async () => [{ affectedRows: 1 }] };
|
||||
},
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
import { createArticle, updateArticle } from "./admin-articles";
|
||||
|
||||
function form(extra: Record<string, string> = {}) {
|
||||
const f = new FormData();
|
||||
for (const [k, v] of Object.entries({
|
||||
title: "Test news",
|
||||
slug: "test-news",
|
||||
shortStory: "Summary",
|
||||
fullStory: "Body",
|
||||
status: "published",
|
||||
...extra,
|
||||
}))
|
||||
f.set(k, v);
|
||||
return f;
|
||||
}
|
||||
describe("news saves", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
state.rows = [];
|
||||
state.insert.mockResolvedValue([{ insertId: 1 }]);
|
||||
});
|
||||
it("preserves a recoverable error and logs its reference", async () => {
|
||||
state.insert.mockRejectedValueOnce(Error("Unknown column status"));
|
||||
const result = await createArticle(form());
|
||||
expect(result).toEqual({
|
||||
ok: false,
|
||||
error: "saveFailedReferencenews-error-1",
|
||||
});
|
||||
expect(state.invalidate).not.toHaveBeenCalled();
|
||||
expect(state.log).toHaveBeenCalled();
|
||||
});
|
||||
it("saves drafts without publication notifications", async () => {
|
||||
expect((await createArticle(form({ status: "draft" }))).ok).toBe(true);
|
||||
expect(state.insert).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
status: "draft",
|
||||
publishAt: null,
|
||||
publishedAt: null,
|
||||
}),
|
||||
);
|
||||
expect(state.notify).not.toHaveBeenCalled();
|
||||
expect(state.invalidate).toHaveBeenCalledOnce();
|
||||
});
|
||||
it("preserves the slug and clears old scheduling for immediate publication", async () => {
|
||||
state.rows = [[{ slug: "test-news", status: "draft", publishedAt: null }]];
|
||||
expect(
|
||||
(
|
||||
await updateArticle(
|
||||
form({ id: "1", publishAt: "2099-01-01T00:00:00Z" }),
|
||||
)
|
||||
).ok,
|
||||
).toBe(true);
|
||||
expect(state.update).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
slug: "test-news",
|
||||
publishAt: null,
|
||||
status: "published",
|
||||
}),
|
||||
);
|
||||
expect(state.invalidate).toHaveBeenCalledOnce();
|
||||
});
|
||||
it("rejects invalid scheduled dates before writing", async () => {
|
||||
expect(
|
||||
(await createArticle(form({ status: "scheduled", publishAt: "invalid" })))
|
||||
.ok,
|
||||
).toBe(false);
|
||||
expect(state.insert).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user