Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(test): strip ansi colors in junit output #23371

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 28 additions & 9 deletions cli/tools/test/reporters/junit.rs
Expand Up @@ -3,9 +3,14 @@
use std::collections::VecDeque;
use std::path::PathBuf;

use lazy_regex::Lazy;

use super::fmt::to_relative_path_or_remote_url;
use super::*;

static ANSI_ESCAPE_REMOVE: Lazy<Regex> =
lazy_regex::lazy_regex!(r#"\x1b\[([\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e])"#);
Comment on lines +11 to +12
Copy link
Member

Choose a reason for hiding this comment

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

Feels like we already have this code available somewhere...

Copy link
Member

Choose a reason for hiding this comment

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

Ah, you can import it from console_static_text::ansi::strip_ansi_codes


pub struct JunitTestReporter {
cwd: Url,
output_path: String,
Expand All @@ -31,13 +36,21 @@ impl JunitTestReporter {
match status {
TestResult::Ok => quick_junit::TestCaseStatus::success(),
TestResult::Ignored => quick_junit::TestCaseStatus::skipped(),
TestResult::Failed(failure) => quick_junit::TestCaseStatus::NonSuccess {
kind: quick_junit::NonSuccessKind::Failure,
message: Some(failure.overview()),
ty: None,
description: Some(failure.detail()),
reruns: vec![],
},
TestResult::Failed(failure) => {
let message = failure.overview();
let detail = failure.detail();
let message_stripped =
ANSI_ESCAPE_REMOVE.replace_all(message.as_str(), "");
let detail_stripped =
ANSI_ESCAPE_REMOVE.replace_all(detail.as_str(), "");
quick_junit::TestCaseStatus::NonSuccess {
kind: quick_junit::NonSuccessKind::Failure,
message: Some(message_stripped.into()),
ty: None,
description: Some(detail_stripped.into()),
reruns: vec![],
}
}
Comment on lines +39 to +53
Copy link
Member

Choose a reason for hiding this comment

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

I thought that it would be great to remove escape codes only when printing to non-tty, but considering it further, now I feel this isn't really necessary given that JUnit XML output is not read by human but actually ingested by some other programs in 99.9% cases.

TestResult::Cancelled => quick_junit::TestCaseStatus::NonSuccess {
kind: quick_junit::NonSuccessKind::Error,
message: Some("Cancelled".to_string()),
Expand All @@ -55,11 +68,17 @@ impl JunitTestReporter {
TestStepResult::Ok => quick_junit::TestCaseStatus::success(),
TestStepResult::Ignored => quick_junit::TestCaseStatus::skipped(),
TestStepResult::Failed(failure) => {
let message = failure.overview();
let detail = failure.detail();
let message_stripped =
ANSI_ESCAPE_REMOVE.replace_all(message.as_str(), "");
let detail_stripped =
ANSI_ESCAPE_REMOVE.replace_all(detail.as_str(), "");
quick_junit::TestCaseStatus::NonSuccess {
kind: quick_junit::NonSuccessKind::Failure,
message: Some(failure.overview()),
message: Some(message_stripped.into()),
ty: None,
description: Some(failure.detail()),
description: Some(detail_stripped.into()),
reruns: vec![],
}
}
Expand Down
6 changes: 6 additions & 0 deletions tests/integration/test_tests.rs
Expand Up @@ -295,6 +295,12 @@ itest!(junit_multiple_test_files {
exit_code: 1,
});

itest!(junit_strip_ansi {
args: "test --reporter junit test/fail_color.ts",
output: "test/junit_strip_ansi.junit.out",
exit_code: 1,
});

#[test]
fn junit_path() {
let context = TestContextBuilder::new().use_temp_cwd().build();
Expand Down
10 changes: 10 additions & 0 deletions tests/testdata/test/fail_color.ts
@@ -0,0 +1,10 @@
Deno.test("fail color", () => {
throw new Error(`RedMessage: \x1b[31mThis should be red text\x1b[39m`);
});

// deno-lint-ignore no-explicit-any
Deno.test("step fail color", async (t: any) => {
Comment on lines +5 to +6
Copy link
Member

Choose a reason for hiding this comment

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

is this type annotation needed?

await t.step("step", () => {
throw new Error(`RedMessage: \x1b[31mThis should be red text\x1b[39m`);
});
});
27 changes: 27 additions & 0 deletions tests/testdata/test/junit_strip_ansi.junit.out
@@ -0,0 +1,27 @@
Check file:///[WILDCARD]/test/fail_color.ts
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="deno test" tests="3" failures="3" errors="0" time="[WILDCARD]">
<testsuite name="./test/fail_color.ts" tests="3" disabled="0" errors="0" failures="3">
<testcase name="fail color" classname="./test/fail_color.ts" time="[WILDCARD]" line="1" col="6">
<failure message="Uncaught Error: RedMessage: This should be red text">Error: RedMessage: This should be red text
throw new Error(`RedMessage: \x1b[31mThis should be red text\x1b[39m`);
^
at file:///[WILDCARD]/test/fail_color.ts:2:9</failure>
</testcase>
<testcase name="step fail color" classname="./test/fail_color.ts" time="[WILDCARD]" line="6" col="6">
<failure message="1 test step failed">1 test step failed.</failure>
</testcase>
<testcase name="step fail color &gt; step" classname="./test/fail_color.ts" time="[WILDCARD]" line="7" col="11">
<failure message="Uncaught Error: RedMessage: This should be red text">Error: RedMessage: This should be red text
throw new Error(`RedMessage: \x1b[31mThis should be red text\x1b[39m`);
^
at file:///[WILDCARD]/test/fail_color.ts:8:11
at innerWrapped (ext:cli/40_test.js:174:11)
at exitSanitizer (ext:cli/40_test.js:103:33)
at Object.outerWrapped [as fn] (ext:cli/40_test.js:117:20)
at TestContext.step (ext:cli/40_test.js:475:37)
at file:///[WILDCARD]/test/fail_color.ts:7:11</failure>
</testcase>
</testsuite>
</testsuites>
error: Test failed