Have you used Jest / React Testing Library? How do you test components and API flows
Yes — Jest/Vitest as the runner, Testing Library for components (queries by role, behavior over implementation). Mock fetch with MSW for API flows (intercept network, no `fetch` mocks). Test what the user sees: roles, accessible names, behavior on click/type. Avoid testing internal state or implementation details. Coverage on critical paths; E2E (Playwright) for golden flows.
Stack
| Tool | Purpose |
|---|---|
| Jest / Vitest | Test runner + assertion library |
| React Testing Library | Render + query React components |
| @testing-library/user-event | Realistic user interactions |
| MSW (Mock Service Worker) | Mock network at the request level |
| Playwright | End-to-end |
Component test
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('login form submits', async () => {
const onSubmit = vi.fn();
render(<LoginForm onSubmit={onSubmit} />);
await userEvent.type(screen.getByLabelText(/email/i), 'a@b.c');
await userEvent.type(screen.getByLabelText(/password/i), 'pass');
await userEvent.click(screen.getByRole('button', { name: /sign in/i }));
expect(onSubmit).toHaveBeenCalledWith({ email: 'a@b.c', password: 'pass' });
});Queries by role and accessible name — same as a screen reader.
Query priority
getByRole(accessible name, role).getByLabelText(form fields).getByPlaceholderText.getByText.getByTestId(last resort).
If you can't query by role, your component probably has an a11y problem.
API flow with MSW
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
const server = setupServer(
http.get('/api/user', () => HttpResponse.json({ id: 1, name: 'Sam' })),
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test('shows user', async () => {
render(<Profile />);
expect(await screen.findByText('Sam')).toBeInTheDocument();
});MSW intercepts at the network layer — no fetch mocks, no axios mocks. Same handlers work in Storybook / Playwright.
What NOT to test
- Component internal state (
expect(component.state.x)). - Specific class names / styles (unless that's the public API).
- Hook order / implementation details.
- Pure unrelated dependencies.
Async patterns
findBy*for async appearances (waits + retries).waitForfor arbitrary async assertions.waitForElementToBeRemovedfor disappearance.
Mocking modules
vi.mock('@/lib/analytics', () => ({ track: vi.fn() }));Mock only at boundary modules (analytics, logger). Don't mock internal modules — refactor instead.
Coverage philosophy
- High coverage on critical paths (auth, checkout, save).
- Lower coverage on UI permutations (visual regression handles that).
- E2E (Playwright) for happy-path flows through real-ish stack.
Common mistakes
- Testing
expect(wrapper.find('Button').props().onClick).toBeDefined()(Enzyme leftover style). - Mocking React Query / Redux internals.
- Snapshot tests with huge JSON — diffs become noise.
- Testing implementation details that change with refactors.
Tooling
@testing-library/jest-domfor matchers (toBeInTheDocument,toHaveAccessibleName).--changedfor fast CI on PR diff.--watchlocally for fast feedback.
Interview framing
"Vitest (or Jest) + Testing Library + MSW + Playwright. Query components by role and accessible name — same as a screen reader; reaching for getByTestId is a smell. User-event for realistic interactions. MSW for API flows — mock at the network layer so handlers are reusable across Storybook and Playwright. Don't test internal state or implementation; test what the user sees. Coverage focused on critical paths; visual regression and E2E pick up where unit tests stop. Refactor instead of mocking internal modules."
Follow-up questions
- •Why prefer getByRole over getByTestId?
- •What does MSW give you over fetch mocking?
- •When would you reach for E2E vs unit?
Common mistakes
- •Testing implementation details.
- •fetch mocks instead of MSW.
- •Huge snapshot tests.
- •Testing class names.
Performance considerations
- •Vitest parallelism + happy-dom faster than jsdom for many cases.
Edge cases
- •Async timing (use findBy and waitFor).
- •Strict Mode double-rendering effects in tests.
- •Portals and getBy queries.
Real-world examples
- •Testing Library docs, Kent C. Dodds' guides, MSW examples.