Your runner already writes JUnit XML. One curl line puts those results into a Jira
test cycle — pass, fail, duration and the failure message — with no plugin inside your pipeline.
JUnit XML is the one format nearly every runner can emit. CaseRun gives your Jira project an ingest URL; your pipeline posts the XML file to it after the tests run. Results appear in a test cycle, and tests that don't exist yet are created from the XML, so you don't have to pre-register anything.
curl -X POST "$CASERUN_INGEST_URL&cycle=Nightly&env=staging&version=$BUILD_NUMBER" \
-H "Content-Type: application/xml" \
--data-binary @results.xml
| Parameter | What it does |
|---|---|
cycle (required) | Name of the test cycle. If it doesn't exist, it's created. |
env | Free text — staging, prod, chrome. Shown in the ingest log. |
version | Build or release identifier. |
The URL itself (including the project and a secret token) is shown on the CI tab inside the app. Keep it in your CI secret store; you can rotate it from that same tab.
Add the JUnit reporter alongside your usual one:
// playwright.config.ts
export default defineConfig({
reporter: [['list'], ['junit', { outputFile: 'results.xml' }]],
});
Or without touching the config: npx playwright test --reporter=junit (writes to stdout — redirect it
with PLAYWRIGHT_JUNIT_OUTPUT_NAME=results.xml).
npm i -D mocha-junit-reporter
// cypress.config.js
module.exports = defineConfig({
reporter: 'mocha-junit-reporter',
reporterOptions: { mochaFile: 'results/[hash].xml', toConsole: true },
});
Cypress writes one file per spec. Post them in a loop, or merge them first — CaseRun accepts either, and
posting several files into the same cycle just adds to it.
pytest --junitxml=results.xml
Class names come through as the test's grouping, so tests/test_login.py::test_valid stays readable
in the cycle.
Maven Surefire already writes JUnit XML — no configuration needed:
mvn test
# XML lands in target/surefire-reports/*.xml
curl -X POST "$CASERUN_INGEST_URL&cycle=CI" -H "Content-Type: application/xml" \
--data-binary @target/surefire-reports/TEST-*.xml
Gradle: build/test-results/test/*.xml. TestNG emits its own format as well, but the
junitreports folder holds the JUnit-shaped files — use those.
npm i -D jest-junit
npx jest --reporters=default --reporters=jest-junit # writes junit.xml
npx vitest run --reporter=junit --outputFile=results.xml
robot --xunit results.xml tests/
newman run collection.json -r junit --reporter-junit-export results.xml
- name: Run tests
run: npx playwright test
continue-on-error: true # still report failures
- name: Send results to Jira
if: always()
run: |
curl -X POST "$CASERUN_INGEST_URL&cycle=main&env=ci&version=${{ github.run_number }}" \
-H "Content-Type: application/xml" --data-binary @results.xml
env:
CASERUN_INGEST_URL: ${{ secrets.CASERUN_INGEST_URL }}
if: always() matters — otherwise a failing suite skips the very step that reports the failures.
test:
script:
- pytest --junitxml=results.xml || true
- curl -X POST "$CASERUN_INGEST_URL&cycle=$CI_COMMIT_REF_NAME&env=ci&version=$CI_PIPELINE_IID"
-H "Content-Type: application/xml" --data-binary @results.xml
artifacts:
reports: { junit: results.xml }
post {
always {
sh '''curl -X POST "$CASERUN_INGEST_URL&cycle=nightly&env=ci&version=$BUILD_NUMBER" \
-H "Content-Type: application/xml" --data-binary @results.xml'''
}
}
- step:
script:
- pytest --junitxml=results.xml || true
- curl -X POST "$CASERUN_INGEST_URL&cycle=main&env=ci&version=$BITBUCKET_BUILD_NUMBER"
-H "Content-Type: application/xml" --data-binary @results.xml
|| true, continue-on-error or
post { always { … } }, otherwise the runs you most want to see never arrive.<testcase … /> tags are real. Passing tests are usually written that way;
a parser that only handles the open/close form silently drops them. Ours reads both — we found that bug
in our own parser by feeding it a real Playwright file.Failed tests carry the failure message from the XML, so the report can answer "what actually broke" without opening the CI logs. The tests that fail most often are ranked on the Reports tab with their last failure message.
Runner not listed here? If it can write JUnit XML, it works. Send the file to support@caserun.dev and we'll tell you what it will produce — or fix the parser if it trips on something.