From 2652c0ece98fff44fcdf119f823015c900e73021 Mon Sep 17 00:00:00 2001 From: hanityx Date: Fri, 11 Sep 2026 03:31:36 +0900 Subject: [PATCH] test_runner: fix quote escaping in JUnit Escape XML content before replacing double quotes and line feeds. Add a snapshot test for repeated quotes, literal quote references, and quotes mixed with ampersands, less-than signs, or a newline. Signed-off-by: hanityx --- lib/internal/test_runner/reporter/junit.js | 2 +- test/fixtures/test-runner/output/junit_quote.js | 9 +++++++++ .../test-runner/output/junit_quote.snapshot | 16 ++++++++++++++++ test/test-runner/test-output-junit-quote.mjs | 11 +++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/test-runner/output/junit_quote.js create mode 100644 test/fixtures/test-runner/output/junit_quote.snapshot create mode 100644 test/test-runner/test-output-junit-quote.mjs diff --git a/lib/internal/test_runner/reporter/junit.js b/lib/internal/test_runner/reporter/junit.js index 5052f5444c0d..e5a3fa961eac 100644 --- a/lib/internal/test_runner/reporter/junit.js +++ b/lib/internal/test_runner/reporter/junit.js @@ -22,7 +22,7 @@ const inspectOptions = { __proto__: null, colors: false, breakLength: Infinity } const HOSTNAME = hostname(); function escapeAttribute(s = '') { - return escapeContent(RegExpPrototypeSymbolReplace(/"/g, RegExpPrototypeSymbolReplace(/\n/g, s, ' '), '"')); + return RegExpPrototypeSymbolReplace(/"/g, RegExpPrototypeSymbolReplace(/\n/g, escapeContent(s), ' '), '"'); } function escapeContent(s = '') { diff --git a/test/fixtures/test-runner/output/junit_quote.js b/test/fixtures/test-runner/output/junit_quote.js new file mode 100644 index 000000000000..4f77d9ffbb0e --- /dev/null +++ b/test/fixtures/test-runner/output/junit_quote.js @@ -0,0 +1,9 @@ +// Flags: --test --test-reporter=junit +'use strict'; +const test = require('node:test'); + +test('quote"only', () => {}); +test('quote"only', () => {}); +test('amp&and"quote"', () => {}); +test('lt {}); +test('line\n"break', () => {}); diff --git a/test/fixtures/test-runner/output/junit_quote.snapshot b/test/fixtures/test-runner/output/junit_quote.snapshot new file mode 100644 index 000000000000..48d3ac2c53c2 --- /dev/null +++ b/test/fixtures/test-runner/output/junit_quote.snapshot @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/test/test-runner/test-output-junit-quote.mjs b/test/test-runner/test-output-junit-quote.mjs new file mode 100644 index 000000000000..6d1769eea83f --- /dev/null +++ b/test/test-runner/test-output-junit-quote.mjs @@ -0,0 +1,11 @@ +// Test that the output of test-runner/output/junit_quote.js matches +// test-runner/output/junit_quote.snapshot +import '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, junitTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/junit_quote.js'), + junitTransform, +);