Type Safety
idavidov13/agentic-playwright
TypeScript type safety conventions for the Playwright scaffold — the "no any" rule, Zod 4 schema patterns (z.strictObject, top-level validators like z.uuid / z.email / z.url / z.int / z.enum)…
Component tests for Supabase Studio that mock API requests at the network layer with MSW.
$ npx skills add supabase/supabase --skill studio-mock-api-tests -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install supabase/supabase studio-mock-api-tests --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/supabase/supabase.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/studio-mock-api-tests .claude/skills/studio-mock-api-tests && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "studio-mock-api-tests" agent skill from https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-tests into .claude/skills/studio-mock-api-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "studio-mock-api-tests", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-testsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add supabase/supabase --skill studio-mock-api-tests -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install supabase/supabase studio-mock-api-tests --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/supabase/supabase.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/studio-mock-api-tests .agents/skills/studio-mock-api-tests && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "studio-mock-api-tests" agent skill from https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-tests into .agents/skills/studio-mock-api-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "studio-mock-api-tests", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add supabase/supabase --skill studio-mock-api-tests -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install supabase/supabase studio-mock-api-tests --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/supabase/supabase.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/studio-mock-api-tests .cursor/skills/studio-mock-api-tests && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "studio-mock-api-tests" agent skill from https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-tests into .cursor/skills/studio-mock-api-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "studio-mock-api-tests", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/supabase/supabase.git --path .agents/skills/studio-mock-api-tests--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add supabase/supabase --skill studio-mock-api-tests -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install supabase/supabase studio-mock-api-tests --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/supabase/supabase.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/studio-mock-api-tests .gemini/skills/studio-mock-api-tests && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "studio-mock-api-tests" agent skill from https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-tests into .gemini/skills/studio-mock-api-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "studio-mock-api-tests", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install supabase/supabase studio-mock-api-testsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add supabase/supabase --skill studio-mock-api-tests -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/supabase/supabase.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/studio-mock-api-tests .github/skills/studio-mock-api-tests && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "studio-mock-api-tests" agent skill from https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-tests into .github/skills/studio-mock-api-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "studio-mock-api-tests", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add supabase/supabase --skill studio-mock-api-tests -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install supabase/supabase studio-mock-api-tests --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/supabase/supabase.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/studio-mock-api-tests .opencode/skills/studio-mock-api-tests && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "studio-mock-api-tests" agent skill from https://github.com/supabase/supabase/tree/master/.agents/skills/studio-mock-api-tests into .opencode/skills/studio-mock-api-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "studio-mock-api-tests", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
studio-mock-api-testsComponent tests for Supabase Studio that mock API requests at the network layer with MSW.
Studio Mock API Tests is an agent skill from supabase/supabase, published by the product's own GitHub organization. Component tests for Supabase Studio that mock API requests at the network layer with MSW. Use when writing or reviewing a component test that exercises a React Query hook or mutation, or when migrating an existing test away from vi.mock('@/data/...'). Covers the customRender + addAPIMock template and the jsdom/MSW gotchas that cost real debugging time.
Its SKILL.md is about 3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering API testing. It works with Supabase, TanStack and OpenAPI. The repository describes itself as: The Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications. The licence is Apache-2.0.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 26c838a. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
mswjs.iotkdodo.euFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
API_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Studio Mock API Tests loads about 3k tokens when it runs. Until then it costs about 94 tokens; SKILL.md has 928 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from supabase/supabase at commit 26c838a, republished under its Apache-2.0 licence (© supabase). 928 words, ~3,032 tokens.
.claude/skills/studio-mock-api-tests/SKILL.md (or your agent's skills folder).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.
/platform/..., /v1/..., or another endpoint
in apps/studio/data/api.d.ts.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.
import { screen } from '@testing-library/react'
import { platformComponents as components } from 'api-types'
import { mockAnimationsApi } from 'jsdom-testing-mocks'
import { HttpResponse } from 'msw'
import { describe, expect, test } from 'vitest'
import { MyComponent } from './MyComponent'
import { customRender } from '@/tests/lib/custom-render'
import { addAPIMock } from '@/tests/lib/msw'
type OrganizationResponse = components['schemas']['OrganizationResponse']
// 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 (add fireEvent, waitFor, or userEvent as the
interactions need them — see the gotchas below). Server lifecycle (listen/resetHandlers/
close) is handled by apps/studio/tests/vitestSetup.ts — handlers
registered via addAPIMock are scoped to the current test.
: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.
// ❌ TypeScript error, MSW won't match
path: '/platform/organizations/{slug}/projects'
// ✅ Correct
path: '/platform/organizations/:slug/projects'HttpResponse.json, not new HttpResponseFor 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.
// ❌ 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 })fireEvent.clickThe convention <Button form={FORM_ID} type="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.
await userEvent.type(screen.getByPlaceholderText('value'), 'hello')
fireEvent.click(await screen.findByRole('button', { name: 'Save' }))profileContextMany hooks (useOrganizationsQuery, anything in data/projects/,
anything that calls useProfile) refuse to fire until a profile is
loaded. Pass one explicitly:
import type { ProfileContextType } from '@/lib/profile'
const PROFILE_CONTEXT: ProfileContextType = {
profile: {
id: 1,
auth0_id: 'auth0|test',
gotrue_id: 'gotrue-test',
username: 'testuser',
primary_email: 'test@example.com',
first_name: null,
last_name: null,
mobile: null,
is_alpha_user: false,
is_sso_user: false,
disabled_features: [],
free_project_limit: null,
},
error: null,
isLoading: false,
isError: false,
isSuccess: true,
}
customRender(<MyComponent />, { profileContext: PROFILE_CONTEXT })useParams is globally mocked to { ref: 'default' }You don't need to mock the Next router for project-scoped components.
Just use 'default' as the project ref in your mock paths:
/v1/projects/default/secrets, /platform/projects/default/.... If
you need a different ref, override with routerMock.setCurrentUrl(...)
(see apps/studio/tests/lib/route-mock.ts).
mswServer.listen({ onUnhandledRequest: 'error' }) is set globally. If a
component (or any child it renders) fires an unmocked request, you'll see
MSW errors in stderr and likely flaky behavior. Cards, lists, and details
panels often fire nested queries (e.g. OrganizationCard calls
useOrgProjectsInfiniteQuery) — read what the rendered subtree does and
mock all of it, or stub it with vi.mock for nested components only.
pathaddAPIMock accepts ?foo=bar suffixes via TrimQueryParams, but the
helper strips them before matching. MSW v2 doesn't match query params via
path strings — read them inside the resolver instead:
addAPIMock({
method: 'get',
path: '/platform/projects',
response: ({ request }) => {
const limit = new URL(request.url).searchParams.get('limit')
// ...
},
})HttpResponse.jsonaddAPIMock's resolver is typed against the OpenAPI success body (and the
standard { message: string } error envelope, exported as APIErrorBody).
But MSW's HttpResponse.json uses NoInfer, so the body type doesn't
narrow from context. Pass the expected shape explicitly — it doubles as a
self-documenting contract assertion:
import { addAPIMock, type APIErrorBody } from '@/tests/lib/msw'
response: () => HttpResponse.json<OrganizationResponse[]>([...])
response: () =>
HttpResponse.json<APIErrorBody>({ message: 'Boom' }, { status: 500 })A mock that drifts from the contract (wrong envelope, missing fields, stale enum values) now fails at compile time, not at runtime. The cost is one type annotation per resolver — well worth it.
For mocks at the network boundary, also prefer createMockOrganizationResponse
(returns the raw OpenAPI OrganizationResponse) over createMockOrganization
(which extends with frontend-derived managed_by / partner_id that the
query layer attaches). Same pattern applies to any type that's a frontend
extension of an OpenAPI schema: build a createMockXResponse helper that
returns the raw API shape.
MSW's own best-practices doc explicitly recommends asserting on what
renders, not on whether a handler was called. The "did the form
submit?" question is best answered by expect(onClose).toHaveBeenCalled()
or by findByText('Saved') — not by spying on the resolver.
There's one legitimate exception: the request body itself is the
contract you care about, and the server's reply doesn't reflect it
back. Bulk-create endpoints (like POST /v1/projects/:ref/secrets) are
the canonical case — 201 with no body, so the only way to verify the
shape sent is to capture it:
const requests: Array<{ ref: string | undefined; body: unknown }> = []
addAPIMock({
method: 'post',
path: '/v1/projects/:ref/secrets',
response: async ({ request, params }) => {
requests.push({ ref: params.ref as string | undefined, body: await request.json() })
return HttpResponse.json<CreateSecretsResponse>({}, { status: 201 })
},
})
// ... drive the UI ...
expect(requests).toEqual([{ ref: 'default', body: [{ name: 'API_KEY', value: 'new-value' }] }])When in doubt, assert on the UI first; reach for request capture only when the UI doesn't observably encode the contract.
If a request isn't being matched, wire up MSW's lifecycle events at the
top of the test file (or temporarily in msw.ts):
import { mswServer } from '@/tests/lib/msw'
mswServer.events.on('request:unhandled', ({ request }) => {
console.log('[MSW] UNHANDLED:', request.method, request.url)
})
mswServer.events.on('response:mocked', ({ request, response }) => {
console.log('[MSW] MATCHED:', request.method, request.url, response.status)
})request:start is already wired in msw.ts. Add request:unhandled and
response:mocked locally when a test misbehaves — usually surfaces a
path-param mismatch or a nested query you forgot to mock.
vi.mock('@/data/...')It bypasses the network boundary, so:
onMutate, onSuccess, and onError callbacks won't run as
they do in real life. (tkdodo.eu/blog/testing-react-query)Reach for vi.mock only for non-network concerns: a heavy child
component (e.g. a Monaco editor) you want to stub, or a common-package
hook with global state.
server.use() pattern.| What | Where |
|---|---|
| Query-only example (loading, error, success) | apps/studio/components/interfaces/Organization/OrgNotFound.test.tsx |
| Mutation example (form, payload assertion) | apps/studio/components/interfaces/Functions/EdgeFunctionSecrets/EditSecretSheet.test.tsx |
SQL-via-pg-meta example (POST resolver branch on query body) | apps/studio/components/interfaces/Integrations/Vault/Secrets/__tests__/EditSecretModal.test.tsx |
addAPIMock source | apps/studio/tests/lib/msw.ts |
customRender source | apps/studio/tests/lib/custom-render.tsx |
| Global handlers + lifecycle | apps/studio/tests/lib/msw-global-api-mocks.ts, apps/studio/tests/vitestSetup.ts |
| Related skills | studio-testing (when to write a component test at all), studio-queries (hook conventions), vitest |
© supabase, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/studio-mock-api-tests of supabase/supabase.
Open the folder on GitHubat commit 26c838a
Studio Mock API Tests next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Studio Mock API Tests this skillsupabase/supabase | 111k | — | ~3k | Automated safety check: Pass | Apache-2.0 | |
| Type Safetyidavidov13/agentic-playwright | 223 | — | ~3.5k | Automated safety check: Pass | MIT | |
| API Testingpetrkindlmann/qa-skills | 165 | — | ~2.7k | Automated safety check: Pass | MIT | |
| Automating API Testingjeremylongshore/tons-of-skills-marketplace | 2.8k | — | ~1.7k | Automated safety check: Pass | MIT | |
| Use Yaakmountain-loop/yaak | 19k | — | ~1.9k | Automated safety check: Pass | MIT | |
| API Testingidavidov13/agentic-playwright | 223 | — | ~5.7k | Automated safety check: Pass | MIT |
idavidov13/agentic-playwright
TypeScript type safety conventions for the Playwright scaffold — the "no any" rule, Zod 4 schema patterns (z.strictObject, top-level validators like z.uuid / z.email / z.url / z.int / z.enum)…
petrkindlmann/qa-skills
Test REST and GraphQL APIs with Playwright APIRequestContext, Supertest, or standalone HTTP clients.
jeremylongshore/tons-of-skills-marketplace
Test automate API endpoint testing including request generation, validation, and comprehensive test coverage for REST and GraphQL APIs.
mountain-loop/yaak
A skill your agent uses when the user mentions Yaak, a Yaak workspace, or the yaak command, or asks to call, hit, or smoke test HTTP/REST endpoints, save or organize API requests for reuse or manual…
idavidov13/agentic-playwright
API testing patterns for Playwright -- apiRequest fixture usage, Zod response schema creation and validation, test.step wrapping for multi-call tests, per-field negative/validation testing, path…
borghei/Claude-Skills
Generate API test suites from route definitions across frameworks: auth, input validation, contract, k6 load testing, mocking, and OpenAPI-driven generation.
supabase/supabase
React composition patterns that scale. An agent skill from supabase/supabase.
supabase/supabase
Write, review, and migrate Supabase logs queries against the ClickHouse-backed logs table (the logs.all.otel analytics endpoint).
supabase/supabase
Review Supabase docs changes locally in your supabase/supabase checkout — either an open PR (triage, classify, verify) or your own branch before opening a PR (local self-review).
supabase/supabase
Vitest API and config reference (Jest-compatible) — mocking with vi., spies, fake timers, coverage configuration, fixtures, snapshots, and test filtering.
supabase/supabase
A skill your agent uses whenever code will build, return, fetch, or execute SQL that runs against a user's real Postgres database — even when the request reads like an ordinary feature or bug fix…
supabase/supabase
Write and run Playwright E2E tests for Supabase Studio (e2e/studio).
Categories
Component tests for Supabase Studio that mock API requests at the network layer with MSW. Studio Mock API Tests is an agent skill from supabase/supabase, published by the product's own GitHub organization. Component tests for Supabase Studio that mock API requests at the network layer with MSW.
Studio Mock API Tests fits situations like: reviewing a component test that exercises a React Query hook; migrating an existing test away from vi.mock(@/data/...).
Run `npx skills add supabase/supabase --skill studio-mock-api-tests -a claude-code`. Or copy the skill folder (.agents/skills/studio-mock-api-tests in supabase/supabase) into .claude/skills/studio-mock-api-tests in your project. Claude Code loads it when a task matches its description.
Run `npx skills add supabase/supabase --skill studio-mock-api-tests -a codex`. Or copy the skill folder (.agents/skills/studio-mock-api-tests in supabase/supabase) into .agents/skills/studio-mock-api-tests in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add supabase/supabase --skill studio-mock-api-tests -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/studio-mock-api-tests, .gemini/skills/studio-mock-api-tests, .github/skills/studio-mock-api-tests and .opencode/skills/studio-mock-api-tests in your project.
Going by SKILL.md and its folder, Studio Mock API Tests needs credentials named API_KEY. Our summary lists: A credential in API_KEY.
SKILL.md names 2 domains. As links in the text: mswjs.io and tkdodo.eu. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Studio Mock API Tests is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Studio Mock API Tests: Type Safety (idavidov13/agentic-playwright, 223 stars), API Testing (petrkindlmann/qa-skills, 165 stars), Automating API Testing (jeremylongshore/tons-of-skills-marketplace, 2.8k stars) and Use Yaak (mountain-loop/yaak, 19k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
supabase (a GitHub organization, an official publisher) maintains it in supabase/supabase, which has 111,222 GitHub stars. The repository holds 22 skills in this directory. The repository was last updated on October 8, 2026.
Source: supabase/supabase on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.