Test Your supabase-js Code Without a Server: An In-Process Backend for Vitest
Most Supabase apps end up with one of two testing strategies: Mock supabase-js . Fast, but the mocks test what you think the database does. RLS, constraints, and defaults never run. Test against a running backend. Accurate, but now every test run needs Docker (or a cloud project), ports, and cleanup between runs. There's a third option: run the backend inside the test process itself . No server,…
Testing Supabase applications typically involves two strategies: mocking the supabase-js library or testing against a running backend. The first approach tests what you believe the database does, but it does not verify RLS, constraints, or defaults. The second option, testing against a live backend, is accurate but requires Docker, ports, cleanup between runs, and complex setup.
A third option exists, which involves running the backend within the test process itself. This eliminates the need for a server, ports, or network, as the real supabase-js code communicates with real Postgres using policies, and the test file disposes of the backend when it concludes. This guide explains how to set up an in-process backend using Vitest and tinbase, an open-source Supabase-compatible backend that can run within the process with PGlite, a Postgres implementation compiled to WebAssembly.
Vitest is an assertion library for testing JavaScript code, while tinbase is a work in progress, focusing on development and testing. tinbase covers a significant portion of the supabase-js functionality but does not include all features. It is essential to review the known gaps in the README before relying on specific functions.
In-process backends function similarly to traditional setups, with supabase-js sending HTTP requests to a server. However, they allow you to pass a custom fetch function. tinbase exposes a backend.fetch function that manages these requests directly, enabling you to wire them together: your code, supabase-js, backend.fetch, and Postgres (PGlite) all occur within a single process.
There is no port listening, so tests can run concurrently without interference, and no cleanup is necessary afterward. To set up the in-process backend, install the necessary dependencies using npm install -D vitest tinbase and npm install @supabase/supabase-js. A helper function, createBackend, initializes a fresh backend and accepts an array of migrations, which define database schema changes.
The function returns a backend object and a newClient function, which creates a separate client for each test run. In this example, a migration table named "notes" is created, enforcing row-level security (RLS) and a policy that allows only authenticated users to access the notes table. The tests begin with anonymous sign-in, granting each client a real authenticated user without email confirmation.
The first test ensures that a note is created and read correctly, while the second test verifies that an error occurs when inserting an empty note due to a check constraint.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.