Skip to main content

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:

  1. ✅ Installs dependencies
  2. ✅ Runs all unit tests with coverage
  3. ✅ Publishes test results (visible in PR "Tests" tab)
  4. ✅ Publishes code coverage (visible in PR "Code Coverage" tab)
  5. ✅ Runs linting validation
  6. ✅ 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

FlagPurpose
--ciOptimized for CI environments (no watch mode, better error output)
--silentReduces console noise
--coverageGenerates code coverage data
--coverageReporters=coberturaXML format for Azure DevOps Code Coverage tab
--coverageReporters=textConsole output summary
--reporters=defaultStandard Jest console output
--reporters=jest-junitJUnit 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:

  1. Navigate to your Pull Request
  2. Click on the Checks or Build status
  3. 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:

  1. Navigate to your Pull Request
  2. Click on the Checks or Build status
  3. 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:

FilePurpose
coverage/junit.xmlJUnit test results for Azure DevOps
coverage/cobertura-coverage.xmlCode coverage for Azure DevOps
coverage/coverage-summary.jsonCoverage summary (optional)

Troubleshooting

Tests Pass Locally but Fail in CI

  1. Check for timing issues - Use waitFor for async operations
  2. Check for environment differences - Mock environment variables
  3. 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

  1. Verify cobertura-coverage.xml is generated in the coverage/ folder
  2. Check that summaryFileLocation path is correct in the pipeline
  3. Ensure condition: succeededOrFailed() is set so report publishes even on test failure

Test Results Not Showing

  1. Verify junit.xml is generated in the coverage/ folder
  2. Check environment variables are set correctly:
    env:
    JEST_JUNIT_OUTPUT_DIR: $(Build.SourcesDirectory)/coverage
    JEST_JUNIT_OUTPUT_NAME: junit.xml
  3. Ensure condition: succeededOrFailed() is set

Best Practices for CI Tests

  1. Keep tests fast - CI runs all tests on every PR
  2. Avoid flaky tests - Tests should pass consistently
  3. Use timeouts appropriately - Set reasonable timeouts for async operations
  4. Mock external services - Don't make real API calls in tests
  5. 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:

VariableValuePurpose
JEST_JUNIT_OUTPUT_DIR$(Build.SourcesDirectory)/coverageWhere to save JUnit XML
JEST_JUNIT_OUTPUT_NAMEjunit.xmlName 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 development branch