Skip to main content

Implementing Testing Workflows

1. Running Unit Tests

Property Description Example
uses Specifies the action to run, e.g., actions/checkout@v4 uses: actions/checkout@v4
with Parameters to pass into the action with: token: ${{ secrets.GITHUB_TOKEN }}
steps List of steps to run in the workflow steps: - name: Run tests

Example: Running Unit Tests with Jest

name: Run Unit Tests
on:
  push:
    branches: [ main ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test
Note: Ensure your project's package.json includes a test script like "test": "jest".

2. Running Integration Tests

Property Description Example
jobs.<job_id>.steps Defines the steps to run in a job, including integration tests.
- name: Run integration tests
  run: npm run test:integration
jobs.<job_id>.steps.run Command to execute for running tests. npm run test:integration
jobs.<job_id>.steps.env Environment variables for test execution.
env:
  NODE_ENV: test
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

Example: Running Integration Tests in a Workflow

name: Integration Tests
on:
  push:
    branches: [ main ]
jobs:
  integration-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm ci
      - name: Run integration tests
        run: npm run test:integration
        env:
          NODE_ENV: test
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
Note: Ensure that your integration tests are isolated and do not interfere with other test suites or production systems.

3. Running E2E Tests

Option Values Description
uses actions/checkout@v4 Checks out your repository code
uses actions/setup-node@v4 Sets up Node.js environment
with.node-version 20 Version of Node.js to use
run npm install Installs project dependencies
run npm run test:e2e Runs end-to-end tests

Example: E2E Test Workflow

name: E2E Tests
on:
  push:
    branches: [ main ]
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install
      - run: npm run test:e2e
Note: Ensure your E2E tests are configured to run in a headless browser environment.

4. Generating Test Coverage

Example: Setting up coverage reporting with Jest

{
  "scripts": {
    "test": "jest --coverage"
  }
}
Option Values Description
jest --coverage true Enables coverage reporting in Jest
coverageDirectory coverage Directory where coverage reports are stored
collectCoverageFrom ["src/**/*.{js,ts}"] Patterns to include in coverage report
Note: Coverage reports are generated in coverage/lcov-report/index.html by default.

Example: Configuring coverage thresholds

{
  "coverageThreshold": {
    "global": {
      "branches": 80,
      "functions": 80,
      "lines": 80,
      "statements": 80
    }
  }
}

Test Coverage Tools Comparison

  • Jest: Built-in coverage support, easy to configure
  • Istanbul : Low-level coverage tool used by Jest and other tools
  • C8: Simple, fast coverage tool for Node.js

5. Uploading Coverage Reports

Example: Upload coverage report to Codecov

name: Test and Upload Coverage
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm ci
      - name: Run tests with coverage
        run: npm run test -- --coverage
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
Property Description Default
file Path to the coverage report file (e.g., coverage/lcov.info) ./coverage/lcov.info
flags Upload flags to categorize the report (e.g., unit, e2e) None
name Custom name for the upload (optional) None
token Codecov upload token (optional, but recommended for private repos) None
Note: Ensure your test command outputs coverage data in a supported format (e.g., lcov, cobertura) for successful upload.
Warning: If token is not provided, the upload will fail for private repositories.

6. Running Linters

Tool Configuration Notes
ESLint eslint --fix Automatically fixes fixable linting errors
Prettier prettier --write . Formats code according to style guide
Stylelint stylelint "**/*.css" --fix Lints CSS files for style issues

Example: ESLint Configuration

{
  "extends": ["eslint:recommended"],
  "rules": {
    "no-console": "warn",
    "semi": ["error", "always"]
  }
}

Example: Prettier Configuration

{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true
}

Workflow Steps for Linting

  1. Install dependencies using npm install
  2. Run linter checks with npm run lint
  3. Fix any issues reported by the linter
Note: Ensure that linting runs before tests to maintain code quality standards.

7. Running Code Formatters

Formatter Command Notes
Prettier npx prettier --write . Formats JavaScript, TypeScript, CSS, HTML, and more
ESLint npx eslint . --fix Fixes linting issues automatically
Black black . Python code formatter
gofmt gofmt -w . Go code formatter

Example: Prettier in GitHub Actions

name: Format Code
on: [push, pull_request]
jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install Prettier
        run: npm install --save-dev prettier
      - name: Format with Prettier
        run: npx prettier --write .
Note: Ensure your formatter is installed in the workflow environment before running it.

8. Running Type Checkers

Checker Command Notes
TypeScript npx tsc --noEmit Checks TypeScript files for type errors without emitting JavaScript
ESLint with TypeScript npx eslint . --ext .ts,.tsx Combines linting and type checking for TypeScript files
JSDoc Type Checker npx jsdoc -c jsdoc.conf.json Validates JSDoc annotations in JavaScript files

Example: Running TypeScript Checks in GitHub Actions

name: Type Check
on: [push, pull_request]
jobs:
  type-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install
      - run: npx tsc --noEmit

9. Using Test Reporters

Reporter Description Usage Notes
junit Generates JUnit XML reports for test results reporter: junit Commonly used with CI tools like Jenkins or TeamCity
json Outputs test results in JSON format reporter: json Useful for parsing and integrating with other systems
lcov Generates coverage reports in LCOV format reporter: lcov Used with tools like Codecov for coverage analysis
spec Displays test results in a readable, spec-style format reporter: spec Default for many test runners, easy to read in logs

Example: Using JUnit Reporter

name: Test with JUnit
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests with JUnit reporter
        run: |
          npm install
          npm test -- --reporter=junit
      - name: Upload JUnit report
        uses: actions/upload-artifact@v4
        with:
          name: junit-report
          path: junit.xml
Note: Ensure that the test runner supports the specified reporter format. Some runners may require additional configuration or plugins to generate reports in specific formats.

10. Failing on Low Coverage

Option Values Notes
coverage.threshold 80 Minimum coverage percentage required to pass the workflow
coverage.fail-on-low true Set to true to fail the workflow if coverage is below threshold
coverage.job test The job name that generates coverage data

Example: Configuring Coverage Failures

name: Test and Coverage
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests with coverage
        run: |
          npm install
          npm test -- --coverage
      - name: Fail if coverage is low
        if: ${{ failure() }}
        run: |
          echo "Coverage below threshold"
          exit 1
Note: Ensure your test suite generates coverage reports in a format compatible with tools like nyc or cobertura.

11. Running Tests in Parallel

Option Values Notes
strategy.matrix max-parallel: 4 Maximum number of parallel jobs
strategy.fail-fast true Stop running jobs if one fails
strategy.max-parallel 8 Maximum number of parallel jobs (default: 4)

Example: Parallel Test Jobs

jobs:
  test:
    strategy:
      matrix:
        node-version: [14.x, 16.x, 18.x]
        os: [ubuntu-latest, windows-latest]
      max-parallel: 4
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      - name: Run Tests
        run: npm test
Note: Parallel jobs run in separate environments and do not share state.
Warning: Ensure tests are isolated to prevent race conditions.

Best Practices for Parallel Testing

  • Use strategy.matrix to define test variations
  • Limit max-parallel to avoid resource exhaustion
  • Ensure tests do not depend on each other's state
  • Use fail-fast: true to stop on first failure

12. Using Test Fixtures

Fixture Type Description Usage Example
Test Data Static data used to set up test scenarios
- name: Set up test data
  run: |
    echo 'user_id=12345' >> $GITHUB_ENV
Mock Services Simulated external services to isolate tests
- name: Start mock server
  run: |
    npm run mock-server && echo "Mock server started"
Database Snapshots Predefined database states for consistent testing
- name: Load database snapshot
  run: |
    psql -d testdb < snapshot.sql

Example: Setting Up a Test Fixture

- name: Prepare test environment
  run: |
    # Create a temporary directory for fixtures
    mkdir -p ./fixtures
    # Copy test data files
    cp -r ./test-data/* ./fixtures/
    # Set environment variables for test run
    echo "FIXTURE_DIR=./fixtures" >> $GITHUB_ENV
Note: Fixtures should be lightweight and reproducible to ensure reliable test runs.
Warning: Avoid modifying global state or shared resources in fixtures as it can lead to test interference.

Was this article helpful?