Skip to content

junit-upload should accept <testsuite> as root element #53

@AndrianBdn

Description

@AndrianBdn

Problem

junit-upload rejects JUnit XML files that have <testsuite> as the root element — it only accepts <testsuites> as root.

Many test runners produce per-class/per-suite files with <testsuite> as root (no <testsuites> wrapper). Users are forced to merge files with a tool like junit-merge before uploading.

Error

[
  {
    "code": "invalid_type",
    "expected": "object",
    "received": "undefined",
    "path": ["testsuites"],
    "message": "Required"
  }
]

Producers that output bare <testsuite> root

  • TestNG JUnitReportReporter — one file per class, each with <testsuite> root
  • Maven Surefire native reports — TEST-*.xml files with <testsuite> root
  • Many JUnit 4/5 runners — per-class XML files

Example file that fails

<?xml version="1.0" encoding="UTF-8"?>
<testsuite hostname="host" failures="0" tests="4" name="com.example.MathUtilsTest"
           time="0.001" errors="0" timestamp="2026-02-10T12:24:12 UTC" skipped="0">
  <testcase classname="com.example.MathUtilsTest" name="testAddition" time="0.001"/>
  <testcase classname="com.example.MathUtilsTest" name="testDivisionByZero" time="0.000"/>
</testsuite>

Expected behavior

When the root element is <testsuite>, treat it as if it were wrapped in <testsuites> — i.e. a single-suite file.

Suggested fix

In junitXmlParser.ts, after xml2js parsing, normalize the structure:

const xmlData = await xml.parseStringPromise(xmlString, { ... })

// Accept bare <testsuite> as root by wrapping it
if (xmlData.testsuite && !xmlData.testsuites) {
    xmlData.testsuites = { testsuite: [xmlData.testsuite] }
    delete xmlData.testsuite
}

This would eliminate the need for junit-merge when uploading multiple per-class files:

# Currently requires merge step:
npx junit-merge -o merged.xml -d target/surefire-reports/junitreports
qasphere junit-upload merged.xml

# With this fix, just pass all files directly:
qasphere junit-upload target/surefire-reports/junitreports/*.xml

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions