the universal sandbox runtime for agents and humans.
pocketenv.io
sandbox
openclaw
agent
claude-code
vercel-sandbox
deno-sandbox
cloudflare-sandbox
atproto
sprites
daytona
1import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
3vi.mock("../../lib/env", () => ({
4 env: {
5 CF_SECRET_KEY: "test-secret-key",
6 },
7}));
8
9// Import after mock is set up
10const { default: validateTurnstile } = await import("../../lib/turnstile");
11
12describe("validateTurnstile", () => {
13 beforeEach(() => {
14 vi.stubGlobal(
15 "fetch",
16 vi.fn().mockResolvedValue({
17 json: vi.fn().mockResolvedValue({ success: true }),
18 }),
19 );
20 });
21
22 afterEach(() => {
23 vi.unstubAllGlobals();
24 });
25
26 it("calls the Cloudflare siteverify endpoint", async () => {
27 await validateTurnstile("token123", "1.2.3.4");
28
29 expect(fetch).toHaveBeenCalledWith(
30 "https://challenges.cloudflare.com/turnstile/v0/siteverify",
31 expect.objectContaining({ method: "POST" }),
32 );
33 });
34
35 it("sends the secret, token, and remoteip in the request body", async () => {
36 await validateTurnstile("my-token", "10.0.0.1");
37
38 const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0];
39 const body = JSON.parse(init.body);
40
41 expect(body).toEqual({
42 secret: "test-secret-key",
43 response: "my-token",
44 remoteip: "10.0.0.1",
45 });
46 });
47
48 it("returns the parsed JSON response on success", async () => {
49 const result = await validateTurnstile("token", "0.0.0.0");
50 expect(result).toEqual({ success: true });
51 });
52
53 it("returns a failure object when fetch throws", async () => {
54 vi.stubGlobal("fetch", vi.fn().mockRejectedValue(new Error("network")));
55
56 const result = await validateTurnstile("token", "0.0.0.0");
57 expect(result).toEqual({
58 success: false,
59 "error-codes": ["internal-error"],
60 });
61 });
62});