git:20260408.c85708c to git:20260415.5cb4040
23 added, 11 removed. Audit A to A.
# Frontend Testing Rules π§ͺ
## Testing Types Overview
| Type | Tool | Speed | Purpose |
| --------------- | --------------------- | --------------- | -------------------------------- |
| **E2E** | Playwright | Slow (~5s/test) | Real browser, full user journeys |
| **Integration** | Vitest + RTL | Fast (~100ms) | Component + mocked API |
| **Unit** | Vitest + RTL | Fastest (~10ms) | Individual functions/components |
| **Visual** | Storybook + Chromatic | N/A | UI appearance, design system |
---
## When to Use Each
### β
E2E Tests (Playwright)
**Use for:** Critical user journeys that MUST work in a real browser.
- Authentication flows (login, signup, logout)
- Payment or sensitive transactions
- Flows requiring real browser APIs (clipboard, downloads)
- Cross-page navigation that must work end-to-end
- **Location:** `src/tests/*.spec.ts` (centralized, as there will be fewer of them)
+ **Location:** `src/playwright/*.spec.ts` (centralized, as there will be fewer of them)
**Import:** Always import `test` and `expect` from `./coverage-fixture` instead of `@playwright/test`. This auto-collects V8 coverage per test for Codecov reporting.
```ts
// correct
import { test, expect } from "./coverage-fixture";
// wrong - bypasses coverage collection
import { test, expect } from "@playwright/test";
```
### β
Integration Tests (Vitest + RTL)
**Use for:** Testing components with their dependencies (API calls, state).
- Page-level behavior with mocked API responses
- Components that fetch data
- User interactions that trigger API calls
- Feature flows within a single page
**Location:** Place tests in a `__tests__` folder next to the component:
```
ComponentName/
__tests__/
main.test.tsx
some-flow.test.tsx
ComponentName.tsx
useComponentName.ts
```
**Start at page level:** Initially write integration tests at the "page" level. No need to write them for every small component.
```
/library/
__tests__/
main.test.tsx
searching-agents.test.tsx
agents-pagination.test.tsx
page.tsx
useLibraryPage.ts
```
Start with a `main.test.tsx` file and split into smaller files as it grows.
**What integration tests should do:**
1. Render a page or complex modal (e.g., `AgentPublishModal`)
2. Mock API requests via MSW
3. Assert UI scenarios via Testing Library
+ **Prefer the UI surface over direct hook tests:** if a `use*.ts` hook only exists to support a page/component, test that page/component instead of adding a `renderHook()` test. Reserve direct hook tests for shared hooks with standalone business logic that cannot be exercised cleanly through the UI.
+
+ **Prefer Orval-generated mocks:** use the generated MSW handlers and response builders from `src/app/api/__generated__/endpoints/*/*.msw.ts` instead of hand-built API response objects or mocking a page/component hook.
+
```tsx
// Example: Test page renders data from API
import { server } from "@/mocks/mock-server";
import { getDeleteV2DeleteStoreSubmissionMockHandler422 } from "@/app/api/__generated__/endpoints/store/store.msw";
test("shows error when submission fails", async () => {
// Override default handler to return error status
server.use(getDeleteV2DeleteStoreSubmissionMockHandler422());
render(<MarketplacePage />);
await screen.findByText("Featured Agents");
// ... assert error UI
});
```
**Tip:** Use `findBy...` methods most of the timeβthey wait for elements to appear, so async code won't cause flaky tests. The regular `getBy...` methods don't wait and error immediately.
### β
Unit Tests (Vitest + RTL)
**Use for:** Testing isolated components and utility functions.
- Pure utility functions (`lib/utils.ts`)
- Component rendering with various props
- Component state changes
- - Custom hooks
+ - Shared hooks with standalone business logic
**Location:** Co-located with the file: `Component.test.tsx` next to `Component.tsx`
```tsx
// Example: Test component renders correctly
render(<AgentCard title="My Agent" />);
expect(screen.getByText("My Agent")).toBeInTheDocument();
```
### β
Storybook Tests (Visual)
**Use for:** Design system, visual appearance, component documentation.
- Atoms (Button, Input, Badge)
- Molecules (Dialog, Card)
- Visual states (hover, disabled, loading)
- Responsive layouts
**Location:** Co-located: `Component.stories.tsx` next to `Component.tsx`
---
## Decision Flowchart
```
Does it need a REAL browser/backend?
ββ YES β E2E (Playwright)
ββ NO
ββ Does it involve API calls or complex state?
ββ YES β Integration (Vitest + RTL)
ββ NO
ββ Is it about visual appearance?
ββ YES β Storybook
ββ NO β Unit (Vitest + RTL)
```
---
## What NOT to Test
β Third-party library internals (Radix UI, React Query)
β CSS styling details (use Storybook)
β Simple prop-passing components with no logic
β TypeScript types
---
## File Organization
```
src/
βββ components/
β βββ atoms/
β βββ Button/
β βββ Button.tsx
β βββ Button.test.tsx # Unit test
β βββ Button.stories.tsx # Visual test
βββ app/
β βββ (platform)/
β βββ marketplace/
β βββ components/
β βββ MainMarketplacePage/
β βββ __tests__/
β β βββ main.test.tsx # Integration test
β β βββ search-agents.test.tsx # Integration test
β βββ MainMarketplacePage.tsx
β βββ useMainMarketplacePage.ts
βββ lib/
β βββ utils.ts
β βββ utils.test.ts # Unit test
βββ mocks/
β βββ mock-handlers.ts # MSW handlers (auto-generated via Orval)
β βββ mock-server.ts # MSW server setup
+ βββ playwright/
+ β βββ *.spec.ts # E2E tests (Playwright) - centralized
+ β βββ pages/ # Playwright page objects
+ β βββ utils/ # Playwright helpers/fixtures
βββ tests/
βββ integrations/
β βββ test-utils.tsx # Testing utilities
β βββ vitest.setup.tsx # Integration test setup
- βββ *.spec.ts # E2E tests (Playwright) - centralized
+ βββ AGENTS.md # Testing guidance for agents
```
---
## Priority Matrix
- | Component Type | Test Priority | Recommended Test |
- | ------------------- | ------------- | ---------------- |
- | Pages/Features | **Highest** | Integration |
- | Custom Hooks | High | Unit |
- | Utility Functions | High | Unit |
- | Organisms (complex) | High | Integration |
- | Molecules | Medium | Unit + Storybook |
- | Atoms | Medium | Storybook only\* |
+ | Component Type | Test Priority | Recommended Test |
+ | ------------------- | ------------- | -------------------------------------- |
+ | Pages/Features | **Highest** | Integration |
+ | Custom Hooks | Medium | Parent integration or shared-hook unit |
+ | Utility Functions | High | Unit |
+ | Organisms (complex) | High | Integration |
+ | Molecules | Medium | Unit + Storybook |
+ | Atoms | Medium | Storybook only\* |
\*Atoms are typically simple enough that Storybook visual tests suffice.
---
## MSW Mocking
API mocking is handled via MSW (Mock Service Worker). Handlers are auto-generated by Orval from the OpenAPI schema.
**Default behavior:** All client-side requests are intercepted and return 200 status with faker-generated data.
**Override for specific tests:** Use generated error handlers to test non-OK status scenarios:
```tsx
import { server } from "@/mocks/mock-server";
import { getDeleteV2DeleteStoreSubmissionMockHandler422 } from "@/app/api/__generated__/endpoints/store/store.msw";
test("shows error when deletion fails", async () => {
server.use(getDeleteV2DeleteStoreSubmissionMockHandler422());
render(<MyComponent />);
// ... assert error UI
});
```
**Generated handlers location:** `src/app/api/__generated__/endpoints/*/` - each endpoint has handlers for different status codes.
+ For Playwright support code, keep browser-only helpers in `src/playwright/` rather than `src/tests/`.
+
---
## Golden Rules
1. **Test behavior, not implementation** - Query by role/text, not class names
2. **One assertion per concept** - Tests should be focused
3. **Mock at boundaries** - Mock API calls, not internal functions
4. **Co-locate integration tests** - Keep `__tests__/` folder next to the component
5. **E2E is expensive** - Only for critical happy paths; prefer integration tests
6. **AI agents are good at writing integration tests** - Start with these when adding test coverage
+ 7. **Prefer component/page tests over hook tests** - Don't add `renderHook()` coverage for component implementation details
+ 8. **Use generated API mocks** - Prefer Orval MSW helpers over manual API object stubs