Skip to content

fix(reporters): junit to strip ANSI sequences from all XML attributes - #11407

Merged
hi-ogawa merged 1 commit into
vitest-dev:mainfrom
meganemura:fix/junit-strip-ansi-in-attributes
Oct 2, 2026
Merged

hi-ogawa merged 1 commit into
vitest-dev:mainfrom
meganemura:fix/junit-strip-ansi-in-attributes

Conversation

@meganemura

Copy link
Copy Markdown
Contributor

Description

The JUnit reporter strips ANSI sequences from the <failure> body, but not from attribute values. escapeXML removes the ESC byte because XML cannot hold it, but the rest of each sequence stays. An error message that has colors (for example, the DOM dump that Testing Library adds by default) gives:

<failure message="[36m&lt;body&gt;[39m" type="Error">

CI tools that show the message attribute then print [36m as text.

This PR strips ANSI sequences in escapeXML. The message attribute, the name of unhandled-error test cases, and system-out / system-err now get the same treatment as the <failure> body.

AI disclosure: I used Claude Code to investigate and write this change.

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. If the feature is substantial or introduces breaking changes without a discussion, PR might be closed.
  • Ideally, include a test that fails without this PR but passes with it.
  • Please, don't make changes to pnpm-lock.yaml unless you introduce a new test example.
  • Please check Allow edits by maintainers to make review process faster. Note that this option is not available for repositories that are owned by Github organizations.

Tests

  • Run the tests with pnpm test:ci.

Locally, 8 tests fail, and the same 8 fail on main without this change.

Documentation

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs command.

Changesets

  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.

🤖 Generated with Claude Code

escapeXML removed only the ESC byte, so attribute values such as the
failure message kept the rest of each sequence (e.g. "[36m").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Sep 30, 2026

Copy link
Copy Markdown

✅ Deploy Preview for vitest-dev ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit b8387a2
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/6abcd39146db4c000863d563
😎 Deploy Preview https://deploy-preview-11407--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@AriPerkkio AriPerkkio left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should JUnit reporter escape these? It seems there's no standarized answer for this.

🤖 says:

ANSI escape handling in JUnit reporters

Legend: ✅ the whole ANSI sequence is removed, ❌ it is not (something is left in the XML), — the reporter does not write that field.

Reporter testcase name / classname failure message failure body system-out / system-err What ❌ fields contain
Vitest (main) ❌ ❌ ✅ ❌ [31m
cargo-nextest ✅ ✅ ✅ ✅
Mocha built-in xunit ✅ — ✅ —
Playwright (default) ❌ ✅ ✅ ❌ [31m
Playwright (stripANSIControlSequences) ✅ ✅ ✅ ✅
jest-junit ❌ — ✅ ❌ see notes
mocha-junit-reporter ✅ ❌ ❌ ✅ [31m
PHPUnit ❌ — ❌ ❌ [31m
pytest ❌ ❌ ❌ ❌ #x1B[31m
Maven Surefire ❌ ❌ ❌ ❌ &amp#27;[31m
go-junit-report ❌ — ❌ ❌ �[31m (U+FFFD)
rspec_junit_formatter ❌ ❌ ❌ ❌ Ruby-style escape + [31m

We should probably add a reporters: [['junit', { stripAnsi: boolean }]] option for this. As we are already removing ANSI codes from body in writeErrorElement, it might be tricky to decide what the default value is. Maybe the type should be stripAnsi: true | false | 'error-bodies-only', and the default would be 'error-bodies-only'. 🤔

@meganemura

meganemura commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor Author

@AriPerkkio Thanks. I read #4958 and #5007, where always stripping was declined. I think the reasons for stripping everything are different now, so I want to suggest it once more before I add an option.

  1. Since fix(reporter): use default error formatter for JUnit #5629, the reporter strips ANSI from the <failure> / <error> body with stripVTControlCharacters. The message attribute comes from the same error, but there only ESC is removed, so text like [36m<body>[39m stays. The same happens in test names, system-out / system-err, and annotations.
  2. XML 1.0 cannot hold the colors. ESC is not in the Char production, a character reference &#x1B; breaks the "Legal Character" constraint, and CDATA also allows only Char. So removeInvalidXMLCharacters always removes ESC. This is not specific to Vitest: Playwright's JUnit reporter also removes ESC when it escapes XML. Without stripping, a user's console.log colors become [31m text, not colors. The concern in fix(vitest): strip ansi code from console output in junit reporter #5007 was about keeping colors, but no option value can keep them.

So I suggest keeping this PR as it is: strip ANSI everywhere. I will also update the description, because it lists only some of the places this change affects.

If you still want an option, how about using the Playwright default as our default? It strips only the parts built from the error: the message attribute, the body, and the stack trace. Then true strips ANSI everywhere.

@AriPerkkio AriPerkkio left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So removeInvalidXMLCharacters always removes ESC.

Ohh I wasn't aware of that. In that case, it's not even possible to preserve colors in these reports (like it was thought in #5007 (comment)).

Removing all ANSI escapes in escapeXML sounds good to me. It's bug fix, not breaking change in my opinion. @hi-ogawa thoughts?

@AriPerkkio
AriPerkkio requested a review from hi-ogawa October 1, 2026 14:33
@AriPerkkio AriPerkkio changed the title fix(junit): strip ANSI sequences from XML attributes fix(reporters): junit to strip ANSI sequences from all XML attributes Oct 1, 2026

@hi-ogawa hi-ogawa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense 👍

@hi-ogawa
hi-ogawa merged commit e1a7314 into vitest-dev:main Oct 2, 2026
29 of 30 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants