Skip to main content

Testing Guide

Substrate uses modern testing tools and best practices to ensure code quality and reliability.

Technology Stack

  • Test Framework: Jest 30
  • Component Testing: React Testing Library
  • Test Runner: Nx (with caching and parallelization)
  • Coverage: Built-in Jest coverage reporting
  • Mocking: Jest mock functions and module mocks

Test Types

Unit Tests

Unit tests verify individual functions, classes, and modules in isolation.

Component Tests

Component tests use React Testing Library to test React components from a user's perspective.

Integration Tests

Integration tests verify that multiple modules or components work together correctly.

Running Tests

Run All Tests

# Run tests for all projects
nx run-many --target=test

# Run tests in parallel
nx run-many --target=test --parallel=3

Run Specific Project Tests

# Test a specific package
nx test shared-components

# Test an app
nx test web

Watch Mode

# Run tests in watch mode
nx test shared-components --watch

Coverage

# Generate coverage report
nx test shared-components --coverage

# Coverage files are output to {projectRoot}/coverage

Affected Tests

Nx can run only tests affected by your changes:

# Test only affected projects
nx affected:test

# Test affected since a specific commit
nx affected:test --base=main

Test Organization

File Naming

  • Unit tests: *.spec.ts
  • Component tests: *.spec.tsx
  • Test files are colocated with source files in the same directory

Directory Structure

packages/shared-components/
├── src/
│ ├── components/
│ │ ├── button.tsx
│ │ ├── button.spec.tsx # Component test
│ │ └── __snapshots__/
│ │ └── button.spec.tsx.snap
│ └── lib/
│ ├── utils.ts
│ └── utils.spec.ts # Unit test

Best Practices

1. Test Behavior, Not Implementation

Focus on what the component or function does, not how it does it.

2. Use Descriptive Test Names

Test names should clearly describe what is being tested and under what conditions.

3. Follow Arrange-Act-Assert Pattern

Structure tests with clear Arrange, Act, and Assert phases.

4. Keep Tests Isolated

Each test should be independent and not rely on the state from other tests. Use beforeEach and afterEach to create fresh instances and clean up.

5. Mock External Dependencies

Use mocks to isolate the code under test from external dependencies.

6. Use React Testing Library Queries

Prefer queries that reflect how users interact with your app:

Query Priority:

  1. getByRole - Best for accessibility
  2. getByLabelText - Good for form elements
  3. getByPlaceholderText - Alternative for inputs
  4. getByText - For non-interactive elements
  5. getByTestId - Last resort only

7. Avoid Snapshot Tests for Everything

Use snapshot tests sparingly, only for components that rarely change and where visual consistency is critical.

8. Test Accessibility

Ensure your components are accessible by checking for proper ARIA labels and keyboard navigation.

Debugging Tests

Run Single Test File

nx test shared-components --testFile=button.spec.tsx

Run Single Test Suite

nx test shared-components --testNamePattern="Button"

Verbose Output

nx test shared-components --verbose

Debug in VS Code

Add to .vscode/launch.json:

{
"type": "node",
"request": "launch",
"name": "Jest Debug",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--runInBand", "--testPathPattern=${relativeFile}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}

Configuration

Project-Level Jest Config

Each project has its own jest.config.cts that extends the workspace preset with settings for display name, test environment, transform configuration, module file extensions, and coverage directory.

Workspace Jest Preset

The workspace-level preset is in jest.preset.js and configures coverage reporters and collection patterns.

Continuous Integration

Tests run automatically in CI/CD pipelines. The CI configuration uses Nx's affected command to run only tests for changed code.

Resources