Skip to content
GeeksSmith
intermediate 9 min read

Frontend Testing Strategy (Unit, Integration, E2E, MSW, a11y)

A resilient frontend testing strategy balances fast unit tests (Vitest/Jest) for pure utility logic, component integration tests (React Testing Library + MSW) testing user behavior from the user's perspective, automated accessibility checks (axe-core), and focused end-to-end smoke flows (Playwright).

Why it matters in interviews

Testing implementation details (like component internal state or shallow rendering) leads to brittle test suites that break on every refactor without catching real production regressions. Staff-level candidates must articulate the 'Testing Trophy' philosophy and MSW network mocking.

Visual & Interactive Explanation

Interactive Flow Execution

Code Examples & Implementation

Behavior-Driven Component Test with React Testing Library and MSW
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import { LoginForm } from './LoginForm';

// 1. Mock network request using MSW (network level, not mocking fetch directly)
const server = setupServer(
  http.post('/api/login', async ({ request }) => {
    const { email } = await request.json() as any;
    if (email === 'admin@test.com') {
      return HttpResponse.json({ user: { name: 'Admin User' } });
    }
    return new HttpResponse(null, { status: 401 });
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('submits login form and displays welcome message on success', async () => {
  const user = userEvent.setup();
  render(<LoginForm />);

  // 2. Query by accessible role (matches how screen readers and users see UI)
  const emailInput = screen.getByRole('textbox', { name: /email/i });
  const passwordInput = screen.getByLabelText(/password/i);
  const submitButton = screen.getByRole('button', { name: /sign in/i });

  // 3. Simulate user interactions
  await user.type(emailInput, 'admin@test.com');
  await user.type(passwordInput, 'Secret123!');
  await user.click(submitButton);

  // 4. Assert user-visible outcome
  expect(await screen.findByText(/welcome back, admin user/i)).toBeInTheDocument();
});

Interview-Ready Answers

Follow Kent C. Dodds' Testing Trophy: prioritize Component Integration tests using React Testing Library and MSW, supported by fast unit tests for pure algorithms, automated axe-core accessibility checks, and critical-path Playwright E2E tests.

Official Documentation & Specifications

Follow-up Questions & Deep Dives

Common Mistakes & Anti-Patterns

  • Testing component internal state (e.g. wrapper.state('count')) instead of asserting on DOM text and accessibility attributes.
  • Using fireEvent instead of userEvent (userEvent faithfully dispatches all accompanying mouse, keyboard, and focus events).
  • Writing hundreds of slow, flaky E2E tests for minor UI variants instead of covering them with fast Integration tests.

Real-World Architectural Scenario

A team's test suite contains 4,000 Enzyme unit tests that take 35 minutes to run and fail on every minor CSS refactor without catching real bugs. How do you lead a testing overhaul?

Rate Your Readiness

Rate how comfortably you can explain this in an interview to update your global readiness gauge:

Rate your confidence: