Skip to content
intermediate Phase 12 · Testing

Integration Testing

Test component interactions and API integrations.

45m
0 problems
Topic Progress 0%

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));
    });
  });
});

Quiz

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

Question 1 options

2. What is MSW?

Question 2 options

3. What is a common mistake when implementing Integration Testing in frontend applications?

Question 3 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.

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