Node.js Setup Guide

Introduction

This guide will help you integrate OtterWise with your Node.js project to track code coverage. OtterWise supports all major Node.js testing frameworks and works with both JavaScript and TypeScript projects.

Whether you're building APIs with Express, full-stack applications with Next.js, or enterprise applications with NestJS, this guide covers the setup for your specific use case.

Prerequisites

Before setting up OtterWise for your Node.js project, you'll need:

  • A GitHub repository connected to OtterWise
  • Node.js installed (version 18.x or higher recommended)
  • A testing framework configured in your project
  • Your OtterWise repository token (found in your repository settings after enabling it in OtterWise)

Supported Coverage Formats

OtterWise supports the following coverage formats for Node.js projects:

  • LCOV - The most common format, supported by all major Node.js coverage tools
  • Clover XML - Alternative XML format (less common for Node.js but supported)

We recommend using LCOV format as it's the standard for JavaScript/TypeScript projects.

Setup with Jest

Jest is the most popular testing framework for Node.js projects. It includes built-in code coverage support powered by Istanbul.

Installation

If you haven't already installed Jest, add it to your project:

npm install --save-dev jest

For TypeScript projects, you'll also need:

npm install --save-dev @types/jest ts-jest

Configuration

Create or update your jest.config.js file to enable coverage collection:

module.exports = {
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['lcov', 'text'],
  collectCoverageFrom: [
    'src/**/*.{js,jsx,ts,tsx}',
    '!src/**/*.d.ts',
    '!src/**/*.test.{js,jsx,ts,tsx}',
  ],
};

Running Tests with Coverage

Add a coverage script to your package.json:

{
  "scripts": {
    "test": "jest",
    "test:coverage": "jest --coverage"
  }
}

Run tests with coverage:

npm run test:coverage

This will generate a coverage report at coverage/lcov.info.

Uploading to OtterWise

After generating the coverage report, upload it to OtterWise using the bash uploader:

# Using environment variable
export OTTERWISE_TOKEN=your-repo-token
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh)

# Or pass token directly
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) --repo-token your-repo-token

Setup with Vitest

Vitest is a blazing-fast unit test framework powered by Vite. It's particularly popular for modern TypeScript projects and Vue/React applications.

Installation

npm install --save-dev vitest @vitest/coverage-v8

Vitest supports multiple coverage providers. We recommend @vitest/coverage-v8 (default) or @vitest/coverage-istanbul.

Configuration

Add coverage configuration to your vite.config.ts or vitest.config.ts:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['lcov', 'text'],
      include: ['src/**/*.{js,ts,jsx,tsx}'],
      exclude: ['src/**/*.test.{js,ts,jsx,tsx}', 'src/**/*.d.ts'],
    },
  },
})

Running Tests with Coverage

Add scripts to your package.json:

{
  "scripts": {
    "test": "vitest",
    "test:coverage": "vitest --coverage"
  }
}

Run tests with coverage:

npm run test:coverage

This will generate a coverage report at coverage/lcov.info.

Setup with Mocha + NYC

Mocha is a flexible testing framework that requires a separate coverage tool. NYC (Istanbul CLI) is the most popular choice.

Installation

npm install --save-dev mocha nyc

Configuration

Create a .nycrc.json file in your project root:

{
  "all": true,
  "include": ["src/**/*.js", "src/**/*.ts"],
  "exclude": [
    "src/**/*.test.js",
    "src/**/*.spec.js",
    "src/**/*.d.ts"
  ],
  "reporter": ["lcov", "text"],
  "report-dir": "coverage"
}

Running Tests with Coverage

Add scripts to your package.json:

{
  "scripts": {
    "test": "mocha",
    "test:coverage": "nyc mocha"
  }
}

Run tests with coverage:

npm run test:coverage

Setup with Node.js Native Test Runner + c8

Node.js 18+ includes a built-in test runner. For coverage, you can use c8, a native V8 coverage tool.

Installation

npm install --save-dev c8

Configuration

Create a .c8rc.json file:

{
  "all": true,
  "include": ["src/**/*.js", "src/**/*.mjs"],
  "exclude": ["src/**/*.test.js", "src/**/*.spec.js"],
  "reporter": ["lcov", "text"],
  "report-dir": "coverage"
}

Running Tests with Coverage

Add scripts to your package.json:

{
  "scripts": {
    "test": "node --test",
    "test:coverage": "c8 node --test"
  }
}

Framework-Specific Setup

Next.js

Next.js projects typically use Jest. Follow the Jest setup instructions above, but use this Jest configuration optimized for Next.js:

// jest.config.js
const nextJest = require('next/jest')

const createJestConfig = nextJest({
  dir: './',
})

const customJestConfig = {
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['lcov', 'text'],
  collectCoverageFrom: [
    'app/**/*.{js,jsx,ts,tsx}',
    'pages/**/*.{js,jsx,ts,tsx}',
    'components/**/*.{js,jsx,ts,tsx}',
    'lib/**/*.{js,jsx,ts,tsx}',
    '!**/*.d.ts',
    '!**/node_modules/**',
    '!**/.next/**',
  ],
  testEnvironment: 'jest-environment-jsdom',
}

module.exports = createJestConfig(customJestConfig)

NestJS

NestJS projects use Jest by default. The framework provides built-in testing utilities. Use this configuration:

// jest.config.js or package.json jest section
{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": "src",
  "testRegex": ".*\\.spec\\.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  },
  "collectCoverage": true,
  "coverageDirectory": "../coverage",
  "coverageReporters": ["lcov", "text"],
  "collectCoverageFrom": [
    "**/*.(t|j)s",
    "!**/*.spec.ts",
    "!**/*.module.ts",
    "!**/main.ts"
  ],
  "testEnvironment": "node"
}

Express.js

Express projects work with any testing framework. We recommend Mocha + NYC or Jest. No special configuration needed beyond the standard setup for your chosen framework.

CI Integration Examples

GitHub Actions

Here's a complete example for a Node.js project using GitHub Actions with the official OtterWise action:

name: Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 2

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '20'
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run tests with coverage
      run: npm run test:coverage

    - name: Upload Coverage to OtterWise
      uses: getOtterWise/github-action@v1
      with:
        token: ${{ secrets.OTTERWISE_TOKEN }}

Important

Remember to add your OTTERWISE_TOKEN to GitHub Secrets (Settings > Secrets and variables > Actions).

GitLab CI

test:
  image: node:20
  stage: test
  script:
    - npm ci
    - npm run test:coverage
    - bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) --repo-token $OTTERWISE_TOKEN
  coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

CircleCI

version: 2.1

jobs:
  test:
    docker:
      - image: cimg/node:20.0
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package-lock.json" }}
      - run:
          name: Install Dependencies
          command: npm ci
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package-lock.json" }}
      - run:
          name: Run Tests with Coverage
          command: npm run test:coverage
      - run:
          name: Upload Coverage to OtterWise
          command: bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) --repo-token $OTTERWISE_TOKEN

workflows:
  version: 2
  test:
    jobs:
      - test

Quick Reference: Coverage Commands

Framework Command Output Location
Jest jest --coverage coverage/lcov.info
Vitest vitest --coverage coverage/lcov.info
Mocha + NYC nyc mocha coverage/lcov.info
Node.js + c8 c8 node --test coverage/lcov.info
Next.js jest --coverage coverage/lcov.info
NestJS npm run test:cov coverage/lcov.info

Monorepo Support

If you're working with a monorepo (using tools like Turborepo, Nx, or Lerna), you can use the --flag option to track coverage separately for each package:

# Upload coverage for the API package
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) \
  --repo-token $OTTERWISE_TOKEN \
  --file ./packages/api/coverage/lcov.info \
  --flag api

# Upload coverage for the web package
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) \
  --repo-token $OTTERWISE_TOKEN \
  --file ./packages/web/coverage/lcov.info \
  --flag web

Troubleshooting

Common Issues and Solutions

Issue Solution
Coverage file not found
  • Verify the coverage command runs successfully
  • Check that coverage/lcov.info exists after running tests
  • Use --file flag to specify custom location
Low coverage reported
  • Check your collectCoverageFrom configuration
  • Ensure test files aren't included in coverage
  • Verify source files are being instrumented correctly
TypeScript files not covered
  • Ensure ts-jest or equivalent is installed
  • Include .ts and .tsx in coverage patterns
  • Check your tsconfig.json is properly configured
Authentication errors
  • Verify OTTERWISE_TOKEN is set correctly
  • Check token hasn't expired (regenerate in OtterWise if needed)
  • Ensure no extra spaces in token value
Git diff issues in CI
  • Set fetch-depth: 2 in GitHub Actions checkout
  • Ensure full git history is available in your CI
  • Check git is installed in your CI environment

Debugging Coverage Generation

To verify your coverage is being generated correctly:

# Run coverage locally
npm run test:coverage

# Check if the file exists
ls -la coverage/lcov.info

# View the first few lines to verify format
head -20 coverage/lcov.info

A valid LCOV file should look like this:

TN:
SF:/path/to/your/src/file.ts
FN:5,(anonymous_0)
FNF:1
FNH:1
FNDA:1,(anonymous_0)
DA:1,1
DA:2,1
...

Additional Upload Options

The OtterWise bash uploader supports several options for advanced use cases. See the Bash Uploader documentation for complete details.

Common options for Node.js projects:

# Specify custom coverage file location
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) \
  --repo-token $OTTERWISE_TOKEN \
  --file ./custom/path/lcov.info

# Add a flag for test suite identification
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) \
  --repo-token $OTTERWISE_TOKEN \
  --flag unit-tests

# Quiet mode for cleaner CI logs
bash <(curl -s https://raw.githubusercontent.com/getOtterWise/bash-uploader/main/uploader.sh) \
  --repo-token $OTTERWISE_TOKEN \
  --quiet

Next Steps

Once you have coverage data uploading successfully, you can:

For additional help, check our example repository or contact OtterWise support.