---
title: JavaScript and TypeScript Tests
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: >-
  Docs > Test Optimization in Datadog > Configure Test Optimization > JavaScript
  and TypeScript Tests
---

# JavaScript and TypeScript Tests

{% callout %}
# Important note for users on the following Datadog sites: app.ddog-gov.com

{% alert level="danger" %}
This product is not supported for your selected [Datadog site](https://docs.datadoghq.com/getting_started/site). ().
{% /alert %}

{% /callout %}

## Compatibility{% #compatibility %}

Supported test frameworks:

| Test Framework | Version    | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| -------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Jest           | \>= 24.8.0 | Only `jsdom` (in the `jest-environment-jsdom` package) and `node` (in the `jest-environment-node` package) are supported as test environments. Custom environments like `@jest-runner/electron/environment` in `jest-electron-runner` are not supported.Only [`jest-circus`](https://github.com/facebook/jest/tree/main/packages/jest-circus) is supported as [`testRunner`](https://jestjs.io/docs/configuration#testrunner-string).`test.concurrent` is not supported. |
| Mocha          | \>= 5.2.0  |
| Cucumber       | \>= 7.0.0  |
| Cypress        | \>= 6.7.0  |
| Playwright     | \>= 1.18.0 |
| Vitest         | \>= 1.16.0 | Supported from `dd-trace>=4.42.0` and `dd-trace>=5.18.0`. Only supported from Node.js>=18.19 or Node.js>=20.6                                                                                                                                                                                                                                                                                                                                                            |

The instrumentation works at runtime, so any transpilers such as TypeScript, Webpack, or Babel are supported out-of-the-box.

## Configuring reporting method{% #configuring-reporting-method %}

To report test results to Datadog, you need to configure the Datadog JavaScript library:

{% tab title="CI Provider with Auto-Instrumentation Support" %}
We support auto-instrumentation for the following CI providers:

| CI Provider    | Auto-Instrumentation method                                                                                                                         |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| GitHub Actions | [Datadog Test Visibility Github Action](https://github.com/marketplace/actions/configure-datadog-test-visibility)                                   |
| Jenkins        | [UI-based configuration](https://docs.datadoghq.com/continuous_integration/pipelines/jenkins/#enable-test-optimization) with Datadog Jenkins plugin |
| GitLab         | [Datadog Test Visibility GitLab Script](https://github.com/DataDog/test-visibility-gitlab-script)                                                   |
| CircleCI       | [Datadog Test Visibility CircleCI Orb](https://circleci.com/orbs/registry/orb/datadog/test-visibility-circleci-orb)                                 |

If you are using auto-instrumentation for one of these providers, you can skip the rest of the setup steps below.

{% alert level="danger" %}
**Note**: Auto-instrumentation is not supported for Cypress tests. To instrument Cypress tests, follow the manual instrumentation steps outlined below.
{% /alert %}

{% /tab %}

{% tab title="Other Cloud CI Provider" %}

{% alert level="info" %}
Agentless mode is available in Datadog JavaScript library versions >= 2.5.0
{% /alert %}
If you are using a cloud CI provider without access to the underlying worker nodes, such as GitHub Actions or CircleCI, configure the library to use the Agentless mode. For this, set the following environment variables:
{% dl %}

{% dt %}
`DD_CIVISIBILITY_AGENTLESS_ENABLED=true` (Required)
{% /dt %}

{% dd %}
Enables or disables Agentless mode.**Default**: `false`
{% /dd %}

{% dt %}
`DD_API_KEY` (Required)
{% /dt %}

{% dd %}
The [Datadog API key](https://app.datadoghq.com/organization-settings/api-keys) used to upload the test results.**Default**: `(empty)`
{% /dd %}

{% /dl %}

Additionally, configure the [Datadog site](https://docs.datadoghq.com/getting_started/site/) to which you want to send data.

{% dl %}

{% dt %}
`DD_SITE` (Required)
{% /dt %}

{% dd %}
The [Datadog site](https://docs.datadoghq.com/getting_started/site/) to upload results to.**Default**: `datadoghq.com`
{% /dd %}

{% /dl %}

{% /tab %}

{% tab title="On-Premises CI Provider" %}
If you are running tests on an on-premises CI provider, such as Jenkins or self-managed GitLab CI, install the Datadog Agent on each worker node by following the [Agent installation instructions](https://docs.datadoghq.com/agent/). This is the recommended option as it allows you to automatically link test results to [logs](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/) and [underlying host metrics](https://docs.datadoghq.com/infrastructure/).

If you are using a Kubernetes executor, Datadog recommends using the [Datadog Operator](https://docs.datadoghq.com/containers/datadog_operator/). The operator includes [Datadog Admission Controller](https://docs.datadoghq.com/agent/cluster_agent/admission_controller/) which can automatically [inject the tracer library](https://docs.datadoghq.com/tracing/trace_collection/library_injection_local/?tab=kubernetes) into the build pods. **Note:** If you use the Datadog Operator, there is no need to download and inject the tracer library since the Admission Controller can do this for you, so you can skip the corresponding step below. However, you still need to make sure that your pods set the environment variables or command-line parameters necessary to enable Test Visibility.

If you are not using Kubernetes or can't use the Datadog Admission Controller and the CI provider is using a container-based executor, set the `DD_TRACE_AGENT_URL` environment variable (which defaults to `http://localhost:8126`) in the build container running the tracer to an endpoint that is accessible from within that container. **Note:** Using `localhost` inside the build references the container itself and not the underlying worker node or any container where the Agent might be running in.

`DD_TRACE_AGENT_URL` includes the protocol and port (for example, `http://localhost:8126`) and takes precedence over `DD_AGENT_HOST` and `DD_TRACE_AGENT_PORT`, and is the recommended configuration parameter to configure the Datadog Agent's URL for CI Visibility.

If you still have issues connecting to the Datadog Agent, use the Agentless Mode. **Note:** When using this method, tests are not correlated with [logs](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/) and [infrastructure metrics](https://docs.datadoghq.com/infrastructure/).
{% /tab %}

## Installing the JavaScript tracer{% #installing-the-javascript-tracer %}

To install the [JavaScript Tracer](https://docs.datadoghq.com/tracing/trace_collection/dd_libraries/nodejs), run:

```bash
yarn add --dev dd-trace
```

For more information, see the [JavaScript Tracer installation documentation](https://github.com/DataDog/dd-trace-js#version-release-lines-and-maintenance).

## Instrument your tests{% #instrument-your-tests %}

{% tab title="Jest/Mocha" %}
Set the `NODE_OPTIONS` environment variable to `-r dd-trace/ci/init`. Run your tests as you normally would, optionally specifying a name for your test session with `DD_TEST_SESSION_NAME`:

```bash
NODE_OPTIONS="-r dd-trace/ci/init" DD_TEST_SESSION_NAME=unit-tests yarn test
```

**Note**: If you set a value for `NODE_OPTIONS`, make sure it does not overwrite `-r dd-trace/ci/init`. This can be done using the `${NODE_OPTIONS:-}` clause:

In the `package.json` file:

```json
{
  "scripts": {
    "test": "NODE_OPTIONS=\"--max-old-space-size=12288 ${NODE_OPTIONS:-}\" jest"
  }
}
```

### Adding custom tags to tests{% #adding-custom-tags-to-tests %}

You can add custom tags to your tests by using the current active span:

```javascript
  it('sum function can sum', () => {
    const testSpan = require('dd-trace').scope().active()
    testSpan.setTag('team_owner', 'my_team')
    // test continues normally
    // ...
  })
```

To create filters or `group by` fields for these tags, you must first create facets. For more information about adding tags, see the [Adding Tags](https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/nodejs?tab=locally#adding-tags) section of the Node.js custom instrumentation documentation.

### Adding custom measures to tests{% #adding-custom-measures-to-tests %}

Just like tags, you can add custom measures to your tests by using the current active span:

```javascript
  it('sum function can sum', () => {
    const testSpan = require('dd-trace').scope().active()
    testSpan.setTag('memory_allocations', 16)
    // test continues normally
    // ...
  })
```

For more information about custom measures, see the [Add Custom Measures Guide](https://docs.datadoghq.com/tests/guides/add_custom_measures/?tab=javascripttypescript).

### Mocha ECMAScript modules (ESM){% #mocha-ecmascript-modules-esm %}

[Mocha >=9.0.0](https://github.com/mochajs/mocha/releases/tag/v9.0.0) uses an ESM-first approach to load test files. Set `NODE_OPTIONS` to `-r dd-trace/ci/init --import dd-trace/register.js` to get full visibility into your tests. See [`dd-trace-js` ESM support](https://github.com/datadog/dd-trace-js?tab=readme-ov-file#ecmascript-modules-esm-support) for more information.
{% /tab %}

{% tab title="Playwright" %}
Set the `NODE_OPTIONS` environment variable to `-r dd-trace/ci/init`. Run your tests as you normally would, optionally specifying a name for your test session with `DD_TEST_SESSION_NAME`:

```bash
NODE_OPTIONS="-r dd-trace/ci/init" DD_TEST_SESSION_NAME=e2e-tests yarn test:e2e
```

**Note**: If you set a value for `NODE_OPTIONS`, make sure it does not overwrite `-r dd-trace/ci/init`. This can be done using the `${NODE_OPTIONS:-}` clause:

In the `package.json` file:

```json
{
  "scripts": {
    "test": "NODE_OPTIONS=\"--max-old-space-size=12288 ${NODE_OPTIONS:-}\" jest"
  }
}
```

### Adding custom tags to tests{% #adding-custom-tags-to-tests %}

You can add custom tags to your tests by using the [custom annotations API from Playwright](https://playwright.dev/docs/test-annotations#custom-annotations):

```javascript
test('user profile', async ({ page }) => {
  test.info().annotations.push({
    type: 'DD_TAGS[test.memory.usage]', // DD_TAGS is mandatory and case sensitive
    description: 'low',
  });
  test.info().annotations.push({
    type: 'DD_TAGS[test.task.id]',
    description: '41123',
  });
  // ...
});

test('landing page', async ({ page }) => {
  test.info().annotations.push({
    type: 'DD_TAGS[test.cpu.usage]',
    description: 'high',
  });
  // ...
});
```

The format of the annotations is the following, where `$TAG_NAME` and `$TAG_VALUE` are *strings* representing tag name and value respectively:

```json
{
  "type": "DD_TAGS[$TAG_NAME]",
  "description": "$TAG_VALUE"
}
```

### Adding custom measures to tests{% #adding-custom-measures-to-tests %}

Custom measures also use custom annotations:

```javascript
test('user profile', async ({ page }) => {
  test.info().annotations.push({
    type: 'DD_TAGS[test.memory.allocations]', // DD_TAGS is mandatory and case sensitive
    description: 16, // this is a number
  });
});
```

The format of the annotations is the following, where `$TAG_NAME` is a *string* representing the tag name and `$TAG_VALUE` is a *number* representing the tag value:

```json
{
  "type": "DD_TAGS[$TAG_NAME]",
  "description": $TAG_VALUE
}
```

**Note**: `description` values in annotations are [typed as strings](https://playwright.dev/docs/api/class-testinfo#test-info-annotations). Numbers also work, but you may need to disable the typing error with `// @ts-expect-error`.

{% alert level="danger" %}
**Important**: The `DD_TAGS` prefix is mandatory and case sensitive.
{% /alert %}

### Playwright - RUM integration{% #playwright---rum-integration %}

If the browser application being tested is instrumented using [Browser Monitoring](https://docs.datadoghq.com/real_user_monitoring/application_monitoring/browser/setup/), the Playwright test results and their generated RUM browser sessions and session replays are automatically linked. For more information, see the [Instrumenting your browser tests with RUM guide](https://docs.datadoghq.com/continuous_integration/guides/rum_integration/).
{% /tab %}

{% tab title="Cucumber" %}
Set the `NODE_OPTIONS` environment variable to `-r dd-trace/ci/init`. Run your tests as you normally would, optionally specifying a name for your test session with `DD_TEST_SESSION_NAME`:

```bash
NODE_OPTIONS="-r dd-trace/ci/init" DD_TEST_SESSION_NAME=integration-tests yarn test:integration
```

**Note**: If you set a value for `NODE_OPTIONS`, make sure it does not overwrite `-r dd-trace/ci/init`. This can be done using the `${NODE_OPTIONS:-}` clause:

In the `package.json` file:

```json
{
  "scripts": {
    "test": "NODE_OPTIONS=\"--max-old-space-size=12288 ${NODE_OPTIONS:-}\" jest"
  }
}
```

### Adding custom tags to tests{% #adding-custom-tags-to-tests %}

You can add custom tags to your test by grabbing the current active span:

```javascript
  When('the function is called', function () {
    const stepSpan = require('dd-trace').scope().active()
    testSpan.setTag('team_owner', 'my_team')
    // test continues normally
    // ...
  })
```

To create filters or `group by` fields for these tags, you must first create facets. For more information about adding tags, see the [Adding Tags](https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/nodejs?tab=locally#adding-tags) section of the Node.js custom instrumentation documentation.

### Adding custom measures to tests{% #adding-custom-measures-to-tests %}

You may also add custom measures to your test by grabbing the current active span:

```javascript
  When('the function is called', function () {
    const stepSpan = require('dd-trace').scope().active()
    testSpan.setTag('memory_allocations', 16)
    // test continues normally
    // ...
  })
```

For more information about custom measures, see the [Add Custom Measures Guide](https://docs.datadoghq.com/tests/guides/add_custom_measures/?tab=javascripttypescript).
{% /tab %}

{% tab title="Cypress" %}
### Cypress version 10 or later{% #cypress-version-10-or-later %}

Use the Cypress API documentation to [learn how to use plugins](https://docs.cypress.io/guides/tooling/plugins-guide#Using-a-plugin) for `cypress>=10`.

In your `cypress.config.js` file, set the following:

In the `cypress.config.js` file:

```javascript
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents: require('dd-trace/ci/cypress/plugin'),
    supportFile: 'cypress/support/e2e.js'
  }
})
```

Add the following line to the **top level** of your `supportFile`:

In the `cypress/support/e2e.js` file:

```javascript
// Your code can be before this line
// require('./commands')
require('dd-trace/ci/cypress/support')
// Also supported:
// import 'dd-trace/ci/cypress/support'
// Your code can also be after this line
// Cypress.Commands.add('login', (email, pw) => {})
```

If you're using other Cypress plugins, your `cypress.config.js` file should contain the following:

In the `cypress.config.js` file:

```javascript
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      // your previous code is before this line
      return require('dd-trace/ci/cypress/plugin')(on, config)
    }
  }
})
```

#### Cypress `after:run` event{% #cypress-afterrun-event %}

Datadog requires the [`after:run`](https://docs.cypress.io/api/plugins/after-run-api) Cypress event to work, and Cypress does not allow multiple handlers for that event. If you defined handlers for `after:run` already, add the Datadog handler manually by importing `'dd-trace/ci/cypress/after-run'`:

In the `cypress.config.js` file:

```javascript
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      require('dd-trace/ci/cypress/plugin')(on, config)
      // other plugins
      on('after:run', (details) => {
        // other 'after:run' handlers
        // important that this function call is returned
        return require('dd-trace/ci/cypress/after-run')(details)
      })
    }
  }
})
```

#### Cypress `after:spec` event{% #cypress-afterspec-event %}

Datadog requires the [`after:spec`](https://docs.cypress.io/api/plugins/after-spec-api) Cypress event to work, and Cypress does not allow multiple handlers for that event. If you defined handlers for `after:spec` already, add the Datadog handler manually by importing `'dd-trace/ci/cypress/after-spec'`:

In the `cypress.config.js` file:

```javascript
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      require('dd-trace/ci/cypress/plugin')(on, config)
      // other plugins
      on('after:spec', (...args) => {
        // other 'after:spec' handlers
        // Important that this function call is returned
        // Important that all the arguments are passed
        return require('dd-trace/ci/cypress/after-spec')(...args)
      })
    }
  }
})
```

### Cypress before version 10{% #cypress-before-version-10 %}

These are the instructions if you're using a version older than `cypress@10`. See the [Cypress documentation](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-100) for more information about migrating to a newer version.

1. Set [`pluginsFile`](https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests#Plugins-file) to `"dd-trace/ci/cypress/plugin"`, for example, through [`cypress.json`](https://docs.cypress.io/guides/references/configuration#cypress-json):

In the `cypress.json` file:

```json
{
  "pluginsFile": "dd-trace/ci/cypress/plugin"
}
```

If you already defined a `pluginsFile`, initialize the instrumentation with:

In the `cypress/plugins/index.js` file:

```javascript
module.exports = (on, config) => {
  // your previous code is before this line
  return require('dd-trace/ci/cypress/plugin')(on, config)
}
```
Add the following line to the **top level** of your [`supportFile`](https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests#Support-file):
In the `cypress/support/index.js` file:

```javascript
// Your code can be before this line
// require('./commands')
require('dd-trace/ci/cypress/support')
// Your code can also be after this line
// Cypress.Commands.add('login', (email, pw) => {})
```

#### Cypress `after:run` event{% #cypress-afterrun-event-1 %}

Datadog requires the [`after:run`](https://docs.cypress.io/api/plugins/after-run-api) Cypress event to work, and Cypress does not allow multiple handlers for that event. If you defined handlers for `after:run` already, add the Datadog handler manually by importing `'dd-trace/ci/cypress/after-run'`:

In the `cypress/plugins/index.js` file:

```javascript
module.exports = (on, config) => {
  // your previous code is before this line
  require('dd-trace/ci/cypress/plugin')(on, config)
  on('after:run', (details) => {
    // other 'after:run' handlers
    // important that this function call is returned
    return require('dd-trace/ci/cypress/after-run')(details)
  })
}
```

#### Cypress `after:spec` event{% #cypress-afterspec-event-1 %}

Datadog requires the [`after:spec`](https://docs.cypress.io/api/plugins/after-spec-api) Cypress event to work, and Cypress does not allow multiple handlers for that event. If you defined handlers for `after:spec` already, add the Datadog handler manually by importing `'dd-trace/ci/cypress/after-spec'`:

In the `cypress/plugins/index.js` file:

```javascript
module.exports = (on, config) => {
  // your previous code is before this line
  require('dd-trace/ci/cypress/plugin')(on, config)
  on('after:spec', (...args) => {
    // other 'after:spec' handlers
    // Important that this function call is returned
    // Important that all the arguments are passed
    return require('dd-trace/ci/cypress/after-run')(...args)
  })
}
```

Run your tests as you normally would, optionally specifying a name for your test session with `DD_TEST_SESSION_NAME`:

```shell
DD_TEST_SESSION_NAME=ui-tests yarn test:ui
```

### Adding custom tags to tests{% #adding-custom-tags-to-tests %}

To add additional information to your tests, such as the team owner, use `cy.task('dd:addTags', { yourTags: 'here' })` in your test or hooks.

For example:

```javascript
beforeEach(() => {
  cy.task('dd:addTags', {
    'before.each': 'certain.information'
  })
})
it('renders a hello world', () => {
  cy.task('dd:addTags', {
    'team.owner': 'ui'
  })
  cy.get('.hello-world')
    .should('have.text', 'Hello World')
})
```

To create filters or `group by` fields for these tags, you must first create facets. For more information about adding tags, see the [Adding Tags](https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/nodejs?tab=locally#adding-tags) section of the Node.js custom instrumentation documentation.

### Adding custom measures to tests{% #adding-custom-measures-to-tests %}

To add custom measures to your tests, such as memory allocations, use `cy.task('dd:addTags', { yourNumericalTags: 1 })` in your test or hooks.

For example:

```javascript
it('renders a hello world', () => {
  cy.task('dd:addTags', {
    'memory_allocations': 16
  })
  cy.get('.hello-world')
    .should('have.text', 'Hello World')
})
```

For more information about custom measures, see the [Add Custom Measures Guide](https://docs.datadoghq.com/tests/guides/add_custom_measures/?tab=javascripttypescript).

### Cypress - RUM integration{% #cypress---rum-integration %}

If the browser application being tested is instrumented using [Browser Monitoring](https://docs.datadoghq.com/real_user_monitoring/application_monitoring/browser/setup/), the Cypress test results and their generated RUM browser sessions and session replays are automatically linked. For more information, see the [Instrumenting your browser tests with RUM guide](https://docs.datadoghq.com/continuous_integration/guides/rum_integration/).
{% /tab %}

{% tab title="Vitest" %}

{% alert level="danger" %}
**Note**: [Vitest is ESM first](https://github.com/vitest-dev/vitest?tab=readme-ov-file#features), so its configuration is different from other test frameworks.
{% /alert %}

`vitest` and `dd-trace` require Node.js>=18.19 or Node.js>=20.6 to work.

Set the `NODE_OPTIONS` environment variable to `--import dd-trace/register.js -r dd-trace/ci/init`. Run your tests as you normally would, optionally specifying a name for your test session with `DD_TEST_SESSION_NAME`:

```bash
NODE_OPTIONS="--import dd-trace/register.js -r dd-trace/ci/init" DD_TEST_SESSION_NAME=smoke-tests yarn test:smoke
```

**Note**: If you set a value for `NODE_OPTIONS`, make sure it does not overwrite `--import dd-trace/register.js -r dd-trace/ci/init`. This can be done using the `${NODE_OPTIONS:-}` clause:

In the `package.json` file:

```json
{
  "scripts": {
    "test": "NODE_OPTIONS=\"--max-old-space-size=12288 ${NODE_OPTIONS:-}\" vitest run"
  }
}
```

### Adding custom tags or measures to tests{% #adding-custom-tags-or-measures-to-tests %}

Not supported.
{% /tab %}

### How to fix "Cannot find module 'dd-trace/ci/init'" errors{% #how-to-fix-cannot-find-module-dd-traceciinit-errors %}

When using `dd-trace`, you might encounter the following error message:

```text
 Error: Cannot find module 'dd-trace/ci/init'
```

This might be because of an incorrect usage of `NODE_OPTIONS`.

For example, if your GitHub Action looks like this:

```yml
jobs:
  my-job:
    name: Run tests
    runs-on: ubuntu-latest
    # Invalid NODE_OPTIONS
    env:
      NODE_OPTIONS: -r dd-trace/ci/init
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Install node
        uses: actions/setup-node@v3
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test
```

**Note:** This does not work because `NODE_OPTIONS` are interpreted by every node process, including `npm install`. If you try to import `dd-trace/ci/init` before it's installed, this step fails.

Your GitHub Action should instead look like this:

```yml
jobs:
  my-job:
    name: Run tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Install node
        uses: actions/setup-node@v3
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test
        env:
          NODE_OPTIONS: -r dd-trace/ci/init
```

Follow these best practices:

- Make sure the `NODE_OPTIONS` environment variable is only set to the process running tests.
- Specifically avoid defining `NODE_OPTIONS` in the global environment variables settings in your pipeline or job definition.

#### Using Yarn 2 or later{% #using-yarn-2-or-later %}

If you're using `yarn>=2` and a `.pnp.cjs` file, you might also get the same error:

```text
 Error: Cannot find module 'dd-trace/ci/init'
```

You can fix it by setting `NODE_OPTIONS` to the following:

```bash
NODE_OPTIONS="-r $(pwd)/.pnp.cjs -r dd-trace/ci/init" yarn test
```

## Reporting code coverage{% #reporting-code-coverage %}

When tests are instrumented with [Istanbul](https://istanbul.js.org/), the Datadog Tracer (v3.20.0 or later) reports it under the `test.code_coverage.lines_pct` tag for your test sessions.

You can see the evolution of the test coverage in the **Coverage** tab of a test session.

For more information, see [Code Coverage](https://docs.datadoghq.com/tests/code_coverage/?tab=javascripttypescript).

## Configuration settings{% #configuration-settings %}

The following is a list of the most important configuration settings that can be used with the tracer.

{% dl %}

{% dt %}
`test_session.name`
{% /dt %}

{% dd %}
Use it to identify a group of tests, such as `integration-tests`, `unit-tests` or `smoke-tests`.**Environment variable**: `DD_TEST_SESSION_NAME`**Default**: (CI job name + test command)**Example**: `unit-tests`, `integration-tests`, `smoke-tests`
{% /dd %}

{% dt %}
`service`
{% /dt %}

{% dd %}
Name of the service or library under test.**Environment variable**: `DD_SERVICE`**Default**: (test framework name)**Example**: `my-ui`
{% /dd %}

{% dt %}
`env`
{% /dt %}

{% dd %}
Name of the environment where tests are being run.**Environment variable**: `DD_ENV`**Default**: `none`**Examples**: `local`, `ci`
{% /dd %}

{% dt %}
`url`
{% /dt %}

{% dd %}
Datadog Agent URL for trace collection in the form `http://hostname:port`.**Environment variable**: `DD_TRACE_AGENT_URL`**Default**: `http://localhost:8126`
{% /dd %}

{% /dl %}

For more information about `service` and `env` reserved tags, see [Unified Service Tagging](https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging). All other [Datadog Tracer configuration](https://docs.datadoghq.com/tracing/trace_collection/library_config/nodejs/?tab=containers#configuration) options can also be used.

## Collecting Git metadata{% #collecting-git-metadata %}

Datadog uses Git information for visualizing your test results and grouping them by repository, branch, and commit. Git metadata is automatically collected by the test instrumentation from CI provider environment variables and the local `.git` folder in the project path, if available.

If you are running tests in non-supported CI providers or with no `.git` folder, you can set the Git information manually using environment variables. These environment variables take precedence over any auto-detected information. Set the following environment variables to provide Git information:

{% dl %}

{% dt %}
`DD_GIT_REPOSITORY_URL`
{% /dt %}

{% dd %}
URL of the repository where the code is stored. Both HTTP and SSH URLs are supported.**Example**: `git@github.com:MyCompany/MyApp.git`, `https://github.com/MyCompany/MyApp.git`
{% /dd %}

{% dt %}
`DD_GIT_BRANCH`
{% /dt %}

{% dd %}
Git branch being tested. Leave empty if providing tag information instead.**Example**: `develop`
{% /dd %}

{% dt %}
`DD_GIT_TAG`
{% /dt %}

{% dd %}
Git tag being tested (if applicable). Leave empty if providing branch information instead.**Example**: `1.0.1`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_SHA`
{% /dt %}

{% dd %}
Full commit hash.**Example**: `a18ebf361cc831f5535e58ec4fae04ffd98d8152`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_MESSAGE`
{% /dt %}

{% dd %}
Commit message.**Example**: `Set release number`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_AUTHOR_NAME`
{% /dt %}

{% dd %}
Commit author name.**Example**: `John Smith`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_AUTHOR_EMAIL`
{% /dt %}

{% dd %}
Commit author email.**Example**: `john@example.com`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_AUTHOR_DATE`
{% /dt %}

{% dd %}
Commit author date in ISO 8601 format.**Example**: `2021-03-12T16:00:28Z`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_COMMITTER_NAME`
{% /dt %}

{% dd %}
Commit committer name.**Example**: `Jane Smith`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_COMMITTER_EMAIL`
{% /dt %}

{% dd %}
Commit committer email.**Example**: `jane@example.com`
{% /dd %}

{% dt %}
`DD_GIT_COMMIT_COMMITTER_DATE`
{% /dt %}

{% dd %}
Commit committer date in ISO 8601 format.**Example**: `2021-03-12T16:00:28Z`
{% /dd %}

{% /dl %}

## Manual testing API{% #manual-testing-api %}

{% alert level="danger" %}
**Note**: The manual testing API is available starting in `dd-trace` versions `5.23.0` and `4.47.0`.
{% /alert %}

If you use Jest, Mocha, Cypress, Playwright, Cucumber, or Vitest, **do not use the manual testing API**, as Test Optimization automatically instruments them and sends the test results to Datadog. The manual testing API is **incompatible** with already supported testing frameworks.

Use the manual testing API only if you use an unsupported testing framework or have a different testing mechanism.

The manual testing API leverages the `node:diagnostics_channel` module from Node.js and is based on channels you can publish to:

```javascript
const { channel } = require('node:diagnostics_channel')

const { describe, test, beforeEach, afterEach, assert } = require('my-custom-test-framework')

const testStartCh = channel('dd-trace:ci:manual:test:start')
const testFinishCh = channel('dd-trace:ci:manual:test:finish')
const testSuite = __filename

describe('can run tests', () => {
  beforeEach((testName) => {
    testStartCh.publish({ testName, testSuite })
  })
  afterEach((status, error) => {
    testFinishCh.publish({ status, error })
  })
  test('first test will pass', () => {
    assert.equal(1, 1)
  })
})
```

### Test start channel{% #test-start-channel %}

Grab this channel by its ID `dd-trace:ci:manual:test:start` to publish that a test is starting. A good place to do this is a `beforeEach` hook or similar.

```typescript
const { channel } = require('node:diagnostics_channel')
const testStartCh = channel('dd-trace:ci:manual:test:start')

// ... code for your testing framework goes here
  beforeEach(() => {
    const testDefinition = {
      testName: 'a-string-that-identifies-this-test',
      testSuite: 'what-suite-this-test-is-from.js'
    }
    testStartCh.publish(testDefinition)
  })
// code for your testing framework continues here ...
```

The payload to be published has attributes `testName` and `testSuite`, both strings, that identify the test that is about to start.

### Test finish channel{% #test-finish-channel %}

Grab this channel by its ID `dd-trace:ci:manual:test:finish` to publish that a test is ending. A good place to do this is an `afterEach` hook or similar.

```typescript
const { channel } = require('node:diagnostics_channel')
const testFinishCh = channel('dd-trace:ci:manual:test:finish')

// ... code for your testing framework goes here
  afterEach(() => {
    const testStatusPayload = {
      status: 'fail',
      error: new Error('assertion error')
    }
    testStartCh.publish(testStatusPayload)
  })
// code for your testing framework continues here ...
```

The payload to be published has attributes `status` and `error`:

- `status` is a string that takes one of three values:

  - `'pass'` when a test passes.
  - `'fail'` when a test fails.
  - `'skip'` when a test has been skipped.

- `error` is an `Error` object containing the reason why a test failed.

### Add tags channel{% #add-tags-channel %}

Grab this channel by its ID `dd-trace:ci:manual:test:addTags` to publish that a test needs custom tags. This can be done within the test function:

```typescript
const { channel } = require('node:diagnostics_channel')
const testAddTagsCh = channel('dd-trace:ci:manual:test:addTags')

// ... code for your testing framework goes here
  test('can sum', () => {
    testAddTagsCh.publish({ 'test.owner': 'my-team', 'number.assertions': 3 })
    const result = sum(2, 1)
    assert.equal(result, 3)
  })
// code for your testing framework continues here ...
```

The payload to be published is a dictionary `<string, string|number>` of tags or measures that are added to the test.

### Run the tests{% #run-the-tests %}

When the test start and end channels are in your code, run your testing framework like you normally do, including the following environment variables:

```shell
NODE_OPTIONS="-r dd-trace/ci/init" DD_TEST_SESSION_NAME=custom-tests yarn run-my-test-framework
```

## Known limitations{% #known-limitations %}

### Browser tests{% #browser-tests %}

Browser tests executed with `mocha`, `jest`, `cucumber`, `cypress`, `playwright`, and `vitest` are instrumented by `dd-trace-js`, but visibility into the browser session itself is not provided by default (for example, network calls, user actions, page loads, and more.).

If you want visibility into the browser process, consider using [RUM & Session Replay](https://docs.datadoghq.com/real_user_monitoring/application_monitoring/browser/). When using Cypress or Playwright, test results and their generated RUM browser sessions and session replays are automatically linked. For more information, see the [Instrumenting your browser tests with RUM guide](https://docs.datadoghq.com/continuous_integration/guides/rum_integration/).

### Cypress interactive mode{% #cypress-interactive-mode %}

Cypress interactive mode (which you can enter by running `cypress open`) is not supported by Test Optimization because some cypress events, such as [`before:run`](https://docs.cypress.io/api/plugins/before-run-api), are not fired. If you want to try it anyway, pass `experimentalInteractiveRunEvents: true` to the [cypress configuration file](https://docs.cypress.io/guides/references/configuration#Configuration-File).

### Jest's `--workerThreads`{% #jests---workerthreads %}

Jest's [workerThreads](https://jestjs.io/docs/configuration#workerthreads) option is not supported.

### Jest's `test.concurrent`{% #jests-testconcurrent %}

Jest's [test.concurrent](https://jestjs.io/docs/api#testconcurrentname-fn-timeout) is not supported.

### Jest's `--forceExit`{% #jests---forceexit %}

Jest's [–forceExit](https://jestjs.io/docs/cli#--forceexit) option may cause data loss. Datadog tries to send data immediately after your tests finish, but shutting down the process abruptly can cause some requests to fail. Use `--forceExit` with caution.

### Mocha's `--exit`{% #mochas---exit %}

Mocha's [–exit](https://mochajs.org/running/cli/#--exit) option may cause data loss. Datadog tries to send data immediately after your tests finish, but shutting down the process abruptly can cause some requests to fail. Use `--exit` with caution.

### Vitest's browser mode{% #vitests-browser-mode %}

Vitest's [browser mode](https://vitest.dev/guide/browser/) is not supported.

## Best practices{% #best-practices %}

Follow these practices to take full advantage of the testing framework and Test Optimization.

### Parameterized tests{% #parameterized-tests %}

Whenever possible, leverage the tools that testing frameworks provide for parameterized tests. For example, for `jest`:

Avoid this:

```javascript
[[1,2,3], [3,4,7]].forEach((a,b,expected) => {
  test('sums correctly', () => {
    expect(a+b).toEqual(expected)
  })
})
```



And use [`test.each`](https://jestjs.io/docs/api#testeachtablename-fn-timeout) instead:

```javascript
test.each([[1,2,3], [3,4,7]])('sums correctly %i and %i', (a,b,expected) => {
  expect(a+b).toEqual(expected)
})
```

For `mocha`, use [`mocha-each`](https://www.npmjs.com/package/mocha-each):

```javascript
const forEach = require('mocha-each');
forEach([
  [1,2,3],
  [3,4,7]
])
.it('adds %i and %i then returns %i', (a,b,expected) => {
  expect(a+b).to.equal(expected)
});
```

When you use this approach, both the testing framework and Test Optimization can tell your tests apart.

### Test session name `DD_TEST_SESSION_NAME`{% #test-session-name-dd_test_session_name %}

Use `DD_TEST_SESSION_NAME` to define the name of the test session and the related group of tests. Examples of values for this tag would be:

- `unit-tests`
- `integration-tests`
- `smoke-tests`
- `flaky-tests`
- `ui-tests`
- `backend-tests`

If `DD_TEST_SESSION_NAME` is not specified, the default value used is a combination of:

- CI job name
- Command used to run the tests (such as `yarn test`)

The test session name should be unique within a repository to help you distinguish different groups of tests.

#### When to use `DD_TEST_SESSION_NAME`{% #when-to-use-dd_test_session_name %}

There's a set of parameters that Datadog checks to establish correspondence between test sessions. The test command used to execute the tests is one of them. If the test command contains a string that changes for every execution, such as a temporary folder, Datadog considers the sessions to be unrelated to each other. For example:

- `yarn test --temp-dir=/var/folders/t1/rs2htfh55mz9px2j4prmpg_c0000gq/T`
- `pnpm vitest --temp-dir=/var/folders/t1/rs2htfh55mz9px2j4prmpg_c0000gq/T`

Datadog recommends using `DD_TEST_SESSION_NAME` if your test commands vary between executions.

## Further reading{% #further-reading %}

- [Forwarding Environment Variables for Tests in Containers](https://docs.datadoghq.com/continuous_integration/tests/containers/)
- [Explore Test Results and Performance](https://docs.datadoghq.com/continuous_integration/tests)
- [Speed up your test jobs with Test Impact Analysis](https://docs.datadoghq.com/tests/test_impact_analysis/javascript)
- [Troubleshooting Test Optimization](https://docs.datadoghq.com/tests/troubleshooting/)
