ProvenPin Install

supabase-js queries and auth tested with a mocked fetch (Vitest): working versions (tested 2026-10-15)

Use @supabase/supabase-js for table queries and auth in app code, and unit-test it offline by passing a fake fetch to createClient.

passed4 passed · 0 failed2026-10-15 11:57 UTC
Status
passed
Last passed
2026-10-15 11:57 UTC
Tests
4 / 4
Language
TypeScript
Runtime
node v22.23.3
pinned versions3
@supabase/supabase-js@2.117.3@types/node@24.19.2vitest@5.0.4
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38730348195

The code

Exactly the files that passed. Your agent can pull them with get_recipe("supabase-js-mocked-fetch") (install), or see them on GitHub.

package.json
{
  "name": "supabase-js-mocked-fetch",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "vitest run --reporter=default --reporter=json --outputFile=test-report.json"
  },
  "dependencies": {
    "@supabase/supabase-js": "2.117.3"
  },
  "devDependencies": {
    "@types/node": "24.19.2",
    "vitest": "5.0.4"
  }
}
src/todos.ts
import type { SupabaseClient } from "@supabase/supabase-js";

export type Todo = { id: number; title: string; done: boolean; user_id: string };

export async function openTodos(sb: SupabaseClient, userId: string): Promise<Todo[]> {
  const { data, error } = await sb.from("todos").select("id,title,done,user_id").eq("user_id", userId).eq("done", false).order("id");
  if (error) throw new Error(error.message);
  return data as Todo[];
}

export async function addTodo(sb: SupabaseClient, userId: string, title: string): Promise<Todo> {
  const { data, error } = await sb.from("todos").insert({ title, user_id: userId }).select().single();
  if (error) throw new Error(error.message);
  return data as Todo;
}

export async function signIn(sb: SupabaseClient, email: string, password: string) {
  const { data, error } = await sb.auth.signInWithPassword({ email, password });
  if (error) throw error;
  return data.user?.id;
}
test/todos.test.ts
import { describe, it, expect, vi } from "vitest";
import { createClient } from "@supabase/supabase-js";
import { addTodo, openTodos, signIn } from "../src/todos";

const URL_ = "https://demo.supabase.co";
function client(handler: (url: URL, init: RequestInit) => Response) {
  const fetch = vi.fn(async (input: RequestInfo | URL, init: RequestInit = {}) => handler(new URL(String(input instanceof Request ? input.url : input)), init));
  const sb = createClient(URL_, "anon-key", { global: { fetch: fetch as any }, auth: { persistSession: false, autoRefreshToken: false } });
  return { sb, fetch };
}
const ok = (body: unknown, status = 200) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });

describe("todos", () => {
  it("builds the PostgREST filter query", async () => {
    const { sb, fetch } = client(() => ok([{ id: 1, title: "a", done: false, user_id: "u1" }]));
    expect(await openTodos(sb, "u1")).toHaveLength(1);
    const url = new URL(String(fetch.mock.calls[0][0]));
    expect(url.pathname).toBe("/rest/v1/todos");
    expect(url.searchParams.get("user_id")).toBe("eq.u1");
    expect(url.searchParams.get("done")).toBe("eq.false");
  });

  it("insert + single returns the row", async () => {
    const { sb, fetch } = client(() => ok({ id: 2, title: "b", done: false, user_id: "u1" }, 201));
    expect((await addTodo(sb, "u1", "b")).id).toBe(2);
    expect(fetch.mock.calls[0][1]?.method).toBe("POST");
  });

  it("surfaces PostgREST errors", async () => {
    const { sb } = client(() => ok({ code: "42501", message: "permission denied for table todos", details: null, hint: null }, 403));
    await expect(openTodos(sb, "u1")).rejects.toThrow(/permission denied/);
  });

  it("signs in through GoTrue", async () => {
    const { sb, fetch } = client((url) => {
      expect(url.pathname).toBe("/auth/v1/token");
      expect(url.searchParams.get("grant_type")).toBe("password");
      return ok({ access_token: "at", token_type: "bearer", expires_in: 3600, expires_at: Math.floor(Date.now() / 1000) + 3600, refresh_token: "rt", user: { id: "u1", aud: "authenticated", app_metadata: {}, user_metadata: {}, created_at: new Date().toISOString() } });
    });
    expect(await signIn(sb, "a@example.com", "pw")).toBe("u1");
    expect(fetch).toHaveBeenCalledTimes(1);
  });
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.