# Harness

This guide explains how to run Playwright tests on [Harness Continuous Integration](https://developer.harness.io/docs/category/set-up-cicd-pipelines) and report results to [Currents](https://currents.dev). It follows Harness NextGen pipeline patterns ([Run steps](https://developer.harness.io/docs/continuous-integration/use-ci/run-step-settings), [stage parallelism](https://developer.harness.io/docs/continuous-integration/use-ci/run-tests/speed-up-ci-test-pipelines-using-parallelism), [secrets](https://developer.harness.io/docs/platform/secrets/add-use-text-secrets)).

{% hint style="warning" %}
**`CURRENTS_CI_BUILD_ID` is mandatory** for Harness. Harness is **not** in Currents’ [auto-detected CI providers](https://docs.currents.dev/guides/parallelization-guide/ci-build-id#build-id-for-popular-ci-providers). If you omit it, Currents may generate a **different** build ID per job or shard: parallel Playwright shards **will not merge into one run**, reporting and orchestration **break**, and **retries** can collide with or duplicate prior runs. Always set `CURRENTS_CI_BUILD_ID` in every Run step (see below).
{% endhint %}

## Prerequisites

**Currents**

* Organization and project at <https://app.currents.dev>
* **Project ID** and **Record Key** — see [record-key](https://docs.currents.dev/guides/record-key "mention")
* **`CURRENTS_CI_BUILD_ID`** set in CI for every Playwright step (mandatory on Harness — see [CI Build ID](#ci-build-id-mandatory-on-harness))
* `@currents/playwright` installed and configured — see [currents-playwright](https://docs.currents.dev/resources/reporters/currents-playwright "mention")

**Harness**

* A **CI pipeline** with a **Build** (`CI`) stage
* A [Docker registry connector](https://developer.harness.io/docs/platform/connectors/cloud-providers/ref-cloud-providers/docker-registry-connector-settings-reference/) that can pull your Playwright image (for example `mcr.microsoft.com/playwright`). Replace `YOUR_DOCKER_CONNECTOR` in the examples with your connector reference (for example `account.harnessImageRegistry` or your org’s Docker Hub connector).

## Store the Record Key as a Harness secret

1. In Harness, create an **encrypted text** secret at the appropriate [scope](https://developer.harness.io/docs/platform/role-based-access-control/rbac-in-harness/#permissions-hierarchy-scopes) (project, org, or account).
2. Use a stable **identifier** (Harness derives it from the name). Example identifier: `currents_record_key`.
3. Reference it only by **identifier** in expressions, not the display name. See [Add and reference text secrets](https://developer.harness.io/docs/platform/secrets/add-use-text-secrets).

{% hint style="warning" %}
Avoid `$` in secret values when possible; the shell may expand it. If unavoidable, follow Harness guidance (for example quoting or base64 encoding) in the [text secrets](https://developer.harness.io/docs/platform/secrets/add-use-text-secrets) documentation.
{% endhint %}

## Application configuration

Use the same Playwright + Currents setup as other CI providers.

**`playwright.config.ts`** (reporter):

{% code title="playwright.config.ts" overflow="wrap" %}

```typescript
import { currentsReporter } from "@currents/playwright";
import { defineConfig } from "@playwright/test";

export default defineConfig({
  reporter: [currentsReporter()],
  use: {
    trace: "on",
    video: "on",
    screenshot: "on",
  },
  // ...projects, testDir, etc.
});
```

{% endcode %}

**`currents.config.ts`**:

{% code title="currents.config.ts" %}

```typescript
import { CurrentsConfig } from "@currents/playwright";

const config: CurrentsConfig = {
  projectId: process.env.CURRENTS_PROJECT_ID ?? "",
  recordKey: process.env.CURRENTS_RECORD_KEY ?? "",
};

export default config;
```

{% endcode %}

## CI Build ID (mandatory on Harness)

**You must provide `CURRENTS_CI_BUILD_ID`** (environment variable or reporter config). It is a **required** input for correct Currents behavior on Harness — not optional.

Without a stable, explicit value:

* Each parallel shard may get its own ID → **multiple runs** instead of one combined run
* Reruns may reuse or collide with IDs → **stale or rejected** uploads — see the [CI Build ID FAQ](https://docs.currents.dev/guides/parallelization-guide/ci-build-id#faq-retrying-builds-and-ci-build-id)

The value must be:

* **Unique per pipeline execution** (each execution gets its own Currents run)
* **Identical across all parallel Playwright shards** in the same execution (shards merge into one run)
* **Different when you retry the same logical build**, when you need a fresh run — see [ci-build-id](https://docs.currents.dev/guides/parallelization-guide/ci-build-id "mention")

Harness resolves expressions before the step runs. Common choices:

| Approach             | Expression (example)                                                                         | Notes                                                                                                                                                             |
| -------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Execution only       | `<+pipeline.executionId>`                                                                    | Unique per execution; confirm behavior for **re-runs** in your Harness edition                                                                                    |
| Execution + sequence | Concatenate `<+pipeline.executionId>` with `<+pipeline.sequenceId>` using `+` or `.concat()` | See [Harness variables](https://developer.harness.io/docs/platform/variables-and-expressions/harness-variables); helps separate retries when `sequenceId` changes |

Compose multi-part IDs with the concatenation patterns documented under **Harness variables** (for example combining `<+pipeline.identifier>`, `<+pipeline.executionId>`, and `<+pipeline.sequenceId>`).

## Option A — Single Run step (no parallelism)

Add a **Run** step in your **CI** stage. Set **Container Registry** to your Docker connector and **Image** to a [Playwright image](https://playwright.dev/docs/docker) tag that matches your `@playwright/test` version.

{% code overflow="wrap" %}

```yaml
execution:
  steps:
    - step:
        type: Run
        name: playwright_currents
        identifier: playwright_currents
        spec:
          connectorRef: YOUR_DOCKER_CONNECTOR
          image: mcr.microsoft.com/playwright:v1.49.0-jammy
          shell: Bash
          command: |-
            npm ci
            npx playwright install chrome
            npx playwright test
          envVariables:
            CI: "true"
            CURRENTS_PROJECT_ID: YOUR_CURRENTS_PROJECT_ID
            CURRENTS_RECORD_KEY: <+secrets.getValue("currents_record_key")>
            CURRENTS_CI_BUILD_ID: <+pipeline.executionId>
```

{% endcode %}

* Replace `YOUR_CURRENTS_PROJECT_ID` with your project ID, or use a [pipeline variable](https://developer.harness.io/docs/platform/variables-and-expressions/harness-variables) (for example `<+pipeline.variables.currents_project_id>`).
* Replace `currents_record_key` with your secret’s **identifier**.

## Option B — Parallel Playwright sharding (recommended)

Use **stage-level** [parallelism](https://developer.harness.io/docs/continuous-integration/use-ci/run-tests/speed-up-ci-test-pipelines-using-parallelism) so Harness runs multiple copies of the stage. Playwright’s [`--shard`](https://playwright.dev/docs/test-sharding) is **1-based**; Harness parallel indices are **0-based**, so use `HARNESS_NODE_INDEX + 1` for the shard index.

Do **not** rely on Harness `split_tests` for Playwright unless you intentionally drive a custom split; native sharding matches the rest of Currents’ CI docs and keeps setup simple.

{% code overflow="wrap" %}

```yaml
- stage:
    name: playwright_tests
    identifier: playwright_tests
    type: CI
    strategy:
      parallelism: 3
      maxConcurrency: 3
    spec:
      cloneCodebase: true
      platform:
        os: Linux
        arch: Amd64
      runtime:
        type: Cloud
        spec: {}
      execution:
        steps:
          - step:
              type: Run
              name: playwright_currents_shard
              identifier: playwright_currents_shard
              spec:
                connectorRef: YOUR_DOCKER_CONNECTOR
                image: mcr.microsoft.com/playwright:v1.49.0-jammy
                shell: Bash
                command: |-
                  npm ci
                  npx playwright install chrome
                  SHARD_INDEX=$((HARNESS_NODE_INDEX + 1))
                  npx playwright test --shard=${SHARD_INDEX}/${HARNESS_NODE_TOTAL}
                envVariables:
                  CI: "true"
                  HARNESS_NODE_INDEX: <+strategy.iteration>
                  HARNESS_NODE_TOTAL: <+strategy.iterations>
                  CURRENTS_PROJECT_ID: YOUR_CURRENTS_PROJECT_ID
                  CURRENTS_RECORD_KEY: <+secrets.getValue("currents_record_key")>
                  CURRENTS_CI_BUILD_ID: <+pipeline.executionId>
```

{% endcode %}

* Tune `parallelism` and `maxConcurrency` per [best practices for looping strategies](https://developer.harness.io/docs/platform/pipelines/looping-strategies/best-practices-for-looping-strategies).
* **`CURRENTS_CI_BUILD_ID` is mandatory** — the **same** value must reach every shard (the `<+pipeline.executionId>` expression above resolves identically for all parallel instances of the same execution).

## Environment variables reference

| Variable               | Required            | Description                                                                                                                                                                                                      |
| ---------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CURRENTS_PROJECT_ID`  | Yes                 | Currents project ID from the dashboard                                                                                                                                                                           |
| `CURRENTS_RECORD_KEY`  | Yes                 | Record key; inject via `<+secrets.getValue("SECRET_IDENTIFIER")>` (or org/account-scoped variant)                                                                                                                |
| `CURRENTS_CI_BUILD_ID` | **Yes (mandatory)** | **Required on Harness.** Stable ID shared by all shards in one execution; must change appropriately on retries — see [ci-build-id](https://docs.currents.dev/guides/parallelization-guide/ci-build-id "mention") |
| `CI`                   | Optional            | Set to `true` so tools behave as in CI                                                                                                                                                                           |
| `HARNESS_NODE_INDEX`   | Parallel only       | `<+strategy.iteration>` — 0-based shard index                                                                                                                                                                    |
| `HARNESS_NODE_TOTAL`   | Parallel only       | `<+strategy.iterations>` — must match `parallelism`                                                                                                                                                              |

## Optional — Pipeline or stage variables

You can define **pipeline** or **stage** variables for non-secret settings (for example project ID) and reference them with expressions such as `<+pipeline.variables.currents_project_id>`. Precedence for environment variables in Harness is **step > stage > pipeline**. See [Variables](https://developer.harness.io/docs/open-source/pipelines/variables) (open-source YAML) and [Harness variables](https://developer.harness.io/docs/platform/variables-and-expressions/harness-variables) (expressions).

## Harness Open Source / GitOps pipeline YAML

If you use the **open-source pipeline** schema (`kind: pipeline`), environment variables are often declared under `spec.options.envs` (pipeline-wide) or `spec.envs` on a `ci` stage, and Run steps use `spec.container` and `spec.script`. The **Currents** requirements are the same: include **`CURRENTS_CI_BUILD_ID` (mandatory)**, other `CURRENTS_*` variables, and `npx playwright test` with optional `--shard`. Map them to your schema per [CI stage reference](https://developer.harness.io/docs/open-source/reference/pipelines/yaml/stage.type.ci).

## Further reading

* [Harness CI Run step settings](https://developer.harness.io/docs/continuous-integration/use-ci/run-step-settings)
* [Speed up CI with parallelism](https://developer.harness.io/docs/continuous-integration/use-ci/run-tests/speed-up-ci-test-pipelines-using-parallelism)
* Currents: [ci-optimization](https://docs.currents.dev/guides/ci-optimization "mention"), [playwright-orchestration](https://docs.currents.dev/guides/ci-optimization/playwright-orchestration "mention")

{% hint style="info" %}
Got stuck configuring CI? Reach out to [support](https://docs.currents.dev/resources/support "mention").
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.currents.dev/getting-started/ci-setup/playwright-harness.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
