Tests in the Pipeline
This guide covers how unit tests are integrated into the Azure DevOps CI/CD pipeline for Pull Requests.
Pipeline Overview
When you create a Pull Request targeting the development branch, the PR validation pipeline automatically:
- ✅ Installs dependencies
- ✅ Runs all unit tests with coverage
- ✅ Publishes test results (visible in PR "Tests" tab)
- ✅ Publishes code coverage (visible in PR "Code Coverage" tab)
- ✅ Runs linting validation
- ✅ Optionally runs Chromatic visual tests
Pipeline Configuration
The PR job is defined in devops/jobs/pr-job.yml:
jobs:
- job: PRValidation
displayName: 'PR Validation for Development'
condition: and(
eq(variables['Build.Reason'], 'PullRequest'),
eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/development')
)
steps:
# ... checkout and setup steps ...
- script: npm run test:ci
displayName: 'Run Unit Tests'
env:
JEST_JUNIT_OUTPUT_DIR: $(Build.SourcesDirectory)/coverage
JEST_JUNIT_OUTPUT_NAME: junit.xml
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/junit.xml'
searchFolder: '$(Build.SourcesDirectory)/coverage'
mergeTestResults: true
testRunTitle: 'Unit Tests'
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@2
displayName: 'Publish Code Coverage'
inputs:
summaryFileLocation: '$(Build.SourcesDirectory)/coverage/cobertura-coverage.xml'
pathToSources: '$(Build.SourcesDirectory)'
condition: succeededOrFailed()
Test Script Configuration
The test:ci script in package.json is configured to generate reports for Azure DevOps:
{
"scripts": {
"test:ci": "jest --ci --silent --coverage --coverageReporters=cobertura --coverageReporters=text --reporters=default --reporters=jest-junit"
}
}
Script Flags Explained
| Flag | Purpose |
|---|---|
--ci | Optimized for CI environments (no watch mode, better error output) |
--silent | Reduces console noise |
--coverage | Generates code coverage data |
--coverageReporters=cobertura | XML format for Azure DevOps Code Coverage tab |
--coverageReporters=text | Console output summary |
--reporters=default | Standard Jest console output |
--reporters=jest-junit | JUnit XML for Azure DevOps Tests tab |
Viewing Results in Azure DevOps
Test Results Tab
After a pipeline run completes, view test results in the PR:
- Navigate to your Pull Request
- Click on the Checks or Build status
- Select the Tests tab
You'll see:
- ✅ Total tests passed/failed
- 📊 Test duration
- 📋 Individual test names and status
- ❌ Failure details with stack traces (if any)
Code Coverage Tab
View code coverage in the PR:
- Navigate to your Pull Request
- Click on the Checks or Build status
- Select the Code Coverage tab
You'll see:
- 📊 Overall coverage percentage
- 📁 Coverage by file/folder
- 🔍 Line-by-line coverage highlighting
- 📈 Coverage trends (if configured)
Required Dependencies
Ensure these packages are installed for CI reporting:
{
"devDependencies": {
"jest": "^29.7.0",
"jest-junit": "^16.0.0"
}
}
Generated Files
The test run generates these files in the coverage/ directory:
| File | Purpose |
|---|---|
coverage/junit.xml | JUnit test results for Azure DevOps |
coverage/cobertura-coverage.xml | Code coverage for Azure DevOps |
coverage/coverage-summary.json | Coverage summary (optional) |
Troubleshooting
Tests Pass Locally but Fail in CI
- Check for timing issues - Use
waitForfor async operations - Check for environment differences - Mock environment variables
- Check for memory issues - CI may have memory limits
// ❌ May fail in CI due to timing
expect(screen.getByText('Data')).toBeInTheDocument();
// ✅ Better - waits for async render
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument();
});
Coverage Report Not Showing
- Verify
cobertura-coverage.xmlis generated in thecoverage/folder - Check that
summaryFileLocationpath is correct in the pipeline - Ensure
condition: succeededOrFailed()is set so report publishes even on test failure
Test Results Not Showing
- Verify
junit.xmlis generated in thecoverage/folder - Check environment variables are set correctly:
env:
JEST_JUNIT_OUTPUT_DIR: $(Build.SourcesDirectory)/coverage
JEST_JUNIT_OUTPUT_NAME: junit.xml - Ensure
condition: succeededOrFailed()is set
Best Practices for CI Tests
- Keep tests fast - CI runs all tests on every PR
- Avoid flaky tests - Tests should pass consistently
- Use timeouts appropriately - Set reasonable timeouts for async operations
- Mock external services - Don't make real API calls in tests
- Run tests locally first - Verify tests pass before pushing
// Set custom timeout for slow tests
jest.setTimeout(10000); // 10 seconds
// Or per-test timeout
test('slow operation', async () => {
// ...
}, 15000);
Environment Variables
The CI pipeline sets these environment variables for test reporting:
| Variable | Value | Purpose |
|---|---|---|
JEST_JUNIT_OUTPUT_DIR | $(Build.SourcesDirectory)/coverage | Where to save JUnit XML |
JEST_JUNIT_OUTPUT_NAME | junit.xml | Name of JUnit XML file |
Pipeline Conditions
Tests and reports run under these conditions:
- Test execution: Always runs when pipeline runs
- Report publishing: Runs even if tests fail (
condition: succeededOrFailed()) - PR validation: Only runs for PRs targeting
developmentbranch