Publish JUnit test results from a Jenkins Pipeline to TestCollab with
@testcollab/cli. The pipeline creates a TestCollab plan, runs the automated tests,
reports their results, and then lets Jenkins retain the same JUnit XML.
This integration does not require a TestCollab Jenkins plugin. For CLI installation and workflow options, see TestCollab CLI: Install and First Run.
The core workflow is createTestPlan → tests → report. Build
traceability and quality gating are separate, optional extensions.
Prerequisites
- A Jenkins agent with Node.js 18 or newer and npm available.
- A repository whose
npm testcommand runs Jest. jest-junitinstalled as a development dependency.- A TestCollab project with a CI tag applied to the automated cases.
- The TestCollab project ID, tag ID, and assignee user ID.
- A TestCollab API token belonging to the assignee.
npm install --save-dev jest-junit
Store the API token in Jenkins
- Open Manage Jenkins > Credentials.
- Add the TestCollab API token as a Secret text credential.
-
Set its credential ID to
testcollab-token, or update the Jenkinsfile to match your chosen ID.
If you need a token, follow Getting an API Token generated. Do not place the token directly in the Jenkinsfile.
Complete declarative Jenkinsfile
This Jenkinsfile preserves the test exit status while still uploading failed results. It assumes the Jenkins agent already provides Node.js 18 or newer.
pipeline {
agent any
environment {
TESTCOLLAB_TOKEN = credentials('testcollab-token')
TC_PROJECT_ID = '123'
TC_CI_TAG_ID = '45'
TC_ASSIGNEE_ID = '67'
TC_API_URL = 'https://api.testcollab.io'
}
stages {
stage('Install dependencies') {
steps {
sh 'npm ci'
}
}
stage('Test and report') {
steps {
sh '''
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"
'''
}
}
}
post {
always {
junit allowEmptyResults: true,
testResults: 'test-results/results.xml'
archiveArtifacts allowEmptyArchive: true,
artifacts: 'test-results/results.xml'
}
}
}
The Jenkins JUnit step is only for Jenkins' own test view. TestCollab receives the result through
tc report, so both systems can use the same XML.
How the Jenkins pipeline works
-
The
credentialshelper exposes the Secret text value asTESTCOLLAB_TOKENduring the build. -
createTestPlancreates a plan from the CI-tagged cases and writes its ID totmp/tc_test_plan. - The shell loads the plan ID, runs Jest, and saves Jest's status.
tc reportuploads the JUnit results to the matching TestCollab executions.- The shell returns a reporting failure first, otherwise the original test status. Failed assertions therefore keep the Jenkins build failed.
-
The declarative
post { always { ... } }block publishes and archives the XML after passing or failing stages.
Use a Jenkins freestyle project
Set the five variables from the Jenkinsfile in the job environment, then add this as an Execute shell step after checkout:
set -e
npm ci
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"
Map Jenkins results with [TC-42]
Include the TestCollab case ID in each result-producing test title. Matching is case-insensitive
and supports [TC-42], TC-42, id-42, and
testcase-42.
test('[TC-42] customer can sign in', async () => {
// Test steps and assertions
});
The case must be part of the plan created from the CI tag and assigned to the API token owner.
Use another JUnit runner
Replace the Jest command with your framework's JUnit command, then keep one combined XML path
consistent in tc report, junit, and archiveArtifacts.
# Playwright
PLAYWRIGHT_JUNIT_OUTPUT_NAME=test-results/results.xml \
npx playwright test --reporter=junit
# pytest
pytest --junitxml=test-results/results.xml
tc report accepts one file per command. Merge a directory of Surefire or
parallel-runner XML files before uploading.
Optional build traceability and quality gates
Once reporting is working, you can optionally
record a deployed build and
link the plan to its version. You can separately run a
quality gate
after tc report. Neither one is required, and you do not need to adopt both.
Use the EU region
For an EU account, change TC_API_URL in the Jenkinsfile or freestyle environment to:
https://api-eu.testcollab.io
Troubleshooting
npx or Node.js is not found
Install Node.js 18 or newer on the Jenkins agent and make it available on the build user's
PATH. The TestCollab CLI does not require a Jenkins-specific plugin.
No API key provided
Confirm testcollab-token is a Secret text credential visible to the job. If you use a
different credential ID, update credentials('testcollab-token').
The JUnit publisher finds no files
Confirm the reporter creates test-results/results.xml. Use the same path in the test
command, tc report, and Jenkins junit step.
The TestCollab cases remain unexecuted
Inspect the JUnit <testcase name> values for [TC-42]. Confirm the
case is selected by the CI tag and assigned to the token owner.


