Ship product gaps: register/vote pages, friend add/accept/decline/remove, email verify TTL, captcha on login/forgot, soft-fail user actions, SSE abort/shared client, Commando Centrum error toasts, admin delete for events/polls, and IT/NL i18n fills. Co-authored-by: Cursor <[email protected]>
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mockGet = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock("@/lib/services/site-settings", () => ({
|
|
siteSettings: { get: mockGet },
|
|
}));
|
|
|
|
import { captchaConfig, verifyCaptcha } from "./captcha";
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
describe("verifyCaptcha", () => {
|
|
it("allows when provider is none", async () => {
|
|
mockGet.mockImplementation(async (key: string, fallback?: string) => {
|
|
if (key === "captcha_provider") return "none";
|
|
return fallback ?? "";
|
|
});
|
|
expect(await verifyCaptcha(null)).toBe(true);
|
|
});
|
|
|
|
it("fails closed when provider set but secret missing", async () => {
|
|
mockGet.mockImplementation(async (key: string, fallback?: string) => {
|
|
if (key === "captcha_provider") return "turnstile";
|
|
if (key === "turnstile_site_key") return "site-key";
|
|
if (key === "turnstile_secret") return "";
|
|
return fallback ?? "";
|
|
});
|
|
expect(await verifyCaptcha("tok")).toBe(false);
|
|
});
|
|
|
|
it("fails closed on provider API/network errors", async () => {
|
|
mockGet.mockImplementation(async (key: string, fallback?: string) => {
|
|
if (key === "captcha_provider") return "turnstile";
|
|
if (key === "turnstile_site_key") return "site-key";
|
|
if (key === "turnstile_secret") return "secret";
|
|
return fallback ?? "";
|
|
});
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn().mockRejectedValue(new Error("network down")),
|
|
);
|
|
expect(await verifyCaptcha("tok", "1.2.3.4")).toBe(false);
|
|
});
|
|
|
|
it("accepts a successful provider response", async () => {
|
|
mockGet.mockImplementation(async (key: string, fallback?: string) => {
|
|
if (key === "captcha_provider") return "recaptcha";
|
|
if (key === "recaptcha_site_key") return "site-key";
|
|
if (key === "recaptcha_secret") return "secret";
|
|
return fallback ?? "";
|
|
});
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
json: async () => ({ success: true }),
|
|
}),
|
|
);
|
|
expect(await verifyCaptcha("good-token")).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("captchaConfig", () => {
|
|
it("returns none by default", async () => {
|
|
mockGet.mockImplementation(async (_key: string, fallback?: string) => {
|
|
return fallback ?? "none";
|
|
});
|
|
const cfg = await captchaConfig();
|
|
expect(cfg.provider).toBe("none");
|
|
});
|
|
});
|