From 011a3640d886c95cc5d0e3cbc1f798d93d6a9979 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 10 Jul 2025 19:42:44 +0200 Subject: [PATCH 1/6] Workaround for discovery with SBT The SBT JUpiter Interface assumes that all tests are classes[1] but does discovery on the classpath root. As a result, it turns feature names into class selectors. Which doesn't quite work. Setting `cucumber.junit-platform.discover-as-root-engine=false` should ensure Cucumber only discovers tests when called by another engine (e.g. the JUnit Platform Suite Engine) and by pass this behaviour. https://github.com/sbt/sbt-jupiter-interface/issues/142 --- .../engine/CucumberEngineDescriptor.java | 4 --- .../platform/engine/CucumberTestEngine.java | 26 +++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineDescriptor.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineDescriptor.java index 2986c670ff..c6d7765790 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineDescriptor.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineDescriptor.java @@ -16,10 +16,6 @@ class CucumberEngineDescriptor extends EngineDescriptor implements Node Date: Thu, 10 Jul 2025 19:52:13 +0200 Subject: [PATCH 2/6] Fix and format --- .../junit/platform/engine/CucumberTestEngine.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java index a2d6b8cb4c..66fee5ac82 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java @@ -54,9 +54,11 @@ public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId engineDescriptor.getUniqueId() // )); - // Early out if Cucumber is the root engine and discovery has been explicitly disabled - // Workaround for https://github.com/sbt/sbt-jupiter-interface/issues/142 - if (supportsDiscoveryAsRootEngine(configurationParameters) && isRootEngine(uniqueId)) { + // Early out if Cucumber is the root engine and discovery has been + // explicitly disabled + // Workaround for + // https://github.com/sbt/sbt-jupiter-interface/issues/142 + if (!supportsDiscoveryAsRootEngine(configurationParameters) && isRootEngine(uniqueId)) { return engineDescriptor; } From 57344a11c7a41f770ebf9d5dfd6357a51292336f Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 13 Jul 2025 00:39:46 +0200 Subject: [PATCH 3/6] WIP --- .../junit/platform/engine/Constants.java | 23 +- .../platform/engine/CucumberTestEngine.java | 6 +- .../engine/CucumberTestEngineTest.java | 449 +++++++++--------- 3 files changed, 260 insertions(+), 218 deletions(-) diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java index 1cacae44cb..55cd7fcba8 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java @@ -207,6 +207,23 @@ public final class Constants { @API(status = Status.EXPERIMENTAL, since = "7.16.2") public static final String JUNIT_PLATFORM_LONG_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME = "cucumber.junit-platform.naming-strategy.long.example-name"; + /** + * Property name used to enable discovery as a root engine: {@value} + *

+ * Valid values are {@code true}, {@code false}. Default: {@code true}. + *

+ * While the JUnit Platform supports both class and file based tests, in + * practice most build tools still assume that the children of a test engine + * have a class source. This can lead to problems when these tools decide to + * process the file based discovery results from Cucumber. + *

+ * By running Cucumber through the JUnit Platform Suit Engine and disabling + * discovery when Cucumber is a "root engine" we prevent this situation from + * occurring. + */ + @API(status = Status.EXPERIMENTAL, since = "7.26.0") + public static final String JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME = "cucumber.junit-platform.discovery.as-root-engine"; + /** * Property name to enable plugins: {@value} *

@@ -272,7 +289,7 @@ public final class Constants { *

* Valid values are {@code underscore} or {@code camelcase}. *

- * By defaults are generated using the under score naming convention. + * By defaults are generated using the underscore naming convention. */ public static final String SNIPPET_TYPE_PROPERTY_NAME = io.cucumber.core.options.Constants.SNIPPET_TYPE_PROPERTY_NAME; @@ -346,8 +363,8 @@ public final class Constants { * scenarios with the same tag. * * @see Junit - * 5 User Guide - Synchronization + * "https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution-synchronization">Junit + * 5 User Guide - Synchronization */ public static final String EXECUTION_EXCLUSIVE_RESOURCES_READ_WRITE_TEMPLATE = EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + EXECUTION_EXCLUSIVE_RESOURCES_TAG_TEMPLATE_VARIABLE + READ_WRITE_SUFFIX; diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java index 66fee5ac82..3a03a52f17 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java @@ -14,6 +14,7 @@ import org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine; import org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutorService; +import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FEATURES_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.PARALLEL_CONFIG_PREFIX; import static org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.deduplicating; @@ -55,8 +56,7 @@ public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId )); // Early out if Cucumber is the root engine and discovery has been - // explicitly disabled - // Workaround for + // explicitly disabled. Workaround for: // https://github.com/sbt/sbt-jupiter-interface/issues/142 if (!supportsDiscoveryAsRootEngine(configurationParameters) && isRootEngine(uniqueId)) { return engineDescriptor; @@ -68,7 +68,7 @@ public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId } private static boolean supportsDiscoveryAsRootEngine(ConfigurationParameters configurationParameters) { - return configurationParameters.getBoolean("cucumber.junit-platform.discover-as-root-engine") + return configurationParameters.getBoolean(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME) .orElse(true); } diff --git a/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java b/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java index abc5590131..f882b0e7de 100644 --- a/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java +++ b/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java @@ -44,6 +44,7 @@ import static io.cucumber.junit.platform.engine.Constants.FEATURES_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FILTER_NAME_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FILTER_TAGS_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_LONG_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME; @@ -93,6 +94,32 @@ class CucumberTestEngineTest { private final CucumberTestEngine engine = new CucumberTestEngine(); + static Set supportsUniqueIdSelectorFromClasspathUri() { + return discoverUniqueIds(selectPackage("io.cucumber.junit.platform.engine")); + + } + + static Set supportsUniqueIdSelectorFromFileUri() { + return discoverUniqueIds(selectDirectory("src/test/resources/io/cucumber/junit/platform/engine")); + + } + + static Set supportsUniqueIdSelectorFromJarFileUri() { + URI uri = new File("src/test/resources/feature.jar").toURI(); + return discoverUniqueIds(selectUri(uri)); + } + + private static Set discoverUniqueIds(DiscoverySelector discoverySelector) { + return EngineTestKit.engine(ENGINE_ID) + .selectors(discoverySelector) + .execute() + .allEvents() + .map(Event::getTestDescriptor) + .filter(Predicate.not(TestDescriptor::isRoot)) + .map(TestDescriptor::getUniqueId) + .collect(toSet()); + } + @Test void id() { assertEquals(ENGINE_ID, engine.getId()); @@ -129,12 +156,12 @@ void supportsClassSelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test @@ -156,8 +183,8 @@ void supportsClasspathResourceSelector() { .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:3", "A single scenario"), // - finishedSuccessfully())); + scenario("scenario:3", "A single scenario"), // + finishedSuccessfully())); } @Test @@ -169,21 +196,21 @@ void warnWhenResourceSelectorIsUsedToSelectAPackage() { DiscoveryIssue discoveryIssue = discoveryResults.getDiscoveryIssues().get(0); assertThat(discoveryIssue.message()) .isEqualTo( - "The classpath resource selector 'io/cucumber/junit/platform/engine' should not be " + - "used to select features in a package. Use the package selector with " + - "'io.cucumber.junit.platform.engine' instead"); + "The classpath resource selector 'io/cucumber/junit/platform/engine' should not be " + + "used to select features in a package. Use the package selector with " + + "'io.cucumber.junit.platform.engine' instead"); // It should also still work selectors .execute() .allEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @@ -210,12 +237,12 @@ public URI getUri() { } } Set resources = new LinkedHashSet<>(Arrays.asList( - new TestResource("io/cucumber/junit/platform/engine/single.feature", - new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), - new TestResource("io/cucumber/junit/platform/engine/single.feature", - new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), - new TestResource("io/cucumber/junit/platform/engine/single.feature", - new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")))); + new TestResource("io/cucumber/junit/platform/engine/single.feature", + new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), + new TestResource("io/cucumber/junit/platform/engine/single.feature", + new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), + new TestResource("io/cucumber/junit/platform/engine/single.feature", + new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")))); Throwable exception = EngineTestKit.engine(ENGINE_ID) // .selectors(selectClasspathResource(resources)) // @@ -228,17 +255,17 @@ public URI getUri() { assertThat(exception) // .isInstanceOf(IllegalArgumentException.class) // .hasMessage( // - "Found %s resources named %s on the classpath %s.", // - resources.size(), // - "io/cucumber/junit/platform/engine/single.feature", // - resources.stream().map(Resource::getUri).collect(toList())); + "Found %s resources named %s on the classpath %s.", // + resources.size(), // + "io/cucumber/junit/platform/engine/single.feature", // + resources.stream().map(Resource::getUri).collect(toList())); } @Test void supportsClasspathResourceSelectorWithFilePosition() { EngineTestKit.engine(ENGINE_ID) .selectors(selectClasspathResource("io/cucumber/junit/platform/engine/rule.feature", // - FilePosition.from(5))) + FilePosition.from(5))) .execute() .allEvents() .assertThatEvents() @@ -249,8 +276,8 @@ void supportsClasspathResourceSelectorWithFilePosition() { void supportsMultipleClasspathResourceSelectors() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -276,13 +303,13 @@ void supportsClasspathRootSelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature"), - feature("root.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature"), + feature("root.feature")); } @Test @@ -292,12 +319,12 @@ void supportsDirectorySelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test @@ -308,21 +335,21 @@ void supportsFileSelector() { .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:3", "A single scenario"), // - finishedSuccessfully())); + scenario("scenario:3", "A single scenario"), // + finishedSuccessfully())); } @Test void supportsFileSelectorWithFilePosition() { EngineTestKit.engine(ENGINE_ID) .selectors(selectFile("src/test/resources/io/cucumber/junit/platform/engine/rule.feature", // - FilePosition.from(5))) + FilePosition.from(5))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:5", "An example of this rule"), // - finishedSuccessfully())); + scenario("scenario:5", "An example of this rule"), // + finishedSuccessfully())); } @Test @@ -332,12 +359,12 @@ void supportsPackageSelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test @@ -349,8 +376,8 @@ void supportsUriSelector() { .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:3", "A single scenario"), // - finishedSuccessfully())); + scenario("scenario:3", "A single scenario"), // + finishedSuccessfully())); } @Test @@ -379,21 +406,6 @@ void supportsUniqueIdSelector(UniqueId selected) { .haveAtLeastOne(event(prefix(selected), finishedSuccessfully())); } - static Set supportsUniqueIdSelectorFromClasspathUri() { - return discoverUniqueIds(selectPackage("io.cucumber.junit.platform.engine")); - - } - - static Set supportsUniqueIdSelectorFromFileUri() { - return discoverUniqueIds(selectDirectory("src/test/resources/io/cucumber/junit/platform/engine")); - - } - - static Set supportsUniqueIdSelectorFromJarFileUri() { - URI uri = new File("src/test/resources/feature.jar").toURI(); - return discoverUniqueIds(selectUri(uri)); - } - @Test void supportsUniqueIdSelectorWithMultipleSelectors() { UniqueId a = EngineTestKit.engine(ENGINE_ID) @@ -428,7 +440,7 @@ void supportsUniqueIdSelectorWithMultipleSelectors() { @Test void supportsUniqueIdSelectorCachesParsedFeaturesAndPickles() { DiscoverySelector featureSelector = selectClasspathResource( - "io/cucumber/junit/platform/engine/scenario-outline.feature"); + "io/cucumber/junit/platform/engine/scenario-outline.feature"); DiscoverySelector[] uniqueIdsFromFeature = discoverUniqueIds(featureSelector) .stream() .map(DiscoverySelectors::selectUniqueId) @@ -460,23 +472,12 @@ void supportsUniqueIdSelectorCachesParsedFeaturesAndPickles() { assertEquals(pickleIdsFromFeature, pickleIdsFromPickles); } - private static Set discoverUniqueIds(DiscoverySelector discoverySelector) { - return EngineTestKit.engine(ENGINE_ID) - .selectors(discoverySelector) - .execute() - .allEvents() - .map(Event::getTestDescriptor) - .filter(Predicate.not(TestDescriptor::isRoot)) - .map(TestDescriptor::getUniqueId) - .collect(toSet()); - } - @Test void supportsFilePositionFeature() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(2))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(2))) .execute() .allEvents() .assertThatEvents() @@ -487,63 +488,63 @@ void supportsFilePositionFeature() { void supportsFilePositionScenario() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(5))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(5))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:5", "A scenario"), // - finishedSuccessfully())); + scenario("scenario:5", "A scenario"), // + finishedSuccessfully())); } @Test void supportsFilePositionScenarioOutline() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(11))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(11))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:11", "A scenario outline"), // - finishedSuccessfully())); + scenario("scenario:11", "A scenario outline"), // + finishedSuccessfully())); } @Test void supportsFilePositionExamples() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(17))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(17))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - examples("examples:17", "With some text"), // - finishedSuccessfully())); + examples("examples:17", "With some text"), // + finishedSuccessfully())); } @Test void supportsFilePositionExample() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(19))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(19))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - example("example:19", "Example #1.1"), // - finishedSuccessfully())); + example("example:19", "Example #1.1"), // + finishedSuccessfully())); } @Test void supportsFilePositionRule() { EngineTestKit.engine(ENGINE_ID) .selectors(selectClasspathResource("io/cucumber/junit/platform/engine/rule.feature", // - FilePosition.from(3))) + FilePosition.from(3))) .execute() .allEvents() .assertThatEvents() @@ -558,20 +559,20 @@ void executesFeaturesInUriOrderByDefault() { .containerEvents() .started() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature"), - feature("root.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature"), + feature("root.feature")); } @Test void supportsFeaturesProperty() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(FEATURES_PROPERTY_NAME, - "src/test/resources/io/cucumber/junit/platform/engine/single.feature") + "src/test/resources/io/cucumber/junit/platform/engine/single.feature") .execute() .allEvents() .assertThatEvents() @@ -583,14 +584,14 @@ void supportsFeaturesProperty() { void supportsFeaturesPropertyWillIgnoreOtherSelectors() { EngineDiscoveryResults discoveryResult = EngineTestKit.engine(ENGINE_ID) .configurationParameter(FEATURES_PROPERTY_NAME, - "src/test/resources/io/cucumber/junit/platform/engine/single.feature") + "src/test/resources/io/cucumber/junit/platform/engine/single.feature") .selectors(selectClasspathResource("io/cucumber/junit/platform/engine/rule.feature")) .discover(); DiscoveryIssue discoveryIssue = discoveryResult.getDiscoveryIssues().get(0); assertThat(discoveryIssue.message()) .startsWith( - "Discovering tests using the cucumber.features property. Other discovery selectors are ignored!"); + "Discovering tests using the cucumber.features property. Other discovery selectors are ignored!"); } @Test @@ -604,6 +605,30 @@ void onlySetsEngineSourceWhenFeaturesPropertyIsUsed() { .haveExactly(1, event(test(finishedSuccessfully()))); } + + @Test + void supportsDisablingDiscoveryAsRootEngine() { + EngineDiscoveryResults discover = EngineTestKit.engine(ENGINE_ID) + .configurationParameter(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME, "false") + .selectors(selectFile("src/test/resources/io/cucumber/junit/platform/engine/single.feature")) + .discover(); + + assertThat(discover.getEngineDescriptor().getChildren()).isEmpty(); + } + + + @Test + void supportsDisablingDiscoveryAsRootEngine__noRoot() { + EngineTestKit.engine(ENGINE_ID) + .configurationParameter(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME, "false") + .selectors(selectFile("src/test/resources/io/cucumber/junit/platform/engine/single.feature")) + .discover() + .allEvents() + .assertThatEvents() + .haveExactly(2, event(engine(emptySource()))) + .haveExactly(1, event(test(finishedSuccessfully()))); + } + @Test void selectAndSkipDisabledScenarioByTags() { EngineTestKit.engine(ENGINE_ID) @@ -614,7 +639,7 @@ void selectAndSkipDisabledScenarioByTags() { .assertThatEvents() .haveExactly(1, event(test())) .haveExactly(1, event(skippedWithReason( - "'cucumber.filter.tags=( @Integration and not ( @Disabled ) )' did not match this scenario"))); + "'cucumber.filter.tags=( @Integration and not ( @Disabled ) )' did not match this scenario"))); } @Test @@ -626,7 +651,7 @@ void selectAndSkipDisabledScenarioByName() { .testEvents() .assertThatEvents() .haveExactly(1, event(test(), - event(skippedWithReason("'cucumber.filter.name=^Nothing$' did not match this scenario")))); + event(skippedWithReason("'cucumber.filter.name=^Nothing$' did not match this scenario")))); } @Test @@ -638,7 +663,7 @@ void cucumberTagsAreConvertedToJunitTags() { .assertThatEvents() .haveAtLeastOne(event(feature(), tags(emptySet()))) .haveAtLeastOne( - event(scenario("scenario:5"), tags("FeatureTag", "ScenarioTag"))) + event(scenario("scenario:5"), tags("FeatureTag", "ScenarioTag"))) .haveAtLeastOne(event(scenario("scenario:11"), tags(emptySet()))) .haveAtLeastOne(event(examples("examples:17"), tags(emptySet()))) .haveAtLeastOne(event(example("example:19"), tags("FeatureTag", "ScenarioOutlineTag", "Example1Tag"))); @@ -654,13 +679,13 @@ void providesClasspathSourceWhenClasspathResourceIsSelected() { .assertThatEvents() .haveAtLeastOne(event(feature(), source(ClasspathResourceSource.from(feature, from(2, 1))))) .haveAtLeastOne( - event(scenario("scenario:5"), source(ClasspathResourceSource.from(feature, from(5, 3))))) + event(scenario("scenario:5"), source(ClasspathResourceSource.from(feature, from(5, 3))))) .haveAtLeastOne( - event(scenario("scenario:11"), source(ClasspathResourceSource.from(feature, from(11, 3))))) + event(scenario("scenario:11"), source(ClasspathResourceSource.from(feature, from(11, 3))))) .haveAtLeastOne( - event(examples("examples:17"), source(ClasspathResourceSource.from(feature, from(17, 5))))) + event(examples("examples:17"), source(ClasspathResourceSource.from(feature, from(17, 5))))) .haveAtLeastOne( - event(example("example:19"), source(ClasspathResourceSource.from(feature, from(19, 7))))); + event(example("example:19"), source(ClasspathResourceSource.from(feature, from(19, 7))))); } @Test @@ -687,19 +712,19 @@ void supportsPackageFilterForClasspathResources() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test void defaultsToShortWithNumberAndPickleIfParameterizedNamingStrategy() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -715,17 +740,17 @@ void supportsLongWithNumberNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .configurationParameter(JUNIT_PLATFORM_LONG_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "number") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() .haveAtLeastOne(event(feature(), displayName("A feature with a parameterized scenario outline"))) .haveAtLeastOne(event(scenario(), - displayName("A feature with a parameterized scenario outline - A scenario full of s"))) + displayName("A feature with a parameterized scenario outline - A scenario full of s"))) .haveAtLeastOne(event(examples(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) .haveAtLeastOne(event(example(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1"))); + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1"))); } @Test @@ -734,17 +759,17 @@ void supportsLongWithPickleNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .configurationParameter(JUNIT_PLATFORM_LONG_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "pickle") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() .haveAtLeastOne(event(feature(), displayName("A feature with a parameterized scenario outline"))) .haveAtLeastOne(event(scenario(), - displayName("A feature with a parameterized scenario outline - A scenario full of s"))) + displayName("A feature with a parameterized scenario outline - A scenario full of s"))) .haveAtLeastOne(event(examples(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) .haveAtLeastOne(event(example(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - A scenario full of Cucumbers"))); + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - A scenario full of Cucumbers"))); } @Test @@ -752,20 +777,20 @@ void supportsLongWithNumberAndPickleIfParameterizedNamingStrategy() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, - "number-and-pickle-if-parameterized") + "number-and-pickle-if-parameterized") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() .haveAtLeastOne(event(feature(), displayName("A feature with a parameterized scenario outline"))) .haveAtLeastOne(event(scenario(), - displayName("A feature with a parameterized scenario outline - A scenario full of s"))) + displayName("A feature with a parameterized scenario outline - A scenario full of s"))) .haveAtLeastOne(event(examples(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) .haveAtLeastOne(event(example(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1: A scenario full of Cucumbers"))); + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1: A scenario full of Cucumbers"))); } @Test @@ -774,7 +799,7 @@ void supportsShortWithPickleNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "short") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "pickle") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -790,7 +815,7 @@ void supportsShortWithNumberNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "short") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "number") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -805,9 +830,9 @@ void supportsShortWithNumberAndPickleIfParameterizedNamingStrategy() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "short") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, - "number-and-pickle-if-parameterized") + "number-and-pickle-if-parameterized") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -822,8 +847,8 @@ void defaultsToLexicalOrder() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) .execute() .allEvents() .started() @@ -831,23 +856,23 @@ void defaultsToLexicalOrder() { .extracting(Event::getTestDescriptor) .extracting(TestDescriptor::getDisplayName) .containsExactly("Cucumber", - "1. A feature to order scenarios", - "1. A feature to order scenarios - 1.1", - "1. A feature to order scenarios - 1.2", - "1. A feature to order scenarios - 1.2 - 1.2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", - "1. A feature to order scenarios - 1.2 - 1.2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", - "1. A feature to order scenarios - 1.3 A rule", - "1. A feature to order scenarios - 1.3 A rule - 1.3.1", - "1. A feature to order scenarios - 1.3 A rule - 1.3.2", - "1. A feature to order scenarios - 1.4", - "1. A feature to order scenarios - 1.4 - 1.4.1", - "1. A feature to order scenarios - 1.4 - 1.4.2", - "A feature with a single scenario", - "A feature with a single scenario - A single scenario"); + "1. A feature to order scenarios", + "1. A feature to order scenarios - 1.1", + "1. A feature to order scenarios - 1.2", + "1. A feature to order scenarios - 1.2 - 1.2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", + "1. A feature to order scenarios - 1.2 - 1.2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", + "1. A feature to order scenarios - 1.3 A rule", + "1. A feature to order scenarios - 1.3 A rule - 1.3.1", + "1. A feature to order scenarios - 1.3 A rule - 1.3.2", + "1. A feature to order scenarios - 1.4", + "1. A feature to order scenarios - 1.4 - 1.4.1", + "1. A feature to order scenarios - 1.4 - 1.4.2", + "A feature with a single scenario", + "A feature with a single scenario - A single scenario"); } @Test @@ -856,8 +881,8 @@ void supportsReverseOrder() { .configurationParameter(EXECUTION_ORDER_PROPERTY_NAME, "reverse") .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) .execute() .allEvents() .started() @@ -865,23 +890,23 @@ void supportsReverseOrder() { .extracting(Event::getTestDescriptor) .extracting(TestDescriptor::getDisplayName) .containsExactly("Cucumber", - "A feature with a single scenario", - "A feature with a single scenario - A single scenario", - "1. A feature to order scenarios", - "1. A feature to order scenarios - 1.4", - "1. A feature to order scenarios - 1.4 - 1.4.2", - "1. A feature to order scenarios - 1.4 - 1.4.1", - "1. A feature to order scenarios - 1.3 A rule", - "1. A feature to order scenarios - 1.3 A rule - 1.3.2", - "1. A feature to order scenarios - 1.3 A rule - 1.3.1", - "1. A feature to order scenarios - 1.2", - "1. A feature to order scenarios - 1.2 - 1.2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", - "1. A feature to order scenarios - 1.1"); + "A feature with a single scenario", + "A feature with a single scenario - A single scenario", + "1. A feature to order scenarios", + "1. A feature to order scenarios - 1.4", + "1. A feature to order scenarios - 1.4 - 1.4.2", + "1. A feature to order scenarios - 1.4 - 1.4.1", + "1. A feature to order scenarios - 1.3 A rule", + "1. A feature to order scenarios - 1.3 A rule - 1.3.2", + "1. A feature to order scenarios - 1.3 A rule - 1.3.1", + "1. A feature to order scenarios - 1.2", + "1. A feature to order scenarios - 1.2 - 1.2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", + "1. A feature to order scenarios - 1.1"); } @Test @@ -898,10 +923,10 @@ void supportsRandomOrder(LogRecordListener logRecordListener) { .orElseThrow(); assertAll( - () -> assertThat(message.getLevel()).isEqualTo(Level.CONFIG), - () -> assertThat(message.getMessage()) - .matches( - "Using generated seed for configuration parameter 'cucumber\\.execution\\.order\\.random\\.seed' with value '\\d+'.")); + () -> assertThat(message.getLevel()).isEqualTo(Level.CONFIG), + () -> assertThat(message.getMessage()) + .matches( + "Using generated seed for configuration parameter 'cucumber\\.execution\\.order\\.random\\.seed' with value '\\d+'.")); } @Test @@ -911,8 +936,8 @@ void supportsRandomOrderWithSeed() { .configurationParameter(EXECUTION_ORDER_RANDOM_SEED_PROPERTY_NAME, "1234") .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) .execute() .allEvents() .started() @@ -920,30 +945,30 @@ void supportsRandomOrderWithSeed() { .extracting(Event::getTestDescriptor) .extracting(TestDescriptor::getDisplayName) .containsExactly("Cucumber", - "1. A feature to order scenarios", - "1. A feature to order scenarios - 1.4", - "1. A feature to order scenarios - 1.4 - 1.4.1", - "1. A feature to order scenarios - 1.4 - 1.4.2", - "1. A feature to order scenarios - 1.1", - "1. A feature to order scenarios - 1.3 A rule", - "1. A feature to order scenarios - 1.3 A rule - 1.3.2", - "1. A feature to order scenarios - 1.3 A rule - 1.3.1", - "1. A feature to order scenarios - 1.2", - "1. A feature to order scenarios - 1.2 - 1.2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", - "1. A feature to order scenarios - 1.2 - 1.2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", - "A feature with a single scenario", - "A feature with a single scenario - A single scenario"); + "1. A feature to order scenarios", + "1. A feature to order scenarios - 1.4", + "1. A feature to order scenarios - 1.4 - 1.4.1", + "1. A feature to order scenarios - 1.4 - 1.4.2", + "1. A feature to order scenarios - 1.1", + "1. A feature to order scenarios - 1.3 A rule", + "1. A feature to order scenarios - 1.3 A rule - 1.3.2", + "1. A feature to order scenarios - 1.3 A rule - 1.3.1", + "1. A feature to order scenarios - 1.2", + "1. A feature to order scenarios - 1.2 - 1.2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", + "1. A feature to order scenarios - 1.2 - 1.2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", + "A feature with a single scenario", + "A feature with a single scenario - A single scenario"); } @Test void reportsParsErrorsAsDiscoveryIssues() { EngineDiscoveryResults results = EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/bad-features/parse-error.feature")) + selectFile("src/test/bad-features/parse-error.feature")) .discover(); DiscoveryIssue issue = results.getDiscoveryIssues().get(0); @@ -959,11 +984,11 @@ void reportsParsErrorsAsDiscoveryIssues() { void supportsExclusiveResources() { PickleDescriptor pickleDescriptor = EngineTestKit.engine(ENGINE_ID) .configurationParameter(EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + "ResourceA" + READ_WRITE_SUFFIX, - "resource-a") + "resource-a") .configurationParameter(EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + "ResourceAReadOnly" + READ_SUFFIX, - "resource-a") + "resource-a") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/resource.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/resource.feature")) .discover() .getEngineDescriptor() .getDescendants() @@ -975,8 +1000,8 @@ void supportsExclusiveResources() { assertThat(pickleDescriptor.getExclusiveResources()) .containsExactlyInAnyOrder( - new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ_WRITE), - new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ)); + new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ_WRITE), + new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ)); } @@ -985,7 +1010,7 @@ void supportsConcurrentExecutionOfFeatureElements() { Set> testDescriptors = EngineTestKit.engine(ENGINE_ID) .configurationParameter(EXECUTION_MODE_FEATURE_PROPERTY_NAME, "concurrent") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) .discover() .getEngineDescriptor() .getDescendants() @@ -1005,7 +1030,7 @@ void supportsSameThreadExecutionOfFeatureElements() { Set testDescriptors = EngineTestKit.engine(ENGINE_ID) .configurationParameter(EXECUTION_MODE_FEATURE_PROPERTY_NAME, "same_thread") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) .discover() .getEngineDescriptor() .getDescendants(); From 094ec59ba0952c946b958d0a1f32e5c197a1e0d7 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 13 Jul 2025 14:25:03 +0200 Subject: [PATCH 4/6] Update docs and tests --- cucumber-junit-platform-engine/README.md | 19 ++++- cucumber-junit-platform-engine/pom.xml | 6 +- .../junit/platform/engine/Constants.java | 19 +++-- .../engine/CucumberTestEngineTest.java | 74 +++++++++++-------- 4 files changed, 75 insertions(+), 43 deletions(-) diff --git a/cucumber-junit-platform-engine/README.md b/cucumber-junit-platform-engine/README.md index ab130fcd46..dc7f2f335f 100644 --- a/cucumber-junit-platform-engine/README.md +++ b/cucumber-junit-platform-engine/README.md @@ -37,12 +37,12 @@ erDiagram In practice, integration is still limited so we discuss the most common workarounds below. -### Maven Surefire and Gradle +### Maven Surefire, Gradle and SBT Maven Surefire and Gradle do not yet support discovery of non-class based tests (see: [gradle/#4773](https://github.com/gradle/gradle/issues/4773), -[SUREFIRE-1724](https://issues.apache.org/jira/browse/SUREFIRE-1724)). As a - workaround, you can either use: +[maven-surefire/#2065](https://github.com/apache/maven-surefire/issues/2065), [stb-jupiter-interface/#142](https://github.com/sbt/sbt-jupiter-interface/issues/142)). +As a workaround, you can either use: * the [JUnit Platform Suite Engine](https://junit.org/junit5/docs/current/user-guide/#junit-platform-suite-engine); * the [JUnit Platform Console Launcher](https://junit.org/junit5/docs/current/user-guide/#running-tests-console-launcher) or; * the [Gradle Cucumber-Companion](https://github.com/gradle/cucumber-companion) plugins for Gradle and Maven. @@ -104,6 +104,19 @@ public class RunCucumberTest { } ``` +##### SBT workarounds + +The `sbt-jupiter-interface` assumes that all tests directly under a test engine +have a class source. This is not the case for Cucumber. By running Cucumber +indirectly through the JUnit Platform Suite Engine and disabling discovery when +run directly as a "root engine" this problem is avoided. + +Add to `junit-platform.properties`: + +``` +cucumber.junit-platform.discovery.as-root-engine=false +``` + #### Use the JUnit Console Launcher ### You can integrate the JUnit Platform Console Launcher in your build by using diff --git a/cucumber-junit-platform-engine/pom.xml b/cucumber-junit-platform-engine/pom.xml index 808e7b5caf..496423c48b 100644 --- a/cucumber-junit-platform-engine/pom.xml +++ b/cucumber-junit-platform-engine/pom.xml @@ -62,12 +62,12 @@ org.junit.jupiter - junit-jupiter-api + junit-jupiter-params test - org.junit.jupiter - junit-jupiter-params + org.junit.platform + junit-platform-suite test diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java index 55cd7fcba8..a808a3e764 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java @@ -212,14 +212,17 @@ public final class Constants { *

* Valid values are {@code true}, {@code false}. Default: {@code true}. *

- * While the JUnit Platform supports both class and file based tests, in - * practice most build tools still assume that the children of a test engine - * have a class source. This can lead to problems when these tools decide to - * process the file based discovery results from Cucumber. - *

- * By running Cucumber through the JUnit Platform Suit Engine and disabling - * discovery when Cucumber is a "root engine" we prevent this situation from - * occurring. + * As an engine on the JUnit Platform, Cucumber can participate in discovery + * directly as a "root" engine. Or indirectly when used through the JUnit + * Platform Suite Engine. + *

+ * Some build tools assume that all root engines produce class based tests. + * This is not the case for Cucumber. Running Cucumber through the JUnit + * Platform Suite Engine. Disabling discovery as a root engine + * resolves this. + *

+ * Note: If a build tool supports JUnits include/exclude Engine + * configuration that option should be preferred over this property. */ @API(status = Status.EXPERIMENTAL, since = "7.26.0") public static final String JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME = "cucumber.junit-platform.discovery.as-root-engine"; diff --git a/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java b/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java index f882b0e7de..97fc3a0def 100644 --- a/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java +++ b/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java @@ -20,6 +20,9 @@ import org.junit.platform.engine.support.descriptor.FileSource; import org.junit.platform.engine.support.hierarchical.ExclusiveResource; import org.junit.platform.engine.support.hierarchical.Node; +import org.junit.platform.suite.api.IncludeEngines; +import org.junit.platform.suite.api.SelectClasspathResource; +import org.junit.platform.suite.api.Suite; import org.junit.platform.testkit.engine.EngineDiscoveryResults; import org.junit.platform.testkit.engine.EngineTestKit; import org.junit.platform.testkit.engine.Event; @@ -94,21 +97,6 @@ class CucumberTestEngineTest { private final CucumberTestEngine engine = new CucumberTestEngine(); - static Set supportsUniqueIdSelectorFromClasspathUri() { - return discoverUniqueIds(selectPackage("io.cucumber.junit.platform.engine")); - - } - - static Set supportsUniqueIdSelectorFromFileUri() { - return discoverUniqueIds(selectDirectory("src/test/resources/io/cucumber/junit/platform/engine")); - - } - - static Set supportsUniqueIdSelectorFromJarFileUri() { - URI uri = new File("src/test/resources/feature.jar").toURI(); - return discoverUniqueIds(selectUri(uri)); - } - private static Set discoverUniqueIds(DiscoverySelector discoverySelector) { return EngineTestKit.engine(ENGINE_ID) .selectors(discoverySelector) @@ -406,6 +394,22 @@ void supportsUniqueIdSelector(UniqueId selected) { .haveAtLeastOne(event(prefix(selected), finishedSuccessfully())); } + + static Set supportsUniqueIdSelectorFromClasspathUri() { + return discoverUniqueIds(selectPackage("io.cucumber.junit.platform.engine")); + + } + + static Set supportsUniqueIdSelectorFromFileUri() { + return discoverUniqueIds(selectDirectory("src/test/resources/io/cucumber/junit/platform/engine")); + + } + + static Set supportsUniqueIdSelectorFromJarFileUri() { + URI uri = new File("src/test/resources/feature.jar").toURI(); + return discoverUniqueIds(selectUri(uri)); + } + @Test void supportsUniqueIdSelectorWithMultipleSelectors() { UniqueId a = EngineTestKit.engine(ENGINE_ID) @@ -605,28 +609,40 @@ void onlySetsEngineSourceWhenFeaturesPropertyIsUsed() { .haveExactly(1, event(test(finishedSuccessfully()))); } + @Suite + @IncludeEngines("cucumber") + @SelectClasspathResource("io/cucumber/junit/platform/engine/single.feature") + static class SuiteTestCase { + } + @Test void supportsDisablingDiscoveryAsRootEngine() { - EngineDiscoveryResults discover = EngineTestKit.engine(ENGINE_ID) - .configurationParameter(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME, "false") - .selectors(selectFile("src/test/resources/io/cucumber/junit/platform/engine/single.feature")) - .discover(); + DiscoverySelector selector = selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"); - assertThat(discover.getEngineDescriptor().getChildren()).isEmpty(); - } + // Ensure classpath resource exists. + assertThat(EngineTestKit.engine(ENGINE_ID) + .selectors(selector) + .discover() + .getEngineDescriptor() + .getChildren()) + .isNotEmpty(); + assertThat(EngineTestKit.engine(ENGINE_ID) + .configurationParameter(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME, "false") + .selectors(selector) + .discover() + .getEngineDescriptor() + .getChildren()) + .isEmpty(); - @Test - void supportsDisablingDiscoveryAsRootEngine__noRoot() { - EngineTestKit.engine(ENGINE_ID) + assertThat(EngineTestKit.engine("junit-platform-suite") .configurationParameter(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME, "false") - .selectors(selectFile("src/test/resources/io/cucumber/junit/platform/engine/single.feature")) + .selectors(selectClass(SuiteTestCase.class)) .discover() - .allEvents() - .assertThatEvents() - .haveExactly(2, event(engine(emptySource()))) - .haveExactly(1, event(test(finishedSuccessfully()))); + .getEngineDescriptor() + .getChildren()) + .isNotEmpty(); } @Test From c1449d96b3eaa2fea36bb9d532eaa4baef950a8c Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 13 Jul 2025 14:31:25 +0200 Subject: [PATCH 5/6] Spotless --- .../junit/platform/engine/Constants.java | 12 +- .../platform/engine/CucumberTestEngine.java | 2 +- .../engine/CucumberTestEngineTest.java | 375 +++++++++--------- 3 files changed, 194 insertions(+), 195 deletions(-) diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java index a808a3e764..2c28d50fec 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java @@ -214,12 +214,12 @@ public final class Constants { *

* As an engine on the JUnit Platform, Cucumber can participate in discovery * directly as a "root" engine. Or indirectly when used through the JUnit - * Platform Suite Engine. + * Platform Suite Engine. *

- * Some build tools assume that all root engines produce class based tests. + * Some build tools assume that all root engines produce class based tests. * This is not the case for Cucumber. Running Cucumber through the JUnit - * Platform Suite Engine. Disabling discovery as a root engine - * resolves this. + * Platform Suite Engine. Disabling discovery as a root engine resolves + * this. *

* Note: If a build tool supports JUnits include/exclude Engine * configuration that option should be preferred over this property. @@ -366,8 +366,8 @@ public final class Constants { * scenarios with the same tag. * * @see Junit - * 5 User Guide - Synchronization + * "https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution-synchronization">Junit + * 5 User Guide - Synchronization */ public static final String EXECUTION_EXCLUSIVE_RESOURCES_READ_WRITE_TEMPLATE = EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + EXECUTION_EXCLUSIVE_RESOURCES_TAG_TEMPLATE_VARIABLE + READ_WRITE_SUFFIX; diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java index 3a03a52f17..e362c1eb1d 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberTestEngine.java @@ -14,8 +14,8 @@ import org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine; import org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutorService; -import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FEATURES_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.PARALLEL_CONFIG_PREFIX; import static org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.deduplicating; import static org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.forwarding; diff --git a/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java b/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java index 97fc3a0def..ff7c107b9c 100644 --- a/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java +++ b/cucumber-junit-platform-engine/src/test/java/io/cucumber/junit/platform/engine/CucumberTestEngineTest.java @@ -144,12 +144,12 @@ void supportsClassSelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test @@ -171,8 +171,8 @@ void supportsClasspathResourceSelector() { .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:3", "A single scenario"), // - finishedSuccessfully())); + scenario("scenario:3", "A single scenario"), // + finishedSuccessfully())); } @Test @@ -184,21 +184,21 @@ void warnWhenResourceSelectorIsUsedToSelectAPackage() { DiscoveryIssue discoveryIssue = discoveryResults.getDiscoveryIssues().get(0); assertThat(discoveryIssue.message()) .isEqualTo( - "The classpath resource selector 'io/cucumber/junit/platform/engine' should not be " + - "used to select features in a package. Use the package selector with " + - "'io.cucumber.junit.platform.engine' instead"); + "The classpath resource selector 'io/cucumber/junit/platform/engine' should not be " + + "used to select features in a package. Use the package selector with " + + "'io.cucumber.junit.platform.engine' instead"); // It should also still work selectors .execute() .allEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @@ -225,12 +225,12 @@ public URI getUri() { } } Set resources = new LinkedHashSet<>(Arrays.asList( - new TestResource("io/cucumber/junit/platform/engine/single.feature", - new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), - new TestResource("io/cucumber/junit/platform/engine/single.feature", - new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), - new TestResource("io/cucumber/junit/platform/engine/single.feature", - new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")))); + new TestResource("io/cucumber/junit/platform/engine/single.feature", + new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), + new TestResource("io/cucumber/junit/platform/engine/single.feature", + new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")), + new TestResource("io/cucumber/junit/platform/engine/single.feature", + new File("src/test/resources/io/cucumber/junit/platform/engine/single.feature")))); Throwable exception = EngineTestKit.engine(ENGINE_ID) // .selectors(selectClasspathResource(resources)) // @@ -243,17 +243,17 @@ public URI getUri() { assertThat(exception) // .isInstanceOf(IllegalArgumentException.class) // .hasMessage( // - "Found %s resources named %s on the classpath %s.", // - resources.size(), // - "io/cucumber/junit/platform/engine/single.feature", // - resources.stream().map(Resource::getUri).collect(toList())); + "Found %s resources named %s on the classpath %s.", // + resources.size(), // + "io/cucumber/junit/platform/engine/single.feature", // + resources.stream().map(Resource::getUri).collect(toList())); } @Test void supportsClasspathResourceSelectorWithFilePosition() { EngineTestKit.engine(ENGINE_ID) .selectors(selectClasspathResource("io/cucumber/junit/platform/engine/rule.feature", // - FilePosition.from(5))) + FilePosition.from(5))) .execute() .allEvents() .assertThatEvents() @@ -264,8 +264,8 @@ void supportsClasspathResourceSelectorWithFilePosition() { void supportsMultipleClasspathResourceSelectors() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -291,13 +291,13 @@ void supportsClasspathRootSelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature"), - feature("root.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature"), + feature("root.feature")); } @Test @@ -307,12 +307,12 @@ void supportsDirectorySelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test @@ -323,21 +323,21 @@ void supportsFileSelector() { .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:3", "A single scenario"), // - finishedSuccessfully())); + scenario("scenario:3", "A single scenario"), // + finishedSuccessfully())); } @Test void supportsFileSelectorWithFilePosition() { EngineTestKit.engine(ENGINE_ID) .selectors(selectFile("src/test/resources/io/cucumber/junit/platform/engine/rule.feature", // - FilePosition.from(5))) + FilePosition.from(5))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:5", "An example of this rule"), // - finishedSuccessfully())); + scenario("scenario:5", "An example of this rule"), // + finishedSuccessfully())); } @Test @@ -347,12 +347,12 @@ void supportsPackageSelector() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test @@ -364,8 +364,8 @@ void supportsUriSelector() { .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:3", "A single scenario"), // - finishedSuccessfully())); + scenario("scenario:3", "A single scenario"), // + finishedSuccessfully())); } @Test @@ -394,7 +394,6 @@ void supportsUniqueIdSelector(UniqueId selected) { .haveAtLeastOne(event(prefix(selected), finishedSuccessfully())); } - static Set supportsUniqueIdSelectorFromClasspathUri() { return discoverUniqueIds(selectPackage("io.cucumber.junit.platform.engine")); @@ -444,7 +443,7 @@ void supportsUniqueIdSelectorWithMultipleSelectors() { @Test void supportsUniqueIdSelectorCachesParsedFeaturesAndPickles() { DiscoverySelector featureSelector = selectClasspathResource( - "io/cucumber/junit/platform/engine/scenario-outline.feature"); + "io/cucumber/junit/platform/engine/scenario-outline.feature"); DiscoverySelector[] uniqueIdsFromFeature = discoverUniqueIds(featureSelector) .stream() .map(DiscoverySelectors::selectUniqueId) @@ -480,8 +479,8 @@ void supportsUniqueIdSelectorCachesParsedFeaturesAndPickles() { void supportsFilePositionFeature() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(2))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(2))) .execute() .allEvents() .assertThatEvents() @@ -492,63 +491,63 @@ void supportsFilePositionFeature() { void supportsFilePositionScenario() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(5))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(5))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:5", "A scenario"), // - finishedSuccessfully())); + scenario("scenario:5", "A scenario"), // + finishedSuccessfully())); } @Test void supportsFilePositionScenarioOutline() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(11))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(11))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - scenario("scenario:11", "A scenario outline"), // - finishedSuccessfully())); + scenario("scenario:11", "A scenario outline"), // + finishedSuccessfully())); } @Test void supportsFilePositionExamples() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(17))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(17))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - examples("examples:17", "With some text"), // - finishedSuccessfully())); + examples("examples:17", "With some text"), // + finishedSuccessfully())); } @Test void supportsFilePositionExample() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // - FilePosition.from(19))) + selectFile("src/test/resources/io/cucumber/junit/platform/engine/scenario-outline.feature", // + FilePosition.from(19))) .execute() .allEvents() .assertThatEvents() .haveExactly(1, event( // - example("example:19", "Example #1.1"), // - finishedSuccessfully())); + example("example:19", "Example #1.1"), // + finishedSuccessfully())); } @Test void supportsFilePositionRule() { EngineTestKit.engine(ENGINE_ID) .selectors(selectClasspathResource("io/cucumber/junit/platform/engine/rule.feature", // - FilePosition.from(3))) + FilePosition.from(3))) .execute() .allEvents() .assertThatEvents() @@ -563,20 +562,20 @@ void executesFeaturesInUriOrderByDefault() { .containerEvents() .started() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature"), - feature("root.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature"), + feature("root.feature")); } @Test void supportsFeaturesProperty() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(FEATURES_PROPERTY_NAME, - "src/test/resources/io/cucumber/junit/platform/engine/single.feature") + "src/test/resources/io/cucumber/junit/platform/engine/single.feature") .execute() .allEvents() .assertThatEvents() @@ -588,14 +587,14 @@ void supportsFeaturesProperty() { void supportsFeaturesPropertyWillIgnoreOtherSelectors() { EngineDiscoveryResults discoveryResult = EngineTestKit.engine(ENGINE_ID) .configurationParameter(FEATURES_PROPERTY_NAME, - "src/test/resources/io/cucumber/junit/platform/engine/single.feature") + "src/test/resources/io/cucumber/junit/platform/engine/single.feature") .selectors(selectClasspathResource("io/cucumber/junit/platform/engine/rule.feature")) .discover(); DiscoveryIssue discoveryIssue = discoveryResult.getDiscoveryIssues().get(0); assertThat(discoveryIssue.message()) .startsWith( - "Discovering tests using the cucumber.features property. Other discovery selectors are ignored!"); + "Discovering tests using the cucumber.features property. Other discovery selectors are ignored!"); } @Test @@ -615,7 +614,7 @@ void onlySetsEngineSourceWhenFeaturesPropertyIsUsed() { static class SuiteTestCase { } - + @Test void supportsDisablingDiscoveryAsRootEngine() { DiscoverySelector selector = selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"); @@ -655,7 +654,7 @@ void selectAndSkipDisabledScenarioByTags() { .assertThatEvents() .haveExactly(1, event(test())) .haveExactly(1, event(skippedWithReason( - "'cucumber.filter.tags=( @Integration and not ( @Disabled ) )' did not match this scenario"))); + "'cucumber.filter.tags=( @Integration and not ( @Disabled ) )' did not match this scenario"))); } @Test @@ -667,7 +666,7 @@ void selectAndSkipDisabledScenarioByName() { .testEvents() .assertThatEvents() .haveExactly(1, event(test(), - event(skippedWithReason("'cucumber.filter.name=^Nothing$' did not match this scenario")))); + event(skippedWithReason("'cucumber.filter.name=^Nothing$' did not match this scenario")))); } @Test @@ -679,7 +678,7 @@ void cucumberTagsAreConvertedToJunitTags() { .assertThatEvents() .haveAtLeastOne(event(feature(), tags(emptySet()))) .haveAtLeastOne( - event(scenario("scenario:5"), tags("FeatureTag", "ScenarioTag"))) + event(scenario("scenario:5"), tags("FeatureTag", "ScenarioTag"))) .haveAtLeastOne(event(scenario("scenario:11"), tags(emptySet()))) .haveAtLeastOne(event(examples("examples:17"), tags(emptySet()))) .haveAtLeastOne(event(example("example:19"), tags("FeatureTag", "ScenarioOutlineTag", "Example1Tag"))); @@ -695,13 +694,13 @@ void providesClasspathSourceWhenClasspathResourceIsSelected() { .assertThatEvents() .haveAtLeastOne(event(feature(), source(ClasspathResourceSource.from(feature, from(2, 1))))) .haveAtLeastOne( - event(scenario("scenario:5"), source(ClasspathResourceSource.from(feature, from(5, 3))))) + event(scenario("scenario:5"), source(ClasspathResourceSource.from(feature, from(5, 3))))) .haveAtLeastOne( - event(scenario("scenario:11"), source(ClasspathResourceSource.from(feature, from(11, 3))))) + event(scenario("scenario:11"), source(ClasspathResourceSource.from(feature, from(11, 3))))) .haveAtLeastOne( - event(examples("examples:17"), source(ClasspathResourceSource.from(feature, from(17, 5))))) + event(examples("examples:17"), source(ClasspathResourceSource.from(feature, from(17, 5))))) .haveAtLeastOne( - event(example("example:19"), source(ClasspathResourceSource.from(feature, from(19, 7))))); + event(example("example:19"), source(ClasspathResourceSource.from(feature, from(19, 7))))); } @Test @@ -728,19 +727,19 @@ void supportsPackageFilterForClasspathResources() { .execute() .containerEvents() .assertEventsMatchLooselyInOrder( - feature("disabled.feature"), - feature("empty-scenario.feature"), - feature("scenario-outline.feature"), - feature("rule.feature"), - feature("single.feature"), - feature("with%20space.feature")); + feature("disabled.feature"), + feature("empty-scenario.feature"), + feature("scenario-outline.feature"), + feature("rule.feature"), + feature("single.feature"), + feature("with%20space.feature")); } @Test void defaultsToShortWithNumberAndPickleIfParameterizedNamingStrategy() { EngineTestKit.engine(ENGINE_ID) .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -756,17 +755,17 @@ void supportsLongWithNumberNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .configurationParameter(JUNIT_PLATFORM_LONG_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "number") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() .haveAtLeastOne(event(feature(), displayName("A feature with a parameterized scenario outline"))) .haveAtLeastOne(event(scenario(), - displayName("A feature with a parameterized scenario outline - A scenario full of s"))) + displayName("A feature with a parameterized scenario outline - A scenario full of s"))) .haveAtLeastOne(event(examples(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) .haveAtLeastOne(event(example(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1"))); + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1"))); } @Test @@ -775,17 +774,17 @@ void supportsLongWithPickleNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .configurationParameter(JUNIT_PLATFORM_LONG_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "pickle") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() .haveAtLeastOne(event(feature(), displayName("A feature with a parameterized scenario outline"))) .haveAtLeastOne(event(scenario(), - displayName("A feature with a parameterized scenario outline - A scenario full of s"))) + displayName("A feature with a parameterized scenario outline - A scenario full of s"))) .haveAtLeastOne(event(examples(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) .haveAtLeastOne(event(example(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - A scenario full of Cucumbers"))); + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - A scenario full of Cucumbers"))); } @Test @@ -793,20 +792,20 @@ void supportsLongWithNumberAndPickleIfParameterizedNamingStrategy() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, - "number-and-pickle-if-parameterized") + "number-and-pickle-if-parameterized") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() .haveAtLeastOne(event(feature(), displayName("A feature with a parameterized scenario outline"))) .haveAtLeastOne(event(scenario(), - displayName("A feature with a parameterized scenario outline - A scenario full of s"))) + displayName("A feature with a parameterized scenario outline - A scenario full of s"))) .haveAtLeastOne(event(examples(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety"))) .haveAtLeastOne(event(example(), displayName( - "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1: A scenario full of Cucumbers"))); + "A feature with a parameterized scenario outline - A scenario full of s - Of the Gherkin variety - Example #1.1: A scenario full of Cucumbers"))); } @Test @@ -815,7 +814,7 @@ void supportsShortWithPickleNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "short") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "pickle") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -831,7 +830,7 @@ void supportsShortWithNumberNamingStrategy() { .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "short") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, "number") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -846,9 +845,9 @@ void supportsShortWithNumberAndPickleIfParameterizedNamingStrategy() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "short") .configurationParameter(JUNIT_PLATFORM_SHORT_NAMING_STRATEGY_EXAMPLE_NAME_PROPERTY_NAME, - "number-and-pickle-if-parameterized") + "number-and-pickle-if-parameterized") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/parameterized-scenario-outline.feature")) .execute() .allEvents() .assertThatEvents() @@ -863,8 +862,8 @@ void defaultsToLexicalOrder() { EngineTestKit.engine(ENGINE_ID) .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) .execute() .allEvents() .started() @@ -872,23 +871,23 @@ void defaultsToLexicalOrder() { .extracting(Event::getTestDescriptor) .extracting(TestDescriptor::getDisplayName) .containsExactly("Cucumber", - "1. A feature to order scenarios", - "1. A feature to order scenarios - 1.1", - "1. A feature to order scenarios - 1.2", - "1. A feature to order scenarios - 1.2 - 1.2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", - "1. A feature to order scenarios - 1.2 - 1.2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", - "1. A feature to order scenarios - 1.3 A rule", - "1. A feature to order scenarios - 1.3 A rule - 1.3.1", - "1. A feature to order scenarios - 1.3 A rule - 1.3.2", - "1. A feature to order scenarios - 1.4", - "1. A feature to order scenarios - 1.4 - 1.4.1", - "1. A feature to order scenarios - 1.4 - 1.4.2", - "A feature with a single scenario", - "A feature with a single scenario - A single scenario"); + "1. A feature to order scenarios", + "1. A feature to order scenarios - 1.1", + "1. A feature to order scenarios - 1.2", + "1. A feature to order scenarios - 1.2 - 1.2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", + "1. A feature to order scenarios - 1.2 - 1.2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", + "1. A feature to order scenarios - 1.3 A rule", + "1. A feature to order scenarios - 1.3 A rule - 1.3.1", + "1. A feature to order scenarios - 1.3 A rule - 1.3.2", + "1. A feature to order scenarios - 1.4", + "1. A feature to order scenarios - 1.4 - 1.4.1", + "1. A feature to order scenarios - 1.4 - 1.4.2", + "A feature with a single scenario", + "A feature with a single scenario - A single scenario"); } @Test @@ -897,8 +896,8 @@ void supportsReverseOrder() { .configurationParameter(EXECUTION_ORDER_PROPERTY_NAME, "reverse") .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) .execute() .allEvents() .started() @@ -906,23 +905,23 @@ void supportsReverseOrder() { .extracting(Event::getTestDescriptor) .extracting(TestDescriptor::getDisplayName) .containsExactly("Cucumber", - "A feature with a single scenario", - "A feature with a single scenario - A single scenario", - "1. A feature to order scenarios", - "1. A feature to order scenarios - 1.4", - "1. A feature to order scenarios - 1.4 - 1.4.2", - "1. A feature to order scenarios - 1.4 - 1.4.1", - "1. A feature to order scenarios - 1.3 A rule", - "1. A feature to order scenarios - 1.3 A rule - 1.3.2", - "1. A feature to order scenarios - 1.3 A rule - 1.3.1", - "1. A feature to order scenarios - 1.2", - "1. A feature to order scenarios - 1.2 - 1.2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", - "1. A feature to order scenarios - 1.1"); + "A feature with a single scenario", + "A feature with a single scenario - A single scenario", + "1. A feature to order scenarios", + "1. A feature to order scenarios - 1.4", + "1. A feature to order scenarios - 1.4 - 1.4.2", + "1. A feature to order scenarios - 1.4 - 1.4.1", + "1. A feature to order scenarios - 1.3 A rule", + "1. A feature to order scenarios - 1.3 A rule - 1.3.2", + "1. A feature to order scenarios - 1.3 A rule - 1.3.1", + "1. A feature to order scenarios - 1.2", + "1. A feature to order scenarios - 1.2 - 1.2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", + "1. A feature to order scenarios - 1.1"); } @Test @@ -939,10 +938,10 @@ void supportsRandomOrder(LogRecordListener logRecordListener) { .orElseThrow(); assertAll( - () -> assertThat(message.getLevel()).isEqualTo(Level.CONFIG), - () -> assertThat(message.getMessage()) - .matches( - "Using generated seed for configuration parameter 'cucumber\\.execution\\.order\\.random\\.seed' with value '\\d+'.")); + () -> assertThat(message.getLevel()).isEqualTo(Level.CONFIG), + () -> assertThat(message.getMessage()) + .matches( + "Using generated seed for configuration parameter 'cucumber\\.execution\\.order\\.random\\.seed' with value '\\d+'.")); } @Test @@ -952,8 +951,8 @@ void supportsRandomOrderWithSeed() { .configurationParameter(EXECUTION_ORDER_RANDOM_SEED_PROPERTY_NAME, "1234") .configurationParameter(JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, "long") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), - selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature"), + selectClasspathResource("io/cucumber/junit/platform/engine/ordering.feature")) .execute() .allEvents() .started() @@ -961,30 +960,30 @@ void supportsRandomOrderWithSeed() { .extracting(Event::getTestDescriptor) .extracting(TestDescriptor::getDisplayName) .containsExactly("Cucumber", - "1. A feature to order scenarios", - "1. A feature to order scenarios - 1.4", - "1. A feature to order scenarios - 1.4 - 1.4.1", - "1. A feature to order scenarios - 1.4 - 1.4.2", - "1. A feature to order scenarios - 1.1", - "1. A feature to order scenarios - 1.3 A rule", - "1. A feature to order scenarios - 1.3 A rule - 1.3.2", - "1. A feature to order scenarios - 1.3 A rule - 1.3.1", - "1. A feature to order scenarios - 1.2", - "1. A feature to order scenarios - 1.2 - 1.2.2", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", - "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", - "1. A feature to order scenarios - 1.2 - 1.2.1", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", - "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", - "A feature with a single scenario", - "A feature with a single scenario - A single scenario"); + "1. A feature to order scenarios", + "1. A feature to order scenarios - 1.4", + "1. A feature to order scenarios - 1.4 - 1.4.1", + "1. A feature to order scenarios - 1.4 - 1.4.2", + "1. A feature to order scenarios - 1.1", + "1. A feature to order scenarios - 1.3 A rule", + "1. A feature to order scenarios - 1.3 A rule - 1.3.2", + "1. A feature to order scenarios - 1.3 A rule - 1.3.1", + "1. A feature to order scenarios - 1.2", + "1. A feature to order scenarios - 1.2 - 1.2.2", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.1", + "1. A feature to order scenarios - 1.2 - 1.2.2 - Example #2.2", + "1. A feature to order scenarios - 1.2 - 1.2.1", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.2", + "1. A feature to order scenarios - 1.2 - 1.2.1 - Example #1.1", + "A feature with a single scenario", + "A feature with a single scenario - A single scenario"); } @Test void reportsParsErrorsAsDiscoveryIssues() { EngineDiscoveryResults results = EngineTestKit.engine(ENGINE_ID) .selectors( - selectFile("src/test/bad-features/parse-error.feature")) + selectFile("src/test/bad-features/parse-error.feature")) .discover(); DiscoveryIssue issue = results.getDiscoveryIssues().get(0); @@ -1000,11 +999,11 @@ void reportsParsErrorsAsDiscoveryIssues() { void supportsExclusiveResources() { PickleDescriptor pickleDescriptor = EngineTestKit.engine(ENGINE_ID) .configurationParameter(EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + "ResourceA" + READ_WRITE_SUFFIX, - "resource-a") + "resource-a") .configurationParameter(EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + "ResourceAReadOnly" + READ_SUFFIX, - "resource-a") + "resource-a") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/resource.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/resource.feature")) .discover() .getEngineDescriptor() .getDescendants() @@ -1016,8 +1015,8 @@ void supportsExclusiveResources() { assertThat(pickleDescriptor.getExclusiveResources()) .containsExactlyInAnyOrder( - new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ_WRITE), - new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ)); + new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ_WRITE), + new ExclusiveResource("resource-a", ExclusiveResource.LockMode.READ)); } @@ -1026,7 +1025,7 @@ void supportsConcurrentExecutionOfFeatureElements() { Set> testDescriptors = EngineTestKit.engine(ENGINE_ID) .configurationParameter(EXECUTION_MODE_FEATURE_PROPERTY_NAME, "concurrent") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) .discover() .getEngineDescriptor() .getDescendants() @@ -1046,7 +1045,7 @@ void supportsSameThreadExecutionOfFeatureElements() { Set testDescriptors = EngineTestKit.engine(ENGINE_ID) .configurationParameter(EXECUTION_MODE_FEATURE_PROPERTY_NAME, "same_thread") .selectors( - selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) + selectClasspathResource("io/cucumber/junit/platform/engine/single.feature")) .discover() .getEngineDescriptor() .getDescendants(); From 30a12642e2108a0d8167b84f4a659547e86a97d2 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 13 Jul 2025 14:56:44 +0200 Subject: [PATCH 6/6] Update docs + changelog --- CHANGELOG.md | 3 +++ cucumber-junit-platform-engine/README.md | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4c7595516..4ecb463146 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- [JUnit Platform Engine] Add `cucumber.junit-platform.discovery.as-root-engine` to work around SBT issues ([#3023](https://github.com/cucumber/cucumber-jvm/pull/3023) M.P. Korstanje) + ### Fixed - [JUnit Platform Engine] Don't use Java 9+ APIs ([#3025](https://github.com/cucumber/cucumber-jvm/pull/3025) M.P. Korstanje) - [JUnit Platform Engine] Implement toString on custom DiscoverySelectors diff --git a/cucumber-junit-platform-engine/README.md b/cucumber-junit-platform-engine/README.md index dc7f2f335f..f3cb890a27 100644 --- a/cucumber-junit-platform-engine/README.md +++ b/cucumber-junit-platform-engine/README.md @@ -448,9 +448,15 @@ cucumber.filter.tags= # a cucumber tag cucumber.glue= # comma separated package names. # example: com.example.glue +cucumber.junit-platform.discovery.as-root-engine # true or false + # default: true + # enable discovery when used as a root engine. + # note: Workaround for SBT issues. + cucumber.junit-platform.naming-strategy= # long, short or surefire. # default: short - # include parent descriptor name in test descriptor. + # long: include parent descriptor names in test descriptor. + # surefire: Workaround to make test names appear nicely with Surefire. cucumber.junit-platform.naming-strategy.short.example-name= # number, number-and-pickle-if-parameterized or pickle. # default: number-and-pickle-if-parameterized