67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const selectFrom = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock("@/lib/db", () => ({
|
|
db: {
|
|
select: () => ({
|
|
from: () => Promise.resolve(selectFrom()),
|
|
}),
|
|
},
|
|
WebsiteWordfilter: { word: "WebsiteWordfilter.word" },
|
|
}));
|
|
|
|
vi.mock("@/env", () => ({
|
|
env: {
|
|
OPENAI_API_KEY: undefined,
|
|
},
|
|
}));
|
|
|
|
import { isAllowed, moderateOrThrow, reloadWordFilter } from "./moderation";
|
|
|
|
beforeEach(() => {
|
|
selectFrom.mockReset();
|
|
reloadWordFilter();
|
|
});
|
|
|
|
describe("moderation", () => {
|
|
it("allows clean text", async () => {
|
|
selectFrom.mockResolvedValue([{ word: "badword" }]);
|
|
const result = await isAllowed("hello world");
|
|
expect(result).toEqual({ ok: true });
|
|
});
|
|
|
|
it("blocks text containing a filtered word", async () => {
|
|
selectFrom.mockResolvedValue([{ word: "badword" }]);
|
|
const result = await isAllowed("this contains badword here");
|
|
expect(result).toEqual({
|
|
ok: false,
|
|
reason: 'Blocked by word filter: "badword"',
|
|
});
|
|
});
|
|
|
|
it("allows empty text", async () => {
|
|
const result = await isAllowed("");
|
|
expect(result).toEqual({ ok: true });
|
|
});
|
|
|
|
it("caches the word list and respects TTL", async () => {
|
|
selectFrom.mockResolvedValue([{ word: "first" }]);
|
|
await isAllowed("test");
|
|
await isAllowed("test");
|
|
expect(selectFrom).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("moderateOrThrow throws on blocked content", async () => {
|
|
selectFrom.mockResolvedValue([{ word: "bad" }]);
|
|
await expect(moderateOrThrow("this is bad")).rejects.toThrow(
|
|
"Blocked by word filter",
|
|
);
|
|
});
|
|
|
|
it("moderateOrThrow resolves on clean content", async () => {
|
|
selectFrom.mockResolvedValue([{ word: "bad" }]);
|
|
await expect(moderateOrThrow("clean text")).resolves.toBeUndefined();
|
|
});
|
|
});
|