On this page
Use @testcollab/cli in GitLab CI to create a TestCollab test plan, run your automated
tests, and upload their JUnit XML results. GitLab can display the same JUnit file in its pipeline
Tests view while TestCollab keeps the results with your manual testing and release history.
The core workflow is createTestPlan → tests → report. A
TestCollab build record and quality gate are not prerequisites for reporting.
For CLI installation and alternative workflows, see TestCollab CLI: Install and First Run.
Prerequisites
- A TestCollab project containing the cases you want the pipeline to execute.
- A CI tag applied to those cases, plus the project ID, tag ID, and assignee user ID.
- A TestCollab API token belonging to the assignee. The user must have permission to create and assign test plans.
- A GitLab project with CI/CD enabled.
-
A test reporter that writes one JUnit XML file. The example below uses Jest and
jest-junit.
Install jest-junit if it is not already part of your project:
npm install --save-dev jest-junit
Add GitLab CI/CD variables
Open Settings > CI/CD > Variables in the GitLab project and add:
| Variable | Value | Protection |
|---|---|---|
TESTCOLLAB_TOKEN |
Your TestCollab API token | Masked and protected when appropriate |
TC_PROJECT_ID |
TestCollab project ID | Plain numeric value |
TC_CI_TAG_ID |
Tag ID selecting the CI cases | Plain numeric value |
TC_ASSIGNEE_ID |
User ID that owns the executions | Plain numeric value |
TC_API_URL |
https://api.testcollab.io |
Use the EU value described below when needed |
Create the token through
Getting an API Token generated. Never
commit the token to .gitlab-ci.yml.
Complete .gitlab-ci.yml
This example creates the plan before Jest runs. It captures the test exit code, uploads the result even after failed assertions, and then returns the original failure to GitLab. The job therefore records failed results without hiding a broken test run.
image: node:22-bookworm
stages:
- test
test-and-report:
stage: test
before_script:
- npm ci
script:
- |
set -e
npx @testcollab/cli createTestPlan \
--project "$TC_PROJECT_ID" \
--ci-tag-id "$TC_CI_TAG_ID" \
--assignee-id "$TC_ASSIGNEE_ID" \
--api-url "$TC_API_URL"
. tmp/tc_test_plan
mkdir -p test-results
set +e
JEST_JUNIT_OUTPUT_DIR=./test-results \
JEST_JUNIT_OUTPUT_NAME=results.xml \
npm test -- --ci --reporters=default --reporters=jest-junit
TEST_EXIT=$?
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 "$TC_API_URL"
REPORT_EXIT=$?
set -e
if [ "$REPORT_EXIT" -ne 0 ]; then
exit "$REPORT_EXIT"
fi
exit "$TEST_EXIT"
artifacts:
when: always
reports:
junit: test-results/results.xml
paths:
- test-results/results.xml
expire_in: 1 week
How the pipeline works
-
createTestPlancreates a plan from the cases carrying your CI tag and writesTESTCOLLAB_TEST_PLAN_IDtotmp/tc_test_plan. - The POSIX
.command loads that ID into the current shell. -
Jest writes
test-results/results.xml. Its exit status is saved instead of discarded. -
tc reportmaps each result to its TestCollab execution and uploads the status. - The script returns a reporting error first, otherwise it returns the Jest status. Failed tests still fail the GitLab job.
-
artifacts: when: alwayspreserves the XML for GitLab even when the job fails.
Map JUnit tests with [TC-42]
Put the TestCollab case ID in every result-producing test title. The CLI recognizes
[TC-42], TC-42, id-42, and testcase-42,
case-insensitively.
describe('Authentication', () => {
test('[TC-42] customer can sign in', async () => {
// Test steps and assertions
});
});
The ID must refer to a case in the plan created from the CI tag. Prefer the bracketed marker because it is visible and unambiguous in GitLab and JUnit output.
Use another JUnit-capable framework
Keep the TestCollab commands unchanged and replace only the Jest command and
--result-file path. For example:
| Framework | Generate JUnit XML | Result file |
|---|---|---|
| Playwright |
PLAYWRIGHT_JUNIT_OUTPUT_NAME=test-results/results.xml npx playwright test
--reporter=junit
|
test-results/results.xml |
| pytest | pytest --junitxml=test-results/results.xml |
test-results/results.xml |
| Maven Surefire | mvn test |
Pass one generated TEST-*.xml file to the CLI |
tc report accepts one result file per command. Merge multiple JUnit files first or
call the command once for the single combined report your runner produces.
Optional build traceability and quality gates
After result reporting works, you can optionally
record the deployed build and
link the plan to its version. You can separately add a
quality gate
after tc report. Neither extension is required, and each can be adopted
independently.
Use the EU region
Set TC_API_URL to the following value for an EU account. The workflow already passes
it to both TestCollab commands.
https://api-eu.testcollab.io
Troubleshooting
The JUnit artifact is missing
Confirm jest-junit is installed and the output directory and filename match
test-results/results.xml. For another runner, update both the GitLab artifact path
and --result-file.
TestCollab does not update a case
Inspect the JUnit <testcase name> value for [TC-42]. Confirm the
case carries the selected CI tag, appears in the created plan, and is assigned to the token owner.
Authentication works on main but not merge requests
A protected GitLab variable is exposed only to protected branches and tags. Review the variable scope before allowing untrusted merge-request pipelines to access a secret.
Failed tests do not fail the job
Do not append || true without restoring the saved exit code. Keep the
TEST_EXIT and final exit logic from the example.


