Documentation

TestNod documentation

Learn how to set up TestNod and configure it to help you spot flaky tests, catch regressions, and see how performance changes over time.

Run metadata: branch, commit, build ID, and tags

Every upload is a JUnit XML file plus a few metadata fields. Only build_id is required, and everything else (branch, commit SHA, run URL, tags) is optional. Set as much as you can on day one, because the fields are cheap to populate from CI environment variables and missing values are hard to fill in retroactively.

Build ID (required)

test_run[metadata][build_id]

The build identifier from your CI provider. This is the only metadata field the upload endpoint requires, and it does two things:

  1. Groups multi-file uploads into one run. Every upload that shares a (project, build_id) attaches to the same pending run, so a parallel matrix that produces ten JUnit files becomes one run with ten attached uploads.
  2. Keys the /finalize call. Once your build is done uploading, the finalize call passes build_id to tell TestNod the run is complete.

Use whatever identifier uniquely names a build inside your CI: the GitHub Actions run_id, CircleCI CIRCLE_WORKFLOW_ID, GitLab CI_PIPELINE_ID, Jenkins BUILD_NUMBER, Buildkite BUILDKITE_BUILD_ID. Pick once and stay consistent so the same build always lands on the same build_id.

While a run is still pending, any upload that carries its build_id attaches to it, so reusing a build_id across two separate builds can fold the second build's uploads into the first run instead of starting a fresh one. Use IDs that are unique per build, not per branch or per day.

Branch

test_run[metadata][branch]

The branch the build ran on. When TestNod computes a run diff, the baseline finder prefers a prior run from the same branch, so without this field a run falls back to comparing against the most recent prior run regardless of which branch produced it. Branch is also a filter on the run history page.

Commit SHA

test_run[metadata][commit_sha]

The full Git commit SHA. Shown on the run page header so reviewers can see which commit produced a run, and used as a hook for future VCS integrations. Use the full 40-character SHA, not the abbreviated form.

Run URL

test_run[metadata][run_url]

URL of the CI build that produced this report. The run page links to it, so you can jump from a TestNod run straight to the original CI logs without hunting. Some CI providers expose this as a built-in environment variable, such as CircleCI's CIRCLE_BUILD_URL or GitLab's CI_JOB_URL. Others, including GitHub Actions, do not, so you build the URL yourself from the parts the CI does expose.

Tags

tags[][value] (repeated)

Tags are how you slice runs across dimensions other than branch. Common patterns:

  • One tag per test suite type: smoke, unit, integration, e2e.
  • One tag for environment: staging, production.
  • One tag for matrix axis: ruby-3.3, node-20, os-ubuntu.

Tags travel with the run and feed the dashboard, the alert tag-matching logic, and the weekly project summary email. If you do not provide any tags, TestNod adds a single Default tag so reports without explicit tagging still cluster together.

A few rules worth knowing:

  • Tags are unordered. The set {smoke, ruby-3.3} and {ruby-3.3, smoke} are equivalent.
  • Tag matching for baselines and alerts is exact: a run tagged smoke does not match a run tagged smoke,fast.
  • There is no separate tag namespace per project. Use names that make sense for your team.

Putting it together

A typical upload from CI sets all five fields, derived from the provider's environment variables:

curl -sS -X POST https://app.testnod.com/integrations/test_runs/upload \
  -H "Project-Token: $TESTNOD_PROJECT_TOKEN" \
  -F "test_run[metadata][branch]=$CI_BRANCH" \
  -F "test_run[metadata][commit_sha]=$CI_COMMIT_SHA" \
  -F "test_run[metadata][run_url]=$CI_RUN_URL" \
  -F "test_run[metadata][build_id]=$CI_BUILD_ID" \
  -F "tags[][value]=$CI_JOB_NAME"

This call carries the metadata, not the JUnit file itself: it registers the upload and returns a presigned URL that you then send the file to. The full upload-then-finalize flow is in Generic CI / curl and the Submission API.

Be first to try TestNod

We're opening early access soon. Drop your email and we'll get you in, and we're happy to help you set up too.

No spam. We'll only email you about TestNod.