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..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
@@ -207,6 +207,26 @@ 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}.
+ *
+ * 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";
+
/**
* Property name to enable plugins: {@value}
*
@@ -272,7 +292,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;
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 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());
@@ -460,17 +475,6 @@ 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)
@@ -604,6 +608,42 @@ void onlySetsEngineSourceWhenFeaturesPropertyIsUsed() {
.haveExactly(1, event(test(finishedSuccessfully())));
}
+ @Suite
+ @IncludeEngines("cucumber")
+ @SelectClasspathResource("io/cucumber/junit/platform/engine/single.feature")
+ static class SuiteTestCase {
+
+ }
+
+ @Test
+ void supportsDisablingDiscoveryAsRootEngine() {
+ DiscoverySelector selector = selectClasspathResource("io/cucumber/junit/platform/engine/single.feature");
+
+ // 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();
+
+ assertThat(EngineTestKit.engine("junit-platform-suite")
+ .configurationParameter(JUNIT_PLATFORM_DISCOVERY_AS_ROOT_ENGINE_PROPERTY_NAME, "false")
+ .selectors(selectClass(SuiteTestCase.class))
+ .discover()
+ .getEngineDescriptor()
+ .getChildren())
+ .isNotEmpty();
+ }
+
@Test
void selectAndSkipDisabledScenarioByTags() {
EngineTestKit.engine(ENGINE_ID)