From a513bd7d8bb30a4b793648d68d19bf2961252086 Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Fri, 3 Oct 2025 20:43:59 +0200 Subject: [PATCH 01/15] Allow overriding the strategy and featureName --- .../MessagesToJunitXmlWriter.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java index 54dd98a..5baf53c 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java @@ -31,11 +31,19 @@ public MessagesToJunitXmlWriter(OutputStream out) { } public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, OutputStream out) { - this(createNamingStrategy(requireNonNull(exampleNameStrategy)), out); + this(createNamingStrategy(requireNonNull(exampleNameStrategy, LONG, EXCLUDE)), out); } - private static NamingStrategy createNamingStrategy(NamingStrategy.ExampleName exampleName) { - return NamingStrategy.strategy(LONG).featureName(EXCLUDE).exampleName(exampleName).build(); + public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.strategy strategy, OutputStream out) { + this(createNamingStrategy(requireNonNull(exampleNameStrategy), requireNonNull(strategy), EXCLUDE), out); + } + + public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.strategy strategy, NamingStrategy.FeatureName featureNameStrategy, OutputStream out) { + this(createNamingStrategy(requireNonNull(exampleNameStrategy), requireNonNull(strategy), requireNonNull(featureNameStrategy)), out); + } + + private static NamingStrategy createNamingStrategy(NamingStrategy.ExampleName exampleName, NamingStrategy.strategy strategy, NamingStrategy.FeatureName featureName) { + return NamingStrategy.strategy(strategy).featureName(featureName).exampleName(exampleName).build(); } private MessagesToJunitXmlWriter(NamingStrategy namingStrategy, OutputStream out) { From 05304e8465589cb75b58090af30042afcdb85d95 Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Fri, 3 Oct 2025 20:45:30 +0200 Subject: [PATCH 02/15] Update MessagesToJunitXmlWriter.java --- .../io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java index 5baf53c..e35f0ae 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java @@ -31,7 +31,7 @@ public MessagesToJunitXmlWriter(OutputStream out) { } public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, OutputStream out) { - this(createNamingStrategy(requireNonNull(exampleNameStrategy, LONG, EXCLUDE)), out); + this(createNamingStrategy(requireNonNull(exampleNameStrategy), LONG, EXCLUDE), out); } public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.strategy strategy, OutputStream out) { From b74281e75e90aa96634bf951fb90b0b530a671c5 Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Fri, 3 Oct 2025 20:47:47 +0200 Subject: [PATCH 03/15] Update MessagesToJunitXmlWriter.java --- .../junitxmlformatter/MessagesToJunitXmlWriter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java index e35f0ae..e05085c 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java @@ -34,15 +34,15 @@ public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, this(createNamingStrategy(requireNonNull(exampleNameStrategy), LONG, EXCLUDE), out); } - public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.strategy strategy, OutputStream out) { + public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.Strategy strategy, OutputStream out) { this(createNamingStrategy(requireNonNull(exampleNameStrategy), requireNonNull(strategy), EXCLUDE), out); } - public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.strategy strategy, NamingStrategy.FeatureName featureNameStrategy, OutputStream out) { + public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.Strategy strategy, NamingStrategy.FeatureName featureNameStrategy, OutputStream out) { this(createNamingStrategy(requireNonNull(exampleNameStrategy), requireNonNull(strategy), requireNonNull(featureNameStrategy)), out); } - private static NamingStrategy createNamingStrategy(NamingStrategy.ExampleName exampleName, NamingStrategy.strategy strategy, NamingStrategy.FeatureName featureName) { + private static NamingStrategy createNamingStrategy(NamingStrategy.ExampleName exampleName, NamingStrategy.Strategy strategy, NamingStrategy.FeatureName featureName) { return NamingStrategy.strategy(strategy).featureName(featureName).exampleName(exampleName).build(); } From 9da9bcc3de0118eba61d46172083e8392c8484f9 Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Fri, 3 Oct 2025 20:54:51 +0200 Subject: [PATCH 04/15] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eddab3..b064a22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Support configurable `NamingStrategy.Strategy` and `NamingStrategy.FeatureName` + ## [0.9.0] - 2025-09-11 ### Changed - Update dependency cucumber/query to 14.0.1 From 6ae58e22aa2afdab85d31a8e4c3046109a38ddf7 Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Fri, 3 Oct 2025 21:06:51 +0200 Subject: [PATCH 05/15] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b064a22..9dcf81d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Support configurable `NamingStrategy.Strategy` and `NamingStrategy.FeatureName` +- Support configurable `NamingStrategy.Strategy` and `NamingStrategy.FeatureName` ([#105](https://github.com/cucumber/junit-xml-formatter/pull/105)) ## [0.9.0] - 2025-09-11 ### Changed From 3ca07d5f8e29e8b027b2a5c9835b16ad0d41622e Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Sat, 4 Oct 2025 18:37:16 +0200 Subject: [PATCH 06/15] Support NamingStrategy in JS too --- javascript/src/makeReport.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/src/makeReport.ts b/javascript/src/makeReport.ts index ca97b5b..5a17ed8 100644 --- a/javascript/src/makeReport.ts +++ b/javascript/src/makeReport.ts @@ -40,7 +40,7 @@ interface ReportFailure { stack?: string } -export function makeReport(query: Query): ReportSuite { +export function makeReport(query, customNamingStrategy = NAMING_STRATEGY): ReportSuite { const statuses = query.countMostSevereTestStepResultStatus() return { time: durationToSeconds(query.findTestRunDuration()), @@ -51,12 +51,12 @@ export function makeReport(query: Query): ReportSuite { (status) => status !== TestStepResultStatus.PASSED && status !== TestStepResultStatus.SKIPPED ), errors: 0, - testCases: makeTestCases(query), + testCases: makeTestCases(query, customNamingStrategy), timestamp: formatTimestamp(query.findTestRunStarted()), } } -function makeTestCases(query: Query): ReadonlyArray { +function makeTestCases(query: Query, namingStrategy: NamingStrategy): ReadonlyArray { return query.findAllTestCaseStarted().map((testCaseStarted) => { const pickle = ensure( query.findPickleBy(testCaseStarted), From 555db8388c120e741edd9a6d3292be50352c88e6 Mon Sep 17 00:00:00 2001 From: Ulrich Pogson Date: Sat, 4 Oct 2025 18:38:49 +0200 Subject: [PATCH 07/15] Update makeReport.ts --- javascript/src/makeReport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/src/makeReport.ts b/javascript/src/makeReport.ts index 5a17ed8..2865ba8 100644 --- a/javascript/src/makeReport.ts +++ b/javascript/src/makeReport.ts @@ -40,7 +40,7 @@ interface ReportFailure { stack?: string } -export function makeReport(query, customNamingStrategy = NAMING_STRATEGY): ReportSuite { +export function makeReport(query: Query, customNamingStrategy: NamingStrategy = NAMING_STRATEGY): ReportSuite { const statuses = query.countMostSevereTestStepResultStatus() return { time: durationToSeconds(query.findTestRunDuration()), From 5b02cb14136f128ef89e163ebd4814bb9d99af8f Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 6 Oct 2025 16:01:32 +0200 Subject: [PATCH 08/15] Use builder pattern for the naming strategy - Makes the whole naming strategy configurable - Make suite name configurable - Make test class name configurable --- .../MessagesToJunitXmlWriter.java | 64 ++++++++++++++++--- .../junitxmlformatter/XmlReportData.java | 31 ++++++--- .../junitxmlformatter/XmlReportWriter.java | 6 +- ...essagesToJunitXmlWriterAcceptanceTest.java | 2 +- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java index e05085c..4909797 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java @@ -9,6 +9,7 @@ import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; +import static io.cucumber.query.NamingStrategy.ExampleName.NUMBER_AND_PICKLE_IF_PARAMETERIZED; import static io.cucumber.query.NamingStrategy.FeatureName.EXCLUDE; import static io.cucumber.query.NamingStrategy.Strategy.LONG; import static java.util.Objects.requireNonNull; @@ -22,32 +23,75 @@ */ public final class MessagesToJunitXmlWriter implements AutoCloseable { + private static final String DEFAULT_TEST_SUITE_NAME = "Cucumber"; private final OutputStreamWriter out; private final XmlReportData data; private boolean streamClosed = false; public MessagesToJunitXmlWriter(OutputStream out) { - this(NamingStrategy.ExampleName.NUMBER_AND_PICKLE_IF_PARAMETERIZED, out); + this("Cucumber", null, createNamingStrategy(NUMBER_AND_PICKLE_IF_PARAMETERIZED), out); } + @Deprecated public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, OutputStream out) { - this(createNamingStrategy(requireNonNull(exampleNameStrategy), LONG, EXCLUDE), out); + this("Cucumber", null, createNamingStrategy(requireNonNull(exampleNameStrategy)), out); } - public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.Strategy strategy, OutputStream out) { - this(createNamingStrategy(requireNonNull(exampleNameStrategy), requireNonNull(strategy), EXCLUDE), out); + public static Builder builder() { + return new Builder(); } - public MessagesToJunitXmlWriter(NamingStrategy.ExampleName exampleNameStrategy, NamingStrategy.Strategy strategy, NamingStrategy.FeatureName featureNameStrategy, OutputStream out) { - this(createNamingStrategy(requireNonNull(exampleNameStrategy), requireNonNull(strategy), requireNonNull(featureNameStrategy)), out); + public static class Builder { + + private String testSuiteName = DEFAULT_TEST_SUITE_NAME; + private String testClassName; + private NamingStrategy testNamingStrategy = NamingStrategy.strategy(LONG) + .featureName(EXCLUDE) + .exampleName(NUMBER_AND_PICKLE_IF_PARAMETERIZED) + .build(); + + private Builder() { + + } + + /** + * Sets the value for the {@code } attribute. Defaults to {@value DEFAULT_TEST_SUITE_NAME}. + */ + public Builder testSuiteName(String testSuiteName) { + this.testSuiteName = requireNonNull(testSuiteName); + return this; + } + + /** + * Sets the value for the {@code } attribute. Defaults to the name of the + * feature file. + */ + public Builder testClassName(String testClassName) { + this.testClassName = testClassName; + return this; + } + + /** + * Set the naming strategy used for the {@code attribute}. Defaults to the + * {@link NamingStrategy.Strategy#LONG} strategy with {@link NamingStrategy.FeatureName#EXCLUDE} and + * {@link NamingStrategy.ExampleName#NUMBER_AND_PICKLE_IF_PARAMETERIZED}. + */ + public Builder namingStrategy(NamingStrategy namingStrategy) { + this.testNamingStrategy = requireNonNull(namingStrategy); + return this; + } + + public MessagesToJunitXmlWriter build(OutputStream out) { + return new MessagesToJunitXmlWriter(testSuiteName, testClassName, testNamingStrategy, requireNonNull(out)); + } } - private static NamingStrategy createNamingStrategy(NamingStrategy.ExampleName exampleName, NamingStrategy.Strategy strategy, NamingStrategy.FeatureName featureName) { - return NamingStrategy.strategy(strategy).featureName(featureName).exampleName(exampleName).build(); + private static NamingStrategy createNamingStrategy(NamingStrategy.ExampleName exampleName) { + return NamingStrategy.strategy(NamingStrategy.Strategy.LONG).featureName(NamingStrategy.FeatureName.EXCLUDE).exampleName(exampleName).build(); } - private MessagesToJunitXmlWriter(NamingStrategy namingStrategy, OutputStream out) { - this.data = new XmlReportData(namingStrategy); + private MessagesToJunitXmlWriter(String testSuiteName, String testClassName, NamingStrategy testNamingStrategy, OutputStream out) { + this.data = new XmlReportData(testSuiteName, testClassName, testNamingStrategy); this.out = new OutputStreamWriter( requireNonNull(out), StandardCharsets.UTF_8 diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportData.java b/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportData.java index 61bbea3..ef4ddd6 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportData.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportData.java @@ -28,21 +28,25 @@ import static io.cucumber.messages.types.TestStepResultStatus.PASSED; import static io.cucumber.query.Repository.RepositoryFeature.INCLUDE_GHERKIN_DOCUMENTS; import static java.time.format.DateTimeFormatter.ISO_INSTANT; +import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.stream.Collectors.toList; class XmlReportData { + private static final long MILLIS_PER_SECOND = SECONDS.toMillis(1L); private final Repository repository = Repository.builder() .feature(INCLUDE_GHERKIN_DOCUMENTS, true) .build(); private final Query query = new Query(repository); - private final NamingStrategy namingStrategy; - - private static final long MILLIS_PER_SECOND = SECONDS.toMillis(1L); - - XmlReportData(NamingStrategy namingStrategy) { - this.namingStrategy = namingStrategy; + private final String testSuiteName; + private final String testClassName; + private final NamingStrategy testNamingStrategy; + + XmlReportData(String testSuiteName, String testClassName, NamingStrategy testNamingStrategy) { + this.testSuiteName = requireNonNull(testSuiteName); + this.testClassName = testClassName; + this.testNamingStrategy = requireNonNull(testNamingStrategy); } void collect(Envelope envelope) { @@ -74,20 +78,27 @@ private Pickle getPickle(TestCaseStarted testCaseStarted) { .orElseThrow(() -> new IllegalStateException("No pickle for " + testCaseStarted.getId())); } - String getPickleName(TestCaseStarted testCaseStarted) { + String getTestName(TestCaseStarted testCaseStarted) { Pickle pickle = getPickle(testCaseStarted); return query.findLineageBy(pickle) - .map(lineage -> namingStrategy.reduce(lineage, pickle)) + .map(lineage -> testNamingStrategy.reduce(lineage, pickle)) .orElseGet(pickle::getName); } - String getFeatureName(TestCaseStarted testCaseStarted) { + String getTestClassName(TestCaseStarted testCaseStarted) { + if (testClassName != null) { + return testClassName; + } return query.findLineageBy(testCaseStarted) .flatMap(Lineage::feature) .map(Feature::getName) .orElseGet(() -> this.getPickle(testCaseStarted).getUri()); } + String getTestSuiteName() { + return testSuiteName; + } + List> getStepsAndResult(TestCaseStarted testCaseStarted) { return query.findTestStepFinishedAndTestStepBy(testCaseStarted) .stream() @@ -138,7 +149,7 @@ TestStepResult getTestCaseStatus(TestCaseStarted testCaseStarted) { .orElse(SCENARIO_WITH_NO_STEPS); } - public Optional getTestRunStartedAt() { + Optional getTestRunStartedAt() { return query.findTestRunStarted() .map(TestRunStarted::getTimestamp) .map(Convertor::toInstant) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportWriter.java index 040b27d..dd3f407 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/XmlReportWriter.java @@ -47,7 +47,7 @@ private void writeTestsuite(EscapingXmlStreamWriter writer) throws XMLStreamExce } private void writeSuiteAttributes(EscapingXmlStreamWriter writer) throws XMLStreamException { - writer.writeAttribute("name", "Cucumber"); + writer.writeAttribute("name", data.getTestSuiteName()); writer.writeAttribute("time", String.valueOf(data.getSuiteDurationInSeconds())); Map counts = data.getTestCaseStatusCounts(); @@ -85,8 +85,8 @@ private void writeTestcase(EscapingXmlStreamWriter writer, TestCaseStarted testC } private void writeTestCaseAttributes(EscapingXmlStreamWriter writer, TestCaseStarted testCaseStarted) throws XMLStreamException { - writer.writeAttribute("classname", data.getFeatureName(testCaseStarted)); - writer.writeAttribute("name", data.getPickleName(testCaseStarted)); + writer.writeAttribute("classname", data.getTestClassName(testCaseStarted)); + writer.writeAttribute("name", data.getTestName(testCaseStarted)); writer.writeAttribute("time", String.valueOf(data.getDurationInSeconds(testCaseStarted))); } diff --git a/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java b/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java index 05ef8a8..37cb167 100644 --- a/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java +++ b/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java @@ -94,7 +94,7 @@ void updateExpectedFiles(TestCase testCase) throws IOException { private static T writeJunitXmlReport(TestCase testCase, T out) throws IOException { try (InputStream in = Files.newInputStream(testCase.source)) { try (NdjsonToMessageIterable envelopes = new NdjsonToMessageIterable(in, deserializer)) { - try (MessagesToJunitXmlWriter writer = new MessagesToJunitXmlWriter(out)) { + try (MessagesToJunitXmlWriter writer = MessagesToJunitXmlWriter.builder().build(out)) { for (Envelope envelope : envelopes) { writer.write(envelope); } From 1283e542962ecad73834477e6c6088ce4d9939e2 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 6 Oct 2025 16:22:46 +0200 Subject: [PATCH 09/15] Use custom naming in test --- ...essagesToJunitXmlWriterAcceptanceTest.java | 47 +++++++++--- .../{ambiguous.xml => ambiguous.default.xml} | 0 ...ttachments.xml => attachments.default.xml} | 0 ...ackgrounds.xml => backgrounds.default.xml} | 0 testdata/src/{cdata.xml => cdata.default.xml} | 0 ...ata-tables.xml => data-tables.default.xml} | 0 ...oc-strings.xml => doc-strings.default.xml} | 0 testdata/src/{empty.xml => empty.default.xml} | 0 ...=> examples-tables-attachment.default.xml} | 0 ... => examples-tables-undefined.default.xml} | 0 testdata/src/examples-tables.custom.xml | 72 +++++++++++++++++++ ...tables.xml => examples-tables.default.xml} | 0 ...> global-hooks-afterall-error.default.xml} | 0 ...l => global-hooks-attachments.default.xml} | 0 ... global-hooks-beforeall-error.default.xml} | 0 ...bal-hooks.xml => global-hooks.default.xml} | 0 ...hment.xml => hooks-attachment.default.xml} | 0 ...onal.xml => hooks-conditional.default.xml} | 0 ...ooks-named.xml => hooks-named.default.xml} | 0 ...efined.xml => hooks-undefined.default.xml} | 0 testdata/src/{hooks.xml => hooks.default.xml} | 0 .../{markdown.xml => markdown.default.xml} | 0 .../src/{minimal.xml => minimal.default.xml} | 0 ...=> multiple-features-reversed.default.xml} | 0 ...ures.xml => multiple-features.default.xml} | 0 ...-types.xml => parameter-types.default.xml} | 0 .../src/{pending.xml => pending.default.xml} | 0 ...ion.xml => regular-expression.default.xml} | 0 ...iguous.xml => retry-ambiguous.default.xml} | 0 ...-pending.xml => retry-pending.default.xml} | 0 ...efined.xml => retry-undefined.default.xml} | 0 testdata/src/{retry.xml => retry.default.xml} | 0 ...unds.xml => rules-backgrounds.default.xml} | 0 testdata/src/{rules.xml => rules.default.xml} | 0 .../src/{skipped.xml => skipped.default.xml} | 0 ...ck-traces.xml => stack-traces.default.xml} | 0 .../{undefined.xml => undefined.default.xml} | 0 ...xml => unknown-parameter-type.default.xml} | 0 ...sed-steps.xml => unused-steps.default.xml} | 0 39 files changed, 111 insertions(+), 8 deletions(-) rename testdata/src/{ambiguous.xml => ambiguous.default.xml} (100%) rename testdata/src/{attachments.xml => attachments.default.xml} (100%) rename testdata/src/{backgrounds.xml => backgrounds.default.xml} (100%) rename testdata/src/{cdata.xml => cdata.default.xml} (100%) rename testdata/src/{data-tables.xml => data-tables.default.xml} (100%) rename testdata/src/{doc-strings.xml => doc-strings.default.xml} (100%) rename testdata/src/{empty.xml => empty.default.xml} (100%) rename testdata/src/{examples-tables-attachment.xml => examples-tables-attachment.default.xml} (100%) rename testdata/src/{examples-tables-undefined.xml => examples-tables-undefined.default.xml} (100%) create mode 100644 testdata/src/examples-tables.custom.xml rename testdata/src/{examples-tables.xml => examples-tables.default.xml} (100%) rename testdata/src/{global-hooks-afterall-error.xml => global-hooks-afterall-error.default.xml} (100%) rename testdata/src/{global-hooks-attachments.xml => global-hooks-attachments.default.xml} (100%) rename testdata/src/{global-hooks-beforeall-error.xml => global-hooks-beforeall-error.default.xml} (100%) rename testdata/src/{global-hooks.xml => global-hooks.default.xml} (100%) rename testdata/src/{hooks-attachment.xml => hooks-attachment.default.xml} (100%) rename testdata/src/{hooks-conditional.xml => hooks-conditional.default.xml} (100%) rename testdata/src/{hooks-named.xml => hooks-named.default.xml} (100%) rename testdata/src/{hooks-undefined.xml => hooks-undefined.default.xml} (100%) rename testdata/src/{hooks.xml => hooks.default.xml} (100%) rename testdata/src/{markdown.xml => markdown.default.xml} (100%) rename testdata/src/{minimal.xml => minimal.default.xml} (100%) rename testdata/src/{multiple-features-reversed.xml => multiple-features-reversed.default.xml} (100%) rename testdata/src/{multiple-features.xml => multiple-features.default.xml} (100%) rename testdata/src/{parameter-types.xml => parameter-types.default.xml} (100%) rename testdata/src/{pending.xml => pending.default.xml} (100%) rename testdata/src/{regular-expression.xml => regular-expression.default.xml} (100%) rename testdata/src/{retry-ambiguous.xml => retry-ambiguous.default.xml} (100%) rename testdata/src/{retry-pending.xml => retry-pending.default.xml} (100%) rename testdata/src/{retry-undefined.xml => retry-undefined.default.xml} (100%) rename testdata/src/{retry.xml => retry.default.xml} (100%) rename testdata/src/{rules-backgrounds.xml => rules-backgrounds.default.xml} (100%) rename testdata/src/{rules.xml => rules.default.xml} (100%) rename testdata/src/{skipped.xml => skipped.default.xml} (100%) rename testdata/src/{stack-traces.xml => stack-traces.default.xml} (100%) rename testdata/src/{undefined.xml => undefined.default.xml} (100%) rename testdata/src/{unknown-parameter-type.xml => unknown-parameter-type.default.xml} (100%) rename testdata/src/{unused-steps.xml => unused-steps.default.xml} (100%) diff --git a/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java b/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java index 37cb167..b47b831 100644 --- a/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java +++ b/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java @@ -2,6 +2,8 @@ import io.cucumber.messages.NdjsonToMessageIterable; import io.cucumber.messages.types.Envelope; +import io.cucumber.query.NamingStrategy; +import io.cucumber.query.NamingStrategy.Strategy; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; @@ -24,7 +26,6 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import java.util.stream.Stream; import static io.cucumber.junitxmlformatter.Jackson.OBJECT_MAPPER; @@ -34,13 +35,35 @@ class MessagesToJunitXmlWriterAcceptanceTest { private static final NdjsonToMessageIterable.Deserializer deserializer = (json) -> OBJECT_MAPPER.readValue(json, Envelope.class); static List acceptance() throws IOException { + List testCases = new ArrayList<>(); + try (Stream paths = Files.list(Paths.get("../testdata/src"))) { - return paths + paths .filter(path -> path.getFileName().toString().endsWith(".ndjson")) - .map(TestCase::new) + .map(source -> new TestCase( + source, + "default", + MessagesToJunitXmlWriter.builder() + ) + ) .sorted(Comparator.comparing(testCase -> testCase.source)) - .collect(Collectors.toList()); + .forEach(testCases::add); } + + testCases.add( + new TestCase( + Paths.get("../testdata/src/examples-tables.ndjson"), + "custom", + MessagesToJunitXmlWriter.builder() + .testSuiteName("Cucumber Suite") + .testClassName("Cucumber Class") + .namingStrategy(NamingStrategy + .strategy(Strategy.LONG) + .build()) + ) + ); + + return testCases; } @ParameterizedTest @@ -94,7 +117,7 @@ void updateExpectedFiles(TestCase testCase) throws IOException { private static T writeJunitXmlReport(TestCase testCase, T out) throws IOException { try (InputStream in = Files.newInputStream(testCase.source)) { try (NdjsonToMessageIterable envelopes = new NdjsonToMessageIterable(in, deserializer)) { - try (MessagesToJunitXmlWriter writer = MessagesToJunitXmlWriter.builder().build(out)) { + try (MessagesToJunitXmlWriter writer = testCase.getBuilder().build(out)) { for (Envelope envelope : envelopes) { writer.write(envelope); } @@ -109,17 +132,25 @@ static class TestCase { private final Path expected; private final String name; + private final MessagesToJunitXmlWriter.Builder builder; + private final String strategyName; - TestCase(Path source) { + TestCase(Path source, String namingStrategyName, MessagesToJunitXmlWriter.Builder builder) { this.source = source; String fileName = source.getFileName().toString(); this.name = fileName.substring(0, fileName.lastIndexOf(".ndjson")); - this.expected = source.getParent().resolve(name + ".xml"); + this.expected = source.getParent().resolve(name + "." + namingStrategyName + ".xml"); + this.builder = builder; + this.strategyName = namingStrategyName; + } + + MessagesToJunitXmlWriter.Builder getBuilder() { + return builder; } @Override public String toString() { - return name; + return name + " -> " + strategyName; } @Override diff --git a/testdata/src/ambiguous.xml b/testdata/src/ambiguous.default.xml similarity index 100% rename from testdata/src/ambiguous.xml rename to testdata/src/ambiguous.default.xml diff --git a/testdata/src/attachments.xml b/testdata/src/attachments.default.xml similarity index 100% rename from testdata/src/attachments.xml rename to testdata/src/attachments.default.xml diff --git a/testdata/src/backgrounds.xml b/testdata/src/backgrounds.default.xml similarity index 100% rename from testdata/src/backgrounds.xml rename to testdata/src/backgrounds.default.xml diff --git a/testdata/src/cdata.xml b/testdata/src/cdata.default.xml similarity index 100% rename from testdata/src/cdata.xml rename to testdata/src/cdata.default.xml diff --git a/testdata/src/data-tables.xml b/testdata/src/data-tables.default.xml similarity index 100% rename from testdata/src/data-tables.xml rename to testdata/src/data-tables.default.xml diff --git a/testdata/src/doc-strings.xml b/testdata/src/doc-strings.default.xml similarity index 100% rename from testdata/src/doc-strings.xml rename to testdata/src/doc-strings.default.xml diff --git a/testdata/src/empty.xml b/testdata/src/empty.default.xml similarity index 100% rename from testdata/src/empty.xml rename to testdata/src/empty.default.xml diff --git a/testdata/src/examples-tables-attachment.xml b/testdata/src/examples-tables-attachment.default.xml similarity index 100% rename from testdata/src/examples-tables-attachment.xml rename to testdata/src/examples-tables-attachment.default.xml diff --git a/testdata/src/examples-tables-undefined.xml b/testdata/src/examples-tables-undefined.default.xml similarity index 100% rename from testdata/src/examples-tables-undefined.xml rename to testdata/src/examples-tables-undefined.default.xml diff --git a/testdata/src/examples-tables.custom.xml b/testdata/src/examples-tables.custom.xml new file mode 100644 index 0000000..d2b6c69 --- /dev/null +++ b/testdata/src/examples-tables.custom.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testdata/src/examples-tables.xml b/testdata/src/examples-tables.default.xml similarity index 100% rename from testdata/src/examples-tables.xml rename to testdata/src/examples-tables.default.xml diff --git a/testdata/src/global-hooks-afterall-error.xml b/testdata/src/global-hooks-afterall-error.default.xml similarity index 100% rename from testdata/src/global-hooks-afterall-error.xml rename to testdata/src/global-hooks-afterall-error.default.xml diff --git a/testdata/src/global-hooks-attachments.xml b/testdata/src/global-hooks-attachments.default.xml similarity index 100% rename from testdata/src/global-hooks-attachments.xml rename to testdata/src/global-hooks-attachments.default.xml diff --git a/testdata/src/global-hooks-beforeall-error.xml b/testdata/src/global-hooks-beforeall-error.default.xml similarity index 100% rename from testdata/src/global-hooks-beforeall-error.xml rename to testdata/src/global-hooks-beforeall-error.default.xml diff --git a/testdata/src/global-hooks.xml b/testdata/src/global-hooks.default.xml similarity index 100% rename from testdata/src/global-hooks.xml rename to testdata/src/global-hooks.default.xml diff --git a/testdata/src/hooks-attachment.xml b/testdata/src/hooks-attachment.default.xml similarity index 100% rename from testdata/src/hooks-attachment.xml rename to testdata/src/hooks-attachment.default.xml diff --git a/testdata/src/hooks-conditional.xml b/testdata/src/hooks-conditional.default.xml similarity index 100% rename from testdata/src/hooks-conditional.xml rename to testdata/src/hooks-conditional.default.xml diff --git a/testdata/src/hooks-named.xml b/testdata/src/hooks-named.default.xml similarity index 100% rename from testdata/src/hooks-named.xml rename to testdata/src/hooks-named.default.xml diff --git a/testdata/src/hooks-undefined.xml b/testdata/src/hooks-undefined.default.xml similarity index 100% rename from testdata/src/hooks-undefined.xml rename to testdata/src/hooks-undefined.default.xml diff --git a/testdata/src/hooks.xml b/testdata/src/hooks.default.xml similarity index 100% rename from testdata/src/hooks.xml rename to testdata/src/hooks.default.xml diff --git a/testdata/src/markdown.xml b/testdata/src/markdown.default.xml similarity index 100% rename from testdata/src/markdown.xml rename to testdata/src/markdown.default.xml diff --git a/testdata/src/minimal.xml b/testdata/src/minimal.default.xml similarity index 100% rename from testdata/src/minimal.xml rename to testdata/src/minimal.default.xml diff --git a/testdata/src/multiple-features-reversed.xml b/testdata/src/multiple-features-reversed.default.xml similarity index 100% rename from testdata/src/multiple-features-reversed.xml rename to testdata/src/multiple-features-reversed.default.xml diff --git a/testdata/src/multiple-features.xml b/testdata/src/multiple-features.default.xml similarity index 100% rename from testdata/src/multiple-features.xml rename to testdata/src/multiple-features.default.xml diff --git a/testdata/src/parameter-types.xml b/testdata/src/parameter-types.default.xml similarity index 100% rename from testdata/src/parameter-types.xml rename to testdata/src/parameter-types.default.xml diff --git a/testdata/src/pending.xml b/testdata/src/pending.default.xml similarity index 100% rename from testdata/src/pending.xml rename to testdata/src/pending.default.xml diff --git a/testdata/src/regular-expression.xml b/testdata/src/regular-expression.default.xml similarity index 100% rename from testdata/src/regular-expression.xml rename to testdata/src/regular-expression.default.xml diff --git a/testdata/src/retry-ambiguous.xml b/testdata/src/retry-ambiguous.default.xml similarity index 100% rename from testdata/src/retry-ambiguous.xml rename to testdata/src/retry-ambiguous.default.xml diff --git a/testdata/src/retry-pending.xml b/testdata/src/retry-pending.default.xml similarity index 100% rename from testdata/src/retry-pending.xml rename to testdata/src/retry-pending.default.xml diff --git a/testdata/src/retry-undefined.xml b/testdata/src/retry-undefined.default.xml similarity index 100% rename from testdata/src/retry-undefined.xml rename to testdata/src/retry-undefined.default.xml diff --git a/testdata/src/retry.xml b/testdata/src/retry.default.xml similarity index 100% rename from testdata/src/retry.xml rename to testdata/src/retry.default.xml diff --git a/testdata/src/rules-backgrounds.xml b/testdata/src/rules-backgrounds.default.xml similarity index 100% rename from testdata/src/rules-backgrounds.xml rename to testdata/src/rules-backgrounds.default.xml diff --git a/testdata/src/rules.xml b/testdata/src/rules.default.xml similarity index 100% rename from testdata/src/rules.xml rename to testdata/src/rules.default.xml diff --git a/testdata/src/skipped.xml b/testdata/src/skipped.default.xml similarity index 100% rename from testdata/src/skipped.xml rename to testdata/src/skipped.default.xml diff --git a/testdata/src/stack-traces.xml b/testdata/src/stack-traces.default.xml similarity index 100% rename from testdata/src/stack-traces.xml rename to testdata/src/stack-traces.default.xml diff --git a/testdata/src/undefined.xml b/testdata/src/undefined.default.xml similarity index 100% rename from testdata/src/undefined.xml rename to testdata/src/undefined.default.xml diff --git a/testdata/src/unknown-parameter-type.xml b/testdata/src/unknown-parameter-type.default.xml similarity index 100% rename from testdata/src/unknown-parameter-type.xml rename to testdata/src/unknown-parameter-type.default.xml diff --git a/testdata/src/unused-steps.xml b/testdata/src/unused-steps.default.xml similarity index 100% rename from testdata/src/unused-steps.xml rename to testdata/src/unused-steps.default.xml From 7e95a061a5bfd41d364900e428966a34e5c5b855 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 7 Oct 2025 02:54:28 +0200 Subject: [PATCH 10/15] Fix naming --- .../junitxmlformatter/MessagesToJunitXmlWriter.java | 2 +- .../MessagesToJunitXmlWriterAcceptanceTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java index 4909797..5f7d6f1 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java @@ -76,7 +76,7 @@ public Builder testClassName(String testClassName) { * {@link NamingStrategy.Strategy#LONG} strategy with {@link NamingStrategy.FeatureName#EXCLUDE} and * {@link NamingStrategy.ExampleName#NUMBER_AND_PICKLE_IF_PARAMETERIZED}. */ - public Builder namingStrategy(NamingStrategy namingStrategy) { + public Builder testNamingStrategy(NamingStrategy namingStrategy) { this.testNamingStrategy = requireNonNull(namingStrategy); return this; } diff --git a/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java b/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java index b47b831..e649036 100644 --- a/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java +++ b/java/src/test/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriterAcceptanceTest.java @@ -29,6 +29,8 @@ import java.util.stream.Stream; import static io.cucumber.junitxmlformatter.Jackson.OBJECT_MAPPER; +import static io.cucumber.query.NamingStrategy.Strategy.LONG; +import static io.cucumber.query.NamingStrategy.strategy; import static org.xmlunit.assertj.XmlAssert.assertThat; class MessagesToJunitXmlWriterAcceptanceTest { @@ -57,9 +59,7 @@ static List acceptance() throws IOException { MessagesToJunitXmlWriter.builder() .testSuiteName("Cucumber Suite") .testClassName("Cucumber Class") - .namingStrategy(NamingStrategy - .strategy(Strategy.LONG) - .build()) + .testNamingStrategy(strategy(LONG).build()) ) ); From 7de60e8bbd623c32f420595fa7863862c1dacf7b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 7 Oct 2025 02:55:01 +0200 Subject: [PATCH 11/15] Fix docs --- .../io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java index 5f7d6f1..891ee03 100644 --- a/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java +++ b/java/src/main/java/io/cucumber/junitxmlformatter/MessagesToJunitXmlWriter.java @@ -64,7 +64,7 @@ public Builder testSuiteName(String testSuiteName) { /** * Sets the value for the {@code } attribute. Defaults to the name of the - * feature file. + * feature. */ public Builder testClassName(String testClassName) { this.testClassName = testClassName; From c66b1ab1f49a7012b15cf1a9b045ae83e34bae02 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 21 Oct 2025 02:40:52 +0200 Subject: [PATCH 12/15] Js implementation --- javascript/package-lock.json | 7 ------- javascript/src/index.spec.ts | 38 +++++++++++++++++++++++++++++------- javascript/src/index.ts | 10 +++++++--- javascript/src/makeReport.ts | 19 +++++++++++++----- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/javascript/package-lock.json b/javascript/package-lock.json index eaeb2cc..cecb4ec 100644 --- a/javascript/package-lock.json +++ b/javascript/package-lock.json @@ -73,7 +73,6 @@ "version": "28.1.0", "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-28.1.0.tgz", "integrity": "sha512-2LzZtOwYKNlCuNf31ajkrekoy2M4z0Z1QGiPH40n4gf5t8VOUFb7m1ojtR4LmGvZxBGvJZP8voOmRqDWzBzYKA==", - "peer": true, "dependencies": { "@types/uuid": "10.0.0", "class-transformer": "0.5.1", @@ -630,7 +629,6 @@ "integrity": "sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -687,7 +685,6 @@ "integrity": "sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.45.0", "@typescript-eslint/types": "8.45.0", @@ -919,7 +916,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1308,7 +1304,6 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-6.0.1.tgz", "integrity": "sha512-/JOoU2//6p5vCXh00FpNgtlw0LjvhGttaWc+y7wpW9yjBm3ys0dI8tSKZxIOgNruz5J0RleccatSIC3uxEZP0g==", "dev": true, - "peer": true, "engines": { "node": ">=18" } @@ -1856,7 +1851,6 @@ "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4791,7 +4785,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/javascript/src/index.spec.ts b/javascript/src/index.spec.ts index 17cc57c..c43e569 100644 --- a/javascript/src/index.spec.ts +++ b/javascript/src/index.spec.ts @@ -5,6 +5,7 @@ import util from 'node:util' import { NdjsonToMessageStream } from '@cucumber/message-streams' import { Envelope } from '@cucumber/messages' +import { namingStrategy, NamingStrategyLength } from '@cucumber/query' import { expect, use } from 'chai' import chaiXml from 'chai-xml' import { globbySync } from 'globby' @@ -22,13 +23,33 @@ describe('Acceptance Tests', async function () { absolute: true, }) - for (const ndjsonFile of ndjsonFiles) { + const testCases = ndjsonFiles.map((ndjsonFile) => { const [suiteName] = path.basename(ndjsonFile).split('.') - it(suiteName, async () => { + return { + suiteName, + source: ndjsonFile, + strategyName: 'default', + options: {}, + } + }) + + testCases.push({ + suiteName: 'examples-tables', + source: '../testdata/src/examples-tables.ndjson', + strategyName: 'custom', + options: { + suiteName: 'Cucumber Suite', + testClassName: 'Cucumber Class', + testNamingStrategy: namingStrategy(NamingStrategyLength.LONG), + }, + }) + + for (const testCase of testCases) { + it(testCase.suiteName + ' -> ' + testCase.strategyName, async () => { let emit: (message: Envelope) => void let content = '' formatter.formatter({ - options: {}, + options: testCase.options, on(type, handler) { emit = handler }, @@ -38,7 +59,7 @@ describe('Acceptance Tests', async function () { }) await asyncPipeline( - fs.createReadStream(ndjsonFile, { encoding: 'utf-8' }), + fs.createReadStream(testCase.source, { encoding: 'utf-8' }), new NdjsonToMessageStream(), new Writable({ objectMode: true, @@ -49,9 +70,12 @@ describe('Acceptance Tests', async function () { }) ) - const expectedXml = fs.readFileSync(ndjsonFile.replace('.ndjson', '.xml'), { - encoding: 'utf-8', - }) + const expectedXml = fs.readFileSync( + testCase.source.replace('.ndjson', '.' + testCase.strategyName + '.xml'), + { + encoding: 'utf-8', + } + ) expect(content).xml.to.be.valid() expect(content).xml.to.deep.eq(expectedXml) }) diff --git a/javascript/src/index.ts b/javascript/src/index.ts index b94874d..96730b1 100644 --- a/javascript/src/index.ts +++ b/javascript/src/index.ts @@ -1,5 +1,5 @@ import { Envelope } from '@cucumber/messages' -import { Query } from '@cucumber/query' +import { NamingStrategy, Query } from '@cucumber/query' import xmlbuilder from 'xmlbuilder' import { makeReport } from './makeReport.js' @@ -11,7 +11,11 @@ export default { on, write, }: { - options: { suiteName?: string } + options: { + suiteName?: string + testClassName?: string + testNamingStrategy?: NamingStrategy + } on: (type: 'message', handler: (message: Envelope) => void) => void write: (content: string) => void }) { @@ -24,7 +28,7 @@ export default { query.update(message) if (message.testRunFinished) { - const testSuite = makeReport(query) + const testSuite = makeReport(query, options.testClassName, options.testNamingStrategy) builder.att('time', testSuite.time) builder.att('tests', testSuite.tests) builder.att('skipped', testSuite.skipped) diff --git a/javascript/src/makeReport.ts b/javascript/src/makeReport.ts index 2865ba8..ef0feeb 100644 --- a/javascript/src/makeReport.ts +++ b/javascript/src/makeReport.ts @@ -1,5 +1,6 @@ import { TestCaseStarted, TestStepResultStatus } from '@cucumber/messages' import { + NamingStrategy, namingStrategy, NamingStrategyExampleName, NamingStrategyFeatureName, @@ -40,7 +41,11 @@ interface ReportFailure { stack?: string } -export function makeReport(query: Query, customNamingStrategy: NamingStrategy = NAMING_STRATEGY): ReportSuite { +export function makeReport( + query: Query, + testClassName: string | undefined = undefined, + customNamingStrategy: NamingStrategy = NAMING_STRATEGY +): ReportSuite { const statuses = query.countMostSevereTestStepResultStatus() return { time: durationToSeconds(query.findTestRunDuration()), @@ -51,12 +56,16 @@ export function makeReport(query: Query, customNamingStrategy: NamingStrategy = (status) => status !== TestStepResultStatus.PASSED && status !== TestStepResultStatus.SKIPPED ), errors: 0, - testCases: makeTestCases(query, customNamingStrategy), + testCases: makeTestCases(query, testClassName, customNamingStrategy), timestamp: formatTimestamp(query.findTestRunStarted()), } } -function makeTestCases(query: Query, namingStrategy: NamingStrategy): ReadonlyArray { +function makeTestCases( + query: Query, + testClassName: string | undefined, + testNamingStrategy: NamingStrategy +): ReadonlyArray { return query.findAllTestCaseStarted().map((testCaseStarted) => { const pickle = ensure( query.findPickleBy(testCaseStarted), @@ -65,8 +74,8 @@ function makeTestCases(query: Query, namingStrategy: NamingStrategy): ReadonlyAr const lineage = ensure(query.findLineageBy(pickle), 'Expected to find Lineage by Pickle') return { - classname: lineage.feature?.name ?? pickle.uri, - name: NAMING_STRATEGY.reduce(lineage, pickle), + classname: testClassName ?? lineage.feature?.name ?? pickle.uri, + name: testNamingStrategy.reduce(lineage, pickle), time: durationToSeconds(query.findTestCaseDurationBy(testCaseStarted)), failure: makeFailure(query, testCaseStarted), output: query From 445117e6fafa34d704fdc98b17349005807e463b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 21 Oct 2025 02:44:55 +0200 Subject: [PATCH 13/15] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dcf81d..0cff427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Support configurable `NamingStrategy.Strategy` and `NamingStrategy.FeatureName` ([#105](https://github.com/cucumber/junit-xml-formatter/pull/105)) +- Support configurable testsuite name, testcase classname, and testcase name. ([#105](https://github.com/cucumber/junit-xml-formatter/pull/105)) ## [0.9.0] - 2025-09-11 ### Changed From 96900f6e0a843e8cd4ce4ce9a5c559c45cfb79bc Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 21 Oct 2025 02:46:09 +0200 Subject: [PATCH 14/15] npm run fix --- javascript/src/makeReport.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/src/makeReport.ts b/javascript/src/makeReport.ts index ef0feeb..1c3c796 100644 --- a/javascript/src/makeReport.ts +++ b/javascript/src/makeReport.ts @@ -42,9 +42,9 @@ interface ReportFailure { } export function makeReport( - query: Query, - testClassName: string | undefined = undefined, - customNamingStrategy: NamingStrategy = NAMING_STRATEGY + query: Query, + testClassName: string | undefined = undefined, + customNamingStrategy: NamingStrategy = NAMING_STRATEGY ): ReportSuite { const statuses = query.countMostSevereTestStepResultStatus() return { From 136182766c2a87d5bcf1cd0333eeaa106670d2d2 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 31 Oct 2025 11:10:20 +0100 Subject: [PATCH 15/15] Update samples --- testdata/src/test-run-exception.default.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 testdata/src/test-run-exception.default.xml diff --git a/testdata/src/test-run-exception.default.xml b/testdata/src/test-run-exception.default.xml new file mode 100644 index 0000000..0cd209c --- /dev/null +++ b/testdata/src/test-run-exception.default.xml @@ -0,0 +1,3 @@ + + +