Unit vs Integration Testing in JavaScript: What to Use When
  Every JavaScript developer faces the same question when building reliable applications: should you write more unit tests or integration tests? Choose wrong, and you’ll either spend hours debugging brittle tests or ship bugs to production. The answer isn’t about picking one over the other—it’s about understanding when each type delivers the most value.
This article clarifies the differences between unit and integration testing in JavaScript, shows you practical examples of each, and provides a decision framework for balancing both in your testing strategy.
Key Takeaways
- Unit tests verify isolated code pieces for speed and precision
 - Integration tests validate component interactions for real-world confidence
 - A 70-20-10 distribution (unit-integration-E2E) works for most JavaScript projects
 - Choose based on what you’re testing: algorithms need unit tests, workflows need integration tests
 
What Is Unit Testing?
Unit testing verifies individual pieces of code work correctly in isolation. Think of it as testing a single LEGO brick before adding it to your structure.
In JavaScript, a unit test typically focuses on:
- A single function or method
 - One component without its children
 - A specific class or module
 
Unit Test Example
// calculator.js
export function calculateDiscount(price, percentage) {
  if (percentage < 0 || percentage > 100) {
    throw new Error('Invalid percentage');
  }
  return price * (1 - percentage / 100);
}
// calculator.test.js
import { calculateDiscount } from './calculator';
test('applies 20% discount correctly', () => {
  expect(calculateDiscount(100, 20)).toBe(80);
});
test('throws error for invalid percentage', () => {
  expect(() => calculateDiscount(100, 150)).toThrow('Invalid percentage');
});
Unit tests excel at:
- Speed: Milliseconds per test since there’s no I/O or external dependencies
 - Precision: Pinpoints exact failure locations
 - Stability: Rarely breaks due to unrelated changes
 
What Is Integration Testing?
Integration testing verifies that multiple parts of your application work together correctly. Instead of testing the LEGO brick alone, you’re testing how several bricks connect.
Integration tests in JavaScript typically cover:
- Component interactions with APIs
 - Multiple modules working together
 - Database operations with business logic
 - UI components with state management
 
Integration Test Example
// userProfile.test.js
import { render, screen, waitFor } from '@testing-library/react';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import UserProfile from './UserProfile';
const server = setupServer(
  rest.get('/api/user/:id', (req, res, ctx) => {
    return res(ctx.json({ 
      id: req.params.id, 
      name: 'Jane Doe',
      role: 'Developer' 
    }));
  })
);
beforeAll(() => server.listen());
afterAll(() => server.close());
test('displays user data after loading', async () => {
  render(<UserProfile userId="123" />);
  
  expect(screen.getByText(/loading/i)).toBeInTheDocument();
  
  await waitFor(() => {
    expect(screen.getByText('Jane Doe')).toBeInTheDocument();
    expect(screen.getByText('Developer')).toBeInTheDocument();
  });
});
Integration tests provide:
- Confidence: Validates real user workflows
 - Coverage: Tests interaction between components
 - Reality: Catches issues unit tests miss
 
Discover how at OpenReplay.com.
Key Differences That Matter
Scope and Isolation
Unit tests isolate code using mocks and stubs. You control every variable. Integration tests use real implementations where possible, mocking only external boundaries like APIs or databases.
Execution Speed
Unit tests run in 1-50ms each. You can run thousands in seconds. Integration tests take 100-500ms or more. They involve setup, teardown, and sometimes real I/O.
Maintenance Cost
Unit tests break only when their specific unit changes. Integration tests can break from changes anywhere in the tested flow, requiring more investigation time.
Bug Detection
Unit tests catch logic errors and edge cases in isolated code. Integration tests catch wiring problems, incorrect assumptions, and contract violations between components.
When to Use Each Type
Write Unit Tests For:
- Pure functions: Business logic, calculations, data transformations
 - Complex algorithms: Sorting, searching, validation rules
 - Edge cases: Error handling, boundary conditions
 - Utility functions: Formatters, parsers, helpers
 
Write Integration Tests For:
- API interactions: HTTP requests, response handling
 - User workflows: Multi-step processes, form submissions
 - Component integration: Parent-child component communication
 - State management: Redux actions, Context API flows
 - Database operations: CRUD operations with business logic
 
The Practical Testing Strategy
Most successful JavaScript projects follow a 70-20-10 distribution:
- 70% Unit tests: Fast feedback, easy debugging
 - 20% Integration tests: Confidence in component interactions
 - 10% End-to-end tests: Final validation of critical paths
 
This isn’t a rigid rule—adjust based on your application type. API-heavy apps need more integration tests. Algorithm-heavy libraries need more unit tests.
CI/CD Pipeline Integration
Structure your pipeline for fast feedback:
- Pre-commit: Run unit tests (< 5 seconds)
 - Pull request: Run all unit and integration tests
 - Pre-deploy: Run full test suite including E2E tests
 
Tools like Jest for unit testing, Testing Library for integration testing, and MSW for API mocking make this pipeline efficient and maintainable.
Common Pitfalls to Avoid
- Over-mocking in integration tests: Defeats the purpose of testing interactions
 - Testing implementation details: Focus on behavior, not internal structure
 - Ignoring test speed: Slow tests discourage frequent running
 - Writing tests after bugs: Proactive testing prevents issues
 
Conclusion
Unit and integration testing in JavaScript aren’t competing strategies—they’re complementary tools. Unit tests give you speed and precision for isolated logic. Integration tests provide confidence that your components work together correctly.
Start with unit tests for business logic and pure functions. Add integration tests for critical user paths and component interactions. Skip the religious debates about testing philosophies and focus on what gives you confidence to ship code.
The best JavaScript testing strategy is the one that catches bugs before users do while keeping your development velocity high. Balance both types based on your application’s needs, and adjust as you learn what breaks most often.
FAQs
Always mock external dependencies in unit tests. This includes databases, APIs, file systems, and other services. Mocking ensures tests run fast, remain predictable, and truly test your code in isolation rather than the behavior of external systems.
Start by asking what could break. If the logic itself is complex, write unit tests first. If the feature involves multiple components talking to each other or external services, prioritize integration tests. Most features benefit from both types.
Unit tests should complete in under 10 seconds for the entire suite. Integration tests can take 1-5 minutes. If your tests take longer, split them into parallel jobs or identify slow tests that need optimization. Fast tests encourage developers to run them frequently.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.