/playground-msw-tests
REQUIRED and PRIMARY testing approach for packages/playground and packages/playground-ui. Triggers on: adding or modifying hooks, pages, route components, data-fetching code, React Query interactions, or any test work in these packages. Generates Vitest tests that drive the real
$ npx -y skills add mastra-ai/mastra --skill playground-msw-tests --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/playground-msw-tests
Context preview
The summary Claude sees to decide when to auto-load this skill.
REQUIRED and PRIMARY testing approach for packages/playground and packages/playground-ui. Triggers on: adding or modifying hooks, pages, route components, data-fetching code, React Query interactions, or any test work in these packages. Generates Vitest tests that drive the real
SKILL.md
playground-msw-tests.SKILL.mdname: playground-msw-tests
description: >
REQUIRED and PRIMARY testing approach for packages/playground and packages/playground-ui.
Triggers on: adding or modifying hooks, pages, route components, data-fetching code,
React Query interactions, or any test work in these packages. Generates Vitest tests
that drive the real @mastra/client-js + React Query stack through MSW handlers and
typed fixtures derived from @mastra/client-js response types. This is the #1 way to
test the playground packages — ABOVE Playwright E2E. Use Playwright only for
cross-page user journeys that MSW cannot model.
MSW + client-js Fixtures: Primary Testing Strategy
Core Principle
**Drive the real transport, mock the network.**
Tests in `packages/playground` and `packages/playground-ui` MUST be written as Vitest tests that exercise the real `@mastra/client-js` SDK, the real React Query cache, and the real component/hook code paths. The only seam we mock is the network boundary, via [MSW](https://mswjs.io/).
This catches contract drift between the playground and `@mastra/client-js` at typecheck time and at test time — something `vi.mock('@/hooks/...')` style tests cannot do.
Priority Order
When you write or refactor a test for these packages, choose in this order:
1. **MSW + typed client-js fixtures (THIS SKILL)** — for hooks, pages, routes, data-fetching, gating, redirect logic, query/mutation flows, error paths. 2. **Playwright E2E** (`e2e-tests-studio` skill) — only for genuine cross-page user journeys, real browser concerns (focus/keyboard/viewport), or anything that requires a real running Mastra server. 3. **Pure unit tests** — only for self-contained utilities/services with no network, no React Query, no router involvement.
If the same behavior can be covered by both #1 and #2, **prefer #1**. MSW tests are faster, deterministic, run in CI without browsers, and assert the real wire contract.
What NOT to do
- ❌ `vi.mock('@/domains/.../hooks/use-agents')` — mocking our own hooks hides
cache, gating and transport bugs.
- ❌ Implementation-mirror tests — do not duplicate source class strings,
branch logic, generated shapes, or calculations without asserting a real behavior or regression.
- ❌ Class-name-only visual tests — `expect(node.className).toContain(...)`
usually just tests that the implementation string exists. Prefer no test over a className duplication test; use computed style, user-visible behavior, or a browser/Storybook check unless the class string itself is the public API.
- ❌ Inline TypeScript types in tests (`type AgentLite = { id: string }`) —
these drift silently from the real SDK.
- ❌ `as any` / `as unknown as ListAgentsResponse` on fixture data, MSW
responses, request payloads, hook inputs, or component event inputs.
- ❌ Returning bespoke shapes from MSW handlers that don't match the real
`@mastra/client-js` response. If a field is optional, include it as optional in the fixture, don't omit the type.
What TO do
- ✅ Put fixtures in a `__tests__/fixtures/` folder next to the test file.
- ✅ Type every fixture with a response type re-exported from `@mastra/client-js`
(e.g. `ListStoredAgentsResponse`, `GetAgentResponse`, `BuilderSettingsResponse`, `GetToolResponse`, `GetWorkflowResponse`, `ListStoredSkillsResponse`).
- ✅ Use direct imports and inferred types from real SDK, hook, component, DOM,
or Testing Library APIs for MSW payloads, request payloads, hook inputs, and component events.
- ✅ Register MSW handlers per test with `server.use(...)` so handlers reset
between tests via the global `afterEach`.
- ✅ Render through `MastraReactProvider` + `QueryClientProvider` + `MemoryRouter`
so the real client SDK is the transport.
- ✅ Use `vi.fn()` wrappers inside MSW handlers to assert which endpoints were
hit (great for testing `enabled: ...` gating without mocking hooks).
Standard Test Skeleton
// @vitest-environment jsdom
import { MastraReactProvider } from '@mastra/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { cleanup, render, screen } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { MemoryRouter } from 'react-router';
import { afterEach, describe, expect, it } from 'vitest';
import { server } from '@/test/msw-server';
import { Subject } from '../subject';
import { happyPathResponse } from './fixtures/subject';
const BASE_URL = 'http://localhost:4111';
const renderSubject = () => {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return render(
<MastraReactProvider baseUrl={BASE_URL}>
<QueryClientProvider client={queryClient}>
<MemoryRouter>
<Subject />
</MemoryRouter>
</QueryClientProvider>
</MastraReactProvider>,
);
};
afterEach(() => cleanup());
describe('Subject', () => {
it('renders the happy path', async () => {
server.use(http.get(`${BASE_URL}/api/agents`, () => HttpResponse.json(happyPathResponse)));
renderSubject();
expect(await screen.findByText('Expected behavior')).not.toBeNull();
});
});Standard Fixture File
// packages/playground/src/.../__tests__/fixtures/subject.ts
import type { ListStoredAgentsResponse } from '@mastra/client-js';
export const emptyStoredAgents: ListStoredAgentsResponse = {
agents: [],
total: 0,
page: 1,
perPage: 50,
hasMore: false,
};
export const oneDraftAgent: ListStoredAgentsResponse = {
...emptyStoredAgents,
agents: [
{
id: 'agent-1',
name: 'Draft Agent',
instructions: '',
model: { provider: 'openai', name: 'gpt-4o-mini' },
status: 'draft',
// ...other required fields from StoredAgentResponse
},
],
total: 1,
};**If a required field on the SDK response type is missing from your fixture, that's a real test failure — fix the fixture, never `as any` it.** The same applies to hook inputs, compo
Read more
name: playground-msw-tests description: > REQUIRED and PRIMARY testing approach for packages/playground and packages/playground-ui. Triggers on: adding or modifying hooks, pages, route components, data-fetching code, React Query interactions, or any test work in these packages. Generates Vitest tests that drive the real @mastra/client-js + React Query stack through MSW handlers and typed fixtures derived from @mastra/client-js response types. This is the #1 way to test the playground packages — ABOVE Playwright E2E. Use Playwright only for cross-page user journeys that MSW cannot model.
MSW + client-js Fixtures: Primary Testing Strategy
Core Principle
**Drive the real transport, mock the network.**
Tests in `packages/playground` and `packages/playground-ui` MUST be written as Vitest tests that exercise the real `@mastra/client-js` SDK, the real React Query cache, and the real component/hook code paths. The only seam we mock is the network boundary, via [MSW](https://mswjs.io/).
This catches contract drift between the playground and `@mastra/client-js` at typecheck time and at test time — something `vi.mock('@/hooks/...')` style tests cannot do.
Priority Order
When you write or refactor a test for these packages, choose in this order:
1. **MSW + typed client-js fixtures (THIS SKILL)** — for hooks, pages, routes, data-fetching, gating, redirect logic, query/mutation flows, error paths. 2. **Playwright E2E** (`e2e-tests-studio` skill) — only for genuine cross-page user journeys, real browser concerns (focus/keyboard/viewport), or anything that requires a real running Mastra server. 3. **Pure unit tests** — only for self-contained utilities/services with no network, no React Query, no router involvement.
If the same behavior can be covered by both #1 and #2, **prefer #1**. MSW tests are faster, deterministic, run in CI without browsers, and assert the real wire contract.
What NOT to do
- ❌ `vi.mock('@/domains/.../hooks/use-agents')` — mocking our own hooks hides
cache, gating and transport bugs.
- ❌ Implementation-mirror tests — do not duplicate source class strings,
branch logic, generated shapes, or calculations without asserting a real behavior or regression.
- ❌ Class-name-only visual tests — `expect(node.className).toContain(...)`
usually just tests that the implementation string exists. Prefer no test over a className duplication test; use computed style, user-visible behavior, or a browser/Storybook check unless the class string itself is the public API.
- ❌ Inline TypeScript types in tests (`type AgentLite = { id: string }`) —
these drift silently from the real SDK.
- ❌ `as any` / `as unknown as ListAgentsResponse` on fixture data, MSW
responses, request payloads, hook inputs, or component event inputs.
- ❌ Returning bespoke shapes from MSW handlers that don't match the real
`@mastra/client-js` response. If a field is optional, include it as optional in the fixture, don't omit the type.
What TO do
- ✅ Put fixtures in a `__tests__/fixtures/` folder next to the test file.
- ✅ Type every fixture with a response type re-exported from `@mastra/client-js`
(e.g. `ListStoredAgentsResponse`, `GetAgentResponse`, `BuilderSettingsResponse`, `GetToolResponse`, `GetWorkflowResponse`, `ListStoredSkillsResponse`).
- ✅ Use direct imports and inferred types from real SDK, hook, component, DOM,
or Testing Library APIs for MSW payloads, request payloads, hook inputs, and component events.
- ✅ Register MSW handlers per test with `server.use(...)` so handlers reset
between tests via the global `afterEach`.
- ✅ Render through `MastraReactProvider` + `QueryClientProvider` + `MemoryRouter`
so the real client SDK is the transport.
- ✅ Use `vi.fn()` wrappers inside MSW handlers to assert which endpoints were
hit (great for testing `enabled: ...` gating without mocking hooks).
Standard Test Skeleton
// @vitest-environment jsdom
import { MastraReactProvider } from '@mastra/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { cleanup, render, screen } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { MemoryRouter } from 'react-router';
import { afterEach, describe, expect, it } from 'vitest';
import { server } from '@/test/msw-server';
import { Subject } from '../subject';
import { happyPathResponse } from './fixtures/subject';
const BASE_URL = 'http://localhost:4111';
const renderSubject = () => {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return render(
<MastraReactProvider baseUrl={BASE_URL}>
<QueryClientProvider client={queryClient}>
<MemoryRouter>
<Subject />
</MemoryRouter>
</QueryClientProvider>
</MastraReactProvider>,
);
};
afterEach(() => cleanup());
describe('Subject', () => {
it('renders the happy path', async () => {
server.use(http.get(`${BASE_URL}/api/agents`, () => HttpResponse.json(happyPathResponse)));
renderSubject();
expect(await screen.findByText('Expected behavior')).not.toBeNull();
});
});Standard Fixture File
// packages/playground/src/.../__tests__/fixtures/subject.ts
import type { ListStoredAgentsResponse } from '@mastra/client-js';
export const emptyStoredAgents: ListStoredAgentsResponse = {
agents: [],
total: 0,
page: 1,
perPage: 50,
hasMore: false,
};
export const oneDraftAgent: ListStoredAgentsResponse = {
...emptyStoredAgents,
agents: [
{
id: 'agent-1',
name: 'Draft Agent',
instructions: '',
model: { provider: 'openai', name: 'gpt-4o-mini' },
status: 'draft',
// ...other required fields from StoredAgentResponse
},
],
total: 1,
};**If a required field on the SDK response type is missing from your fixture, that's a real test failure — fix the fixture, never `as any` it.** The same applies to hook inputs, compo
Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack. It includes everything you need to go from early prototypes to production-ready applications.
Repo: mastra-ai/mastra
Other skills on mastra.
- /builder-smoke-test
Smoke test the Agent Builder feature branch end-to-end against a hermetic project scaffolded by the skill (linked to the current worktree). Covers workspace reconciliation, stored agents/skills CRUD, ownership, visibility, stars, registry/library Copy flow, picker allowlists,
Open skill - /debugging-difficult-bugs
Use early when debugging a medium or hard bug, especially when tests alone may not reveal the real runtime failure. Trigger this before extended TDD iteration when a bug involves runtime state, ordering, persistence, streaming, concurrency, UI/manual reproduction, external
Open skill - /docs-audit
Interactive documentation quality review for Mastra docs. Use when auditing, reviewing, or critiquing Mastra documentation; checking docs against source code; validating code examples, API accuracy, or property completeness; checking whether docs follow the styleguide and
Open skill - /e2e-tests-studio
REQUIRED when modifying any file in packages/playground-ui or packages/playground. Triggers on: React component creation/modification/refactoring, UI changes, new playground features, bug fixes affecting studio UI. Generates Playwright E2E tests that validate PRODUCT BEHAVIOR,
Open skill - /mastra-docs
Documentation guidelines for Mastra. This skill should be used when writing or editing documentation for Mastra. Triggers on tasks involving documentation creation or updates.
Open skill - /mastra-frontend
How to build Mastra frontend interfaces with the @mastra/playground-ui design system. This skill should be used when creating or modifying any application UI — pages, components, styling, or tokens — in this repo or in an external consumer of the design system. The docs site has
Open skill

