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 ab130fcd46..f3cb890a27 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 @@ -435,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 diff --git a/cucumber-junit-platform-engine/pom.xml b/cucumber-junit-platform-engine/pom.xml index c7ffac376f..32236c9de2 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 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)