Skip to content
intermediatePhase 40 · Testing

Integration Testing

Test component interactions and API integrations.

45m
0 problems
Topic Progress0%

What to Test

What to Test

Integration tests verify multiple units work together.

Integration vs Unit

Aspect Unit Integration
Scope Single function Multiple components
Speed Fast Slower
Isolation Fully isolated Some dependencies
Confidence Low High

What to Cover

  1. Component interactions
  2. API calls
  3. State management flows
  4. Form submissions
  5. Navigation

Testing Components Together

// Test components that work together
describe('ShoppingCart', () => {
  it('should add item and update total', async () => {
    render(
      <CartProvider>
        <ProductList />
        <CartSummary />
      </CartProvider>
    );

    // Add item
    fireEvent.click(screen.getByText('Add to Cart'));

    // Verify cart updates
    expect(screen.getByText('1 item')).toBeInTheDocument();
    expect(screen.getByText('$29.99')).toBeInTheDocument();
  });
});

Testing Forms

describe('LoginForm', () => {
  it('should submit form with valid data', async () => {
    const onSubmit = jest.fn();
    render(<LoginForm onSubmit={onSubmit} />);

    fireEvent.change(screen.getByLabelText('Email'), {
      target: { value: 'test@example.com' },
    });
    fireEvent.change(screen.getByLabelText('Password'), {
      target: { value: 'password123' },
    });
    fireEvent.click(screen.getByText('Sign In'));

    await waitFor(() => {
      expect(onSubmit).toHaveBeenCalledWith({
        email: 'test@example.com',
        password: 'password123',
      });
    });
  });
});

Testing API Calls

Testing API Calls

Mock API responses for reliable tests.

MSW (Mock Service Worker)

// src/mocks/handlers.js
import { rest } from 'msw';

export const handlers = [
  rest.get('/api/users', (req, res, ctx) => {
    return res(
      ctx.json([
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' },
      ])
    );
  }),

  rest.post('/api/users', async (req, res, ctx) => {
    const body = await req.json();
    return res(ctx.json({ id: 3, ...body }));
  }),
];

// src/mocks/server.js
import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const server = setupServer(...handlers);

Test Setup

// src/test/setup.js
import { server } from '../mocks/server';

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

Component Test

describe('UserList', () => {
  it('should display users', async () => {
    render(<UserList />);

    // Wait for data to load
    await waitFor(() => {
      expect(screen.getByText('John')).toBeInTheDocument();
      expect(screen.getByText('Jane')).toBeInTheDocument();
    });
  });

  it('should handle API error', async () => {
    server.use(
      rest.get('/api/users', (req, res, ctx) => {
        return res(ctx.status(500));
      })
    );

    render(<UserList />);

    await waitFor(() => {
      expect(screen.getByText('Error loading users')).toBeInTheDocument();
    });
  });
});

Fetch Mock

// Simple fetch mock
beforeEach(() => {
  global.fetch = jest.fn();
});

afterEach(() => {
  jest.restoreAllMocks();
});

it('should fetch data', async () => {
  global.fetch.mockResolvedValueOnce({
    ok: true,
    json: async () => ({ data: 'test' }),
  });

  const data = await fetchData();
  expect(data).toEqual({ data: 'test' });
  expect(global.fetch).toHaveBeenCalledWith('/api/data');
});

Testing User Flows

Testing User Flows

Test complete user journeys through the application.

Multi-Step Form

describe('Checkout Flow', () => {
  it('should complete checkout', async () => {
    render(<CheckoutPage />);

    // Step 1: Shipping
    fireEvent.change(screen.getByLabelText('Name'), {
      target: { value: 'John Doe' },
    });
    fireEvent.change(screen.getByLabelText('Address'), {
      target: { value: '123 Main St' },
    });
    fireEvent.click(screen.getByText('Continue'));

    // Step 2: Payment
    await waitFor(() => {
      expect(screen.getByText('Payment')).toBeInTheDocument();
    });

    fireEvent.change(screen.getByLabelText('Card Number'), {
      target: { value: '4242424242424242' },
    });
    fireEvent.click(screen.getByText('Place Order'));

    // Step 3: Confirmation
    await waitFor(() => {
      expect(screen.getByText('Order Confirmed')).toBeInTheDocument();
    });
  });
});

Navigation Flow

describe('Navigation', () => {
  it('should navigate through pages', async () => {
    render(
      <MemoryRouter>
        <App />
      </MemoryRouter>
    );

    // Start at home
    expect(screen.getByText('Home')).toBeInTheDocument();

    // Navigate to products
    fireEvent.click(screen.getByText('Products'));
    await waitFor(() => {
      expect(screen.getByText('Product List')).toBeInTheDocument();
    });

    // Navigate to product detail
    fireEvent.click(screen.getByText('Product 1'));
    await waitFor(() => {
      expect(screen.getByText('Product 1 Details')).toBeInTheDocument();
    });
  });
});

Search Flow

describe('Search', () => {
  it('should search and filter results', async () => {
    render(<SearchPage />);

    // Type search query
    fireEvent.change(screen.getByLabelText('Search'), {
      target: { value: 'laptop' },
    });

    // Wait for results
    await waitFor(() => {
      expect(screen.getByText('Laptop Pro')).toBeInTheDocument();
    });

    // Apply filter
    fireEvent.click(screen.getByText('Price: Low to High'));

    // Verify sorted results
    await waitFor(() => {
      const prices = screen.getAllByText(/\\$\\d+/);
      const priceValues = prices.map(el => 
        parseInt(el.textContent.replace('$', ''))
      );
      expect(priceValues).toEqual([...priceValues].sort((a, b) => a - b));
    });
  });
});

Practice Problems

0/3solved
Build Integration Testing Component

Create a reusable React component implementing Integration Testing. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Integration Testing Testing

Write unit and integration tests for Integration Testing using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Integration Testing Performance

Optimize Integration Testing for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What is the difference between unit and integration tests?

Question 1 options

2. What is MSW?

Question 2 options

3. What is the primary purpose of Integration Testing?

Question 3 options

4. What is a common mistake when implementing Integration Testing?

Question 4 options

Flashcards

Question

What is integration testing?

Answer

Testing multiple components working together, including API calls and user interactions.

Question

What is MSW?

Answer

Mock Service Worker - intercepts API requests for realistic testing.

Question

What should integration tests cover?

Answer

Component interactions, API calls, form submissions, and user flows.

Question

How do you test async operations?

Answer

Use waitFor() to wait for async operations to complete.

Question

What is Integration Testing?

Answer

Integration Testing is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Integration tests verify multiple components working together
  • 2.MSW provides realistic API mocking
  • 3.Test complete user flows through the application
  • 4.Use waitFor for async operations
  • 5.Integration tests give higher confidence than unit tests

Interview Tips

  • Explain the difference between unit and integration tests
  • Discuss how to mock API calls for testing
  • Know how to test user flows

Cheat Sheet

Integration Testing Cheat Sheet

What to Test

  • Component interactions
  • API calls
  • Form submissions
  • User flows
  • Navigation

MSW Setup

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

Common Patterns

  • waitFor() for async
  • fireEvent for events
  • screen queries for elements