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:
getByRole- Best for accessibilitygetByLabelText- Good for form elementsgetByPlaceholderText- Alternative for inputsgetByText- For non-interactive elementsgetByTestId- 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.