
Studio Mock Api Tests
Write Supabase Studio component tests that mock HTTP with MSW instead of vi.mocking data hooks.
Overview
studio-mock-api-tests is an agent skill for the Ship phase that teaches MSW-based component testing for Supabase Studio React Query flows.
Install
npx skills add https://github.com/supabase/supabase --skill studio-mock-api-testsWhat is this skill?
- customRender + addAPIMock template for mounting Studio components under test
- Intercept /platform/..., /v1/..., and api.d.ts endpoints at the network layer with MSW
- Explicit migration path off vi.mock('@/data/...') toward request-level mocks
- Documents jsdom and MSW gotchas that commonly burn debugging time
- Skip MSW when the component is purely presentational with no data fetching
Adoption & trust: 11 installs on skills.sh; 104k GitHub stars.
What problem does it solve?
You need Studio component tests but vi.mocking data modules hides real HTTP behavior and breaks when query keys or routes change.
Who is it for?
Developers adding or refactoring Vitest component tests for Studio screens that call React Query against platform or v1 APIs.
Skip if: Teams testing dumb presentational components with no hooks, or projects not using Studio’s customRender/MSW test stack.
When should I use this skill?
Writing or reviewing a Studio component test that exercises a React Query hook or mutation, or migrating away from vi.mock('@/data/...').
What do I get? / Deliverables
You get a repeatable customRender + addAPIMock template and MSW assertions so tests mock the network like production instead of brittle module stubs.
- MSW-backed component test file following the customRender template
- Assertions on rendered UI and intercepted API request payloads
Recommended Skills
Journey fit
How it compares
Prefer network-level MSW mocks over vi.mock('@/data/...') when you want tests to track real endpoint contracts.
Common Questions / FAQ
Who is studio-mock-api-tests for?
Solo builders and Supabase Studio contributors writing Vitest component tests for UI that uses React Query hooks or mutations against Studio API routes.
When should I use studio-mock-api-tests?
Use it in Ship while adding or reviewing component tests, when migrating off vi.mock data modules, or when a descendant component triggers fetches to /platform/... or /v1/... endpoints.
Is studio-mock-api-tests safe to install?
Treat it as procedural test guidance only; review the Security Audits panel on this page before trusting the skill package in your agent environment.
SKILL.md
READMESKILL.md - Studio Mock Api Tests
# Studio MSW component tests Mount a Studio component, intercept its network calls with MSW, assert what renders and what gets sent. The infrastructure is already wired up — this skill is the working template plus the gotchas. ## When to use - The component (or any descendant it renders) calls a React Query hook or mutation that hits `/platform/...`, `/v1/...`, or another endpoint in `apps/studio/data/api.d.ts`. - You'd otherwise be tempted to write `vi.mock('@/data/some-query', ...)`. **Don't.** Mock the network instead — see "Why not vi.mock" below. If the component is purely presentational with no data fetching, you don't need MSW; render and assert directly. ## The template ```tsx import { fireEvent, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { mockAnimationsApi } from 'jsdom-testing-mocks' import { HttpResponse } from 'msw' import { describe, expect, test, vi } from 'vitest' import { MyComponent } from './MyComponent' import { customRender } from '@/tests/lib/custom-render' import { addAPIMock } from '@/tests/lib/msw' // Needed if the component renders inside a Sheet, Modal, Popover, or // anything else built on Radix that uses Web Animations. mockAnimationsApi() describe('MyComponent', () => { test('renders rows from the API', async () => { addAPIMock({ method: 'get', path: '/platform/organizations', response: () => HttpResponse.json<OrganizationResponse[]>([ { /* ... */ }, ]), }) customRender(<MyComponent />) expect(await screen.findByText('Acme')).toBeInTheDocument() }) }) ``` That's the whole pattern. Server lifecycle (`listen`/`resetHandlers`/ `close`) is handled by `apps/studio/tests/vitestSetup.ts` — handlers registered via `addAPIMock` are scoped to the current test. ## Gotchas that will eat your afternoon ### 1. Path params use `:slug`, not `{slug}` `addAPIMock` is typed from the OpenAPI `paths`, but path params are remapped to MSW's `:param` format. Autocomplete will guide you, but if typecheck reports the path isn't assignable, you're using the OpenAPI `{slug}` form. ```ts // ❌ TypeScript error, MSW won't match path: '/platform/organizations/{slug}/projects' // ✅ Correct path: '/platform/organizations/:slug/projects' ``` ### 2. Use `HttpResponse.json`, not `new HttpResponse` For success responses, always go through `HttpResponse.json` — even for 204/201-no-content endpoints. A raw `new HttpResponse(null, { status: 201 })` returns no content-type, and `openapi-fetch` can hang the mutation flow, which silently breaks `onSuccess` callbacks. ```ts // ❌ Mutation onSuccess silently never fires response: () => new HttpResponse(null, { status: 201 }) // ✅ Works (pass the OpenAPI body shape explicitly — see gotcha #8) response: () => HttpResponse.json<MyResponse>({}, { status: 201 }) ``` ### 3. Submit buttons in Sheets/Modals need `fireEvent.click` The convention `<Button form={FORM_ID} htmlType="submit" />` (button outside the form, associated by id) doesn't reliably trigger submission under `userEvent.click` in jsdom. Use `fireEvent.click` for the submit button. Continue to use `userEvent.type` for inputs. ```ts await userEvent.type(screen.getByPlaceholderText('value'), 'hello') fireEvent.click(await screen.findByRole('button', { name: 'Save' })) ``` ### 4. Profile-gated queries need a `profileContext` Many hooks (`useOrganizationsQuery`, anything in `data/projects/`, anything that calls `useProfile`) refuse to fire until a profile is