Karate test reporting
Karate writes a readable HTML report per run and then your CI job ends and takes it with it.
Qualflare turns those runs into
hosted, historical reporting: every scenario as its own
case, every Examples row tracked separately, tags
preserved, and AI clustering of failures by root cause.
Send Karate results to Qualflare
There is no flag to add: Karate already writes a JSON report per feature as part of a normal run.
# Karate writes a JSON report per feature into target/karate-reports/
mvn test
# Or via the standalone JAR
java -jar karate.jar src/test/features/ Point the CLI at the directory and it reads every feature report in it, merging them into one launch:
# Point at the directory — one launch, however many features ran
qf my-project collect target/karate-reports/ --format karate In CI that's one added step. Authenticate the CLI once with your Qualflare access token, stored as a CI secret — see the CLI docs.
# .github/workflows/api-tests.yml
- name: Run Karate suite
run: mvn -B test
- name: Upload results to Qualflare
if: always() # upload even when scenarios fail — that's the point
run: qf my-project collect target/karate-reports/ --format karate
The if: always() line is the one people leave out.
Maven exits non-zero when scenarios fail, so without it the upload runs only on green builds and your
failure history — the entire point — stays empty.
Features, scenarios, and what counts as a test
Karate is Gherkin pointed at APIs rather than browsers — the Given/When/Then shape, with HTTP and JSON assertions as first-class syntax instead of step definitions you have to write:
Feature: Checkout API
Background:
* url baseUrl
* header Authorization = 'Bearer ' + token
@smoke @payments
Scenario: rejects an expired card
Given path 'checkout'
And request { card: '4000000000000069' }
When method post
Then status 402
And match response.code == 'card_expired' The scenario is the test. Each one becomes a case, with its steps carried as detail underneath. That is not an arbitrary choice: a Karate scenario halts at its first failing step, so promoting steps to tests would report the cascade of skipped steps after a failure as if each were an independent failure, inflating every red number in the report. One scenario, one verdict, with the failing step named.
Scenario Outline is where the counting gets
interesting. Each Examples row runs independently and
arrives as its own case, carrying its example index:
Scenario Outline: rejects <label>
Given path 'checkout'
And request { card: '<card>' }
When method post
Then status 402
Examples:
| label | card |
| expired card | 4000000000000069 | # exampleIndex 0
| declined | 4000000000000002 | # exampleIndex 1
| no funds | 4000000000009995 | # exampleIndex 2
Three rows, three cases, three histories. If only the no funds
row is intermittent, per-row history points at that specific input — whereas collapsing the outline into
one case tells you only that “rejects <label> is a bit flaky”, which is not something you can act on.
The same principle applies to Cucumber
and to data providers in TestNG.
Tags are preserved — the feature's and the scenario's own, combined onto the case — so you can filter a
report by @smoke or
@payments the same way you filter a run. Worth naming
because it bit us once: merging those two tag lists naively lets one scenario's tags leak onto its
siblings. Tags on a case are its own plus its feature's, and nothing borrowed.
What you get on top of the HTML report
- History across runs. Karate's report describes one execution and is overwritten by the next; “has this scenario been getting flakier?” needs many.
- Examples rows as first-class cases. Flakiness attributed to the data row that causes it.
- AI failure clustering. When an expired token or a downed dependency takes out 30 scenarios, they group into one root cause rather than 30 separate failures.
- Flaky scoring from history. Karate has no scenario-level rerun, so there is no in-run attempt data — history is the only available method, and the more accurate one.
- Tags carried through. Filter and segment the report the way you segment the run.
- One launch across every suite. API scenarios next to UI and unit results instead of three disconnected pass rates.
Karate's report vs Qualflare
| karate-reports/ | Qualflare | |
|---|---|---|
| History across CI runs | — | Yes |
| Flaky scoring over time | — | Yes |
| AI failure clustering (root cause) | — | Yes |
| API results beside UI & unit suites | — | Yes |
| Full request/response log for one run | Yes | Partly |
| Local, zero-setup, offline | Yes | — |
Complementary, and the “Partly” is honest: Karate's own HTML report is excellent for reading one run's request and response bodies in detail. Keep it for that, and add Qualflare for what one run cannot show.
Get AI analysis on your Karate runs
Start free — point qf collect at karate-reports/ and get your first AI analysis in minutes.
Qualflare works the same with Newman, k6, CucumberJS, JUnit, TestNG and 20+ more frameworks. Prefer reading first? See Cucumber & BDD test reporting. Weighing tools? See how it compares to other test management platforms, or browse all framework reporting guides. Every reporter is open source.
Frequently asked questions
How do I send Karate results to Qualflare?
Karate already writes a JSON report per feature into target/karate-reports/ as part of a normal run, so there is no extra flag to add. Point the CLI at the directory — qf my-project collect target/karate-reports/ --format karate — and it reads every feature file in it and merges them into one launch.
Is a Karate scenario a test, or is a step a test?
The scenario is the test. Each scenario becomes one case, and its steps are carried as detail beneath it rather than as separate cases. That matches how Karate actually fails: a scenario stops at the first failing step, so counting steps as tests would report a cascade of skipped steps as if they were independent failures and inflate every red number.
How are Scenario Outline examples reported?
Each Examples row is its own case, carrying its example index. This matters for flaky detection: if only one data row is intermittent, per-row history points straight at that input, whereas folding the rows into their outline averages the signal away and tells you only that "the outline is a bit flaky".
Are Karate tags preserved?
Yes — both the feature-level tags and the scenario’s own, combined onto the case. That lets you filter a report by @smoke or @payments the same way you filter a run with Karate’s tag selectors. Worth knowing: combining the two lists naively is an easy source of cross-contamination between scenarios, and was a real bug here once, so tags you see on a case are its own plus its feature’s and nothing borrowed from a sibling.
Does Karate have a retry mechanism that hides flakiness?
Karate has a retry until construct for polling an endpoint that is expected to become ready, which is a legitimate wait rather than a test rerun. There is no built-in re-run-the-whole-scenario retry, so there is no in-run attempt data that could mask a flaky scenario — flakiness has to come from history across runs, which is the more accurate method anyway.
Can I report Karate alongside my UI and unit tests?
Yes, and that is usually the point. API scenarios, UI runs and unit suites normally live in three separate reports with three separate pass rates and no combined view. Uploading them all to the same project puts them in one launch, so release risk is assessed across everything that ran rather than per tool.
Setup reflects the Qualflare CLI (docs.qualflare.com) as of September 2026. Syntax and the report location follow Karate's own documentation; the scenario-as-case model, Examples-row handling and tag combination are taken from the CLI's Karate parser. Written by İbrahim Süren, Qualflare.