Help Center/Automation & CI/CD/Your CI provider

CircleCI Integration with TestCollab: Upload Test Results

Connect CircleCI to TestCollab, create a test plan, upload JUnit test results with the CLI, and preserve useful CI run context.

On this page

Connect CircleCI to TestCollab with @testcollab/cli to create a test plan before a job runs and upload its JUnit results afterward. CircleCI can still display the same XML in its Tests tab, while TestCollab keeps the automated results with your manual testing, builds, and releases.

The core workflow is createTestPlan → tests → report. It needs neither a build record nor a quality gate. For the zero-setup option and all CLI commands, start with TestCollab CLI: Install and First Run.

Prerequisites

  • A TestCollab project with the automated test cases you want to run.
  • A CI tag applied to those cases. Note the project ID and tag ID from TestCollab.
  • The user ID of the person or service account that will own the executions.
  • A TestCollab API token for that same user. The user must have access to the project and permission to create and assign test plans.
  • A test reporter that writes JUnit XML. The complete example below uses Jest with jest-junit.

Name each automated test with its TestCollab case ID, such as [TC-42] customer can sign in. The ID lets the CLI update the right execution in the new test plan.

Add environment variables in CircleCI

Open your CircleCI project, go to Project Settings > Environment Variables, and add these values:

Variable Value Secret?
TESTCOLLAB_TOKEN Your TestCollab API token Yes
TC_PROJECT_ID Your TestCollab project ID No
TC_CI_TAG_ID The tag ID used for CI cases No
TC_ASSIGNEE_ID The execution owner in TestCollab No

Do not place TESTCOLLAB_TOKEN directly in .circleci/config.yml. If you still need a token, follow Getting an API Token generated.

Complete .circleci/config.yml

This job creates a TestCollab test plan, runs Jest, stores the JUnit report in CircleCI, and uploads the same report to TestCollab. Add jest-junit to your development dependencies before using it.

npm install --save-dev jest-junit
version: 2.1

jobs:
  test:
    docker:
      - image: cimg/node:22.16
    steps:
      - checkout

      - restore_cache:
          keys:
            - npm-v1-{{ checksum "package-lock.json" }}

      - run:
          name: Install dependencies
          command: npm ci

      - save_cache:
          key: npm-v1-{{ checksum "package-lock.json" }}
          paths:
            - ~/.npm

      - run:
          name: Create TestCollab test plan
          command: |
            npx @testcollab/cli createTestPlan \
              --project "$TC_PROJECT_ID" \
              --ci-tag-id "$TC_CI_TAG_ID" \
              --assignee-id "$TC_ASSIGNEE_ID"

      - run:
          name: Run Jest and generate JUnit XML
          command: |
            mkdir -p test-results
            JEST_JUNIT_OUTPUT_DIR=./test-results \
            JEST_JUNIT_OUTPUT_NAME=results.xml \
            npm test -- --ci --reporters=default --reporters=jest-junit

      - store_test_results:
          path: test-results

      - run:
          name: Upload results to TestCollab
          when: always
          command: |
            source tmp/tc_test_plan
            npx @testcollab/cli report \
              --project "$TC_PROJECT_ID" \
              --test-plan-id "$TESTCOLLAB_TEST_PLAN_ID" \
              --format junit \
              --result-file ./test-results/results.xml

workflows:
  test-and-report:
    jobs:
      - test

The upload step uses when: always, so it runs after passing and failing test commands. A failed test job still stays failed; the upload only records its result in TestCollab.

How the workflow works

  1. createTestPlan creates a plan from the cases carrying your CI tag and writes its ID to tmp/tc_test_plan.
  2. Jest runs and writes test-results/results.xml.
  3. store_test_results lets CircleCI read that XML for its Tests tab and timing data.
  4. The final step sources tmp/tc_test_plan and sends the same results to the matching executions in TestCollab.

Keep both store_test_results and tc report. CircleCI gives developers feedback inside the pipeline run. TestCollab provides the shared test-management record, including manual and automated cases in the same plan.

Map CircleCI tests to TestCollab cases

Put an explicit marker in each test title. Matching is case-insensitive, and the CLI recognizes [TC-42], TC-42, id-42, and testcase-42.

describe('Authentication', () => {
  test('[TC-42] customer can sign in', async () => {
    // Test steps and assertions
  });
});

The number is the TestCollab test case ID, not the test plan ID. The case must be included in the plan created from your CI tag.

Optional build traceability and quality gates

tc createBuild recognizes CircleCI automatically. It reads the build number, commit SHA, and CircleCI build URL from CIRCLE_BUILD_NUM, CIRCLE_SHA1, and CIRCLE_BUILD_URL.

CircleCI exposes CIRCLE_REPOSITORY_URL as a Git remote, which may be SSH rather than a browser URL. The CLI deliberately does not turn it into a repository or commit link. Pass verified web URLs explicitly when you want those links on the TestCollab build:

npx @testcollab/cli createBuild \
  --project "$TC_PROJECT_ID" \
  --repo-url "$TC_REPOSITORY_WEB_URL" \
  --commit-url "$TC_COMMIT_WEB_URL"

Add TC_REPOSITORY_WEB_URL and TC_COMMIT_WEB_URL as project environment variables or construct them from a known GitHub, GitLab, or Bitbucket web URL. See Creating Builds from Your CI/CD Pipeline before linking the test plan to that build.

Independently, you can add a quality gate after tc report when a later deployment must meet defined result criteria. Neither option is required for the copyable workflow above, and you can add either one without the other.

Use the EU region

EU accounts must add this option to every TestCollab CLI command in the workflow:

--api-url https://api-eu.testcollab.io

For example, the upload command ends with:

npx @testcollab/cli report \
  --project "$TC_PROJECT_ID" \
  --test-plan-id "$TESTCOLLAB_TEST_PLAN_ID" \
  --format junit \
  --result-file ./test-results/results.xml \
  --api-url https://api-eu.testcollab.io

Troubleshooting

No API key provided

Confirm the variable is named TESTCOLLAB_TOKEN and is available to this job. Environment variables from restricted contexts may not be exposed to untrusted forked builds.

The result file does not exist

Check that jest-junit is installed and that the test command writes to ./test-results/results.xml. The upload path is relative to the job's working directory.

Tests run, but cases are not updated

Inspect the generated XML and confirm each <testcase name="..."> contains the intended [TC-42] marker. Also confirm the CI tag selected that case when the plan was created and the token belongs to the assigned execution owner.

The upload step did not run after a failure

when: always belongs on the CircleCI run step, at the same indentation level as name and command. Keep test execution and result upload in separate steps.

Last updated 2026-08-26.