### Build Cucumber-JVM with Maven Source: https://github.com/cucumber/cucumber-jvm/blob/main/CONTRIBUTING.md Initial build command to install the project while skipping tests and archetypes. ```bash mvn install -DskipTests=true -DskipITs=true -Darchetype.test.skip=true ``` -------------------------------- ### Define Logging Properties Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-core/README.md Example configuration for java.util.logging to output FINE level logs to the console. ```properties handlers=java.util.logging.ConsoleHandler .level=FINE java.util.logging.ConsoleHandler.level=FINE java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter ``` -------------------------------- ### Configuration Properties: Basic Settings Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Example `cucumber.properties` file showing basic configuration for glue code, features, and filtering. ```properties # cucumber.properties cucumber.glue=com.example.stepdefs cucumber.features=src/test/resources/features # Filtering cucumber.filter.tags=@smoke and not @wip cucumber.filter.name=^Login.* # Execution cucumber.execution.dry-run=false cucumber.execution.parallel.enabled=true cucumber.execution.parallel.config.strategy=fixed cucumber.execution.parallel.config.fixed.parallelism=4 cucumber.execution.order=random # Plugins cucumber.plugin=pretty, html:target/cucumber-report.html, json:target/cucumber.json, rerun:target/rerun.txt # Output cucumber.ansi-colors.disabled=false cucumber.snippet-type=underscore # Publishing cucumber.publish.enabled=false cucumber.publish.quiet=true ``` -------------------------------- ### Implement Lazy Resource Initialization Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-picocontainer/README.md Example of lazily creating expensive resources to optimize performance during scenario recreation. ```java public class LazyWebDriver implements Webdriver { private final Webdriver delegate; private Webdriver getDelegate() { if (delegate == null) { delegate = new ChromeWebDriver(); } return webdriver; } @Override public void doThing() { getDelegate().doThing(); } ... } ``` -------------------------------- ### TableEntryTransformer Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/datatable/README.md Illustrates how to transform a table into a list of maps by splitting the header from the body and pairing them. ```gherkin Header: | firstName | lastName | Body: | Annie M. G. | Schmidt | | Roald | Dahl | | Astrid | Lindgren | ``` -------------------------------- ### Combined Table Transformation Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/datatable/README.md Demonstrates creating a map of keys and values by splitting a table into keys and values, then applying transformations. ```gherkin Keys: Values: Header: | firstName | | lastName | birthDate | Body: | Annie M. G. | | Schmidt | 1911-03-20 | | Roald | => | Dahl | 1916-09-13 | | Astrid | | Lindgren | 1907-11-14 ``` -------------------------------- ### Eclipse System Property Example Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Pass system parameters like '-DtargetAppType=MobileWebApp' in the VM Arguments section to configure application types. ```bash -DtargetAppType=MobileWebApp ``` -------------------------------- ### Configuration Properties: Parallel Execution Strategy Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Example `junit-platform.properties` file configuring parallel execution with a dynamic strategy. ```properties # junit-platform.properties cucumber.execution.parallel.enabled=true cucumber.execution.parallel.config.strategy=dynamic cucumber.execution.parallel.config.dynamic.factor=1.0 ``` -------------------------------- ### Message Formatter Output Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v6.0.0.md Example of the NDJSON output structure generated by the message formatter. ```ndjson {"source":{"uri":"features/minimal/minimal.feature","data":"Feature: minim ... {"gherkinDocument":{"uri":"features/minimal/minimal.feature","feature": ... {"pickle":{"id":"4","uri":"features/minimal/minimal.feature", ... }} {"stepDefinition":{"id":"0","pattern":{"source":"I have {int} cukes in my ... {"testRunStarted":{"timestamp":{"seconds":"0","nanos":0}}} {"testCase":{"id":"6","pickleId":"4","testSteps":[{"id":"5","pickleStepId": ... {"testCaseStarted":{"timestamp":{"seconds":"0","nanos":1000000},"attempt":0, ... {"testStepStarted":{"timestamp":{"seconds":"0","nanos":2000000}, ... {"testStepFinished":{"testStepResult":{"status":"PASSED","duration": ... {"testCaseFinished":{"timestamp":{"seconds":"0","nanos":6000000}, ... {"testRunFinished":{"timestamp":{"seconds":"0","nanos":7000000}}} ``` -------------------------------- ### Guice ScenarioScoped Step Definitions Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Example of step definitions using Guice with @ScenarioScoped for state isolation. Dependencies like ShoppingCart and ProductService are injected. ```java package com.example.stepdefs; import io.cucumber.guice.ScenarioScoped; import io.cucumber.java.en.Given; import javax.inject.Inject; @ScenarioScoped public class ShoppingCartSteps { private final ShoppingCart cart; private final ProductService productService; @Inject public ShoppingCartSteps(ShoppingCart cart, ProductService productService) { this.cart = cart; this.productService = productService; } @Given("I add {string} to my cart") public void i_add_to_my_cart(String productName) { Product product = productService.findByName(productName); cart.add(product); } } ``` -------------------------------- ### CDI Jakarta Step Definition Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-jakarta-cdi/README.md Example of a step definition class using CDI for dependency injection. Ensure step definition classes are application-scoped or higher to share state. Consider adding a `beans.xml` to declare all test classes as beans. ```java package com.example.app; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; public class StepDefinition { @Inject private final Belly belly; public StepDefinitions(Belly belly) { this.belly = belly; } @Given("I have {int} {word} in my belly") public void I_have_n_things_in_my_belly(int n, String what) { belly.setContents(Collections.nCopies(n, what)); } @Then("there are {int} cukes in my belly") public void checkCukes(int n) { assertEquals(belly.getContents(), Collections.nCopies(n, "cukes")); } } ``` -------------------------------- ### Implement BeforeAll and AfterAll Hooks in Java Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Use static methods annotated with @BeforeAll and @AfterAll for expensive setup and teardown operations that run once per test suite. ```java package com.example.app; import io.cucumber.java.AfterAll; import io.cucumber.java.BeforeAll; public class GlobalHooks { private static TestServer server; @BeforeAll public static void beforeAll() { server = new TestServer(); server.start(); System.out.println("Test server started on port " + server.getPort()); } @AfterAll public static void afterAll() { if (server != null) { server.stop(); System.out.println("Test server stopped"); } } } ``` -------------------------------- ### Installing a TypeRegistryConfigurer Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v4.2.0.md Implement TypeRegistryConfigurer to install a custom object mapper for parameter type transformations. Ensure the locale is set and configure default transformers. ```java public class ParameterTypes implements TypeRegistryConfigurer { @Override public Locale locale() { return ENGLISH; } @Override public void configureTypeRegistry(TypeRegistry typeRegistry) { Transformer transformer = new Transformer(); typeRegistry.setDefaultDataTableCellTransformer(transformer); typeRegistry.setDefaultDataTableEntryTransformer(transformer); typeRegistry.setDefaultParameterTransformer(transformer); } private class Transformer implements ParameterByTypeTransformer, TableEntryByTypeTransformer, TableCellByTypeTransformer { ObjectMapper objectMapper = new ObjectMapper(); @Override public Object transform(String s, Type type) { return objectMapper.convertValue(s, objectMapper.constructType(type)); } @Override public T transform(Map map, Class aClass, TableCellByTypeTransformer tableCellByTypeTransformer) { return objectMapper.convertValue(map, aClass); } @Override public T transform(String s, Class aClass) { return objectMapper.convertValue(s, aClass); } } } ``` -------------------------------- ### Select Classpath Resource with File Position Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Select a feature file from the classpath and specify a starting line number for discovery. ```java DiscoverySelectors.selectClasspathResource("rule.feature", FilePosition.from(5)) ``` -------------------------------- ### Configure Custom Publishing URL Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v6.5.0.md Example of overriding the default publishing URL and adding custom HTTP headers using curl-like syntax. ```bash export CUCUMBER_PUBLISH_URL="https://host.com -X POST -H 'Content-Type: application/x-ndjson'" ``` -------------------------------- ### Select File with File Position Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Select a feature file from the file system and specify a starting line number for discovery. ```java DiscoverySelectors.selectFile("rule.feature", FilePosition.from(5)) ``` -------------------------------- ### Define Gherkin Scenario for Parameter Transformation Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v5.0.0.md Example Gherkin scenario demonstrating parameter lookup within a catalog. ```gherkin Given the awesome catalog When a user places the awestruck eels in his basket Then you will be shocked at what happened next ``` -------------------------------- ### Define Parallel Execution Scenarios Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Example Gherkin features demonstrating resource locking and isolation tags. ```gherkin Feature: Parallel Execution @reads-and-writes-system-properties Scenario: Modify system property Given I set system property "test.mode" to "enabled" When I read system property "test.mode" Then the value should be "enabled" @reads-system-properties Scenario: Read system property When I read system property "java.version" Then the value should not be empty @isolated Scenario: Must run alone Given this test requires exclusive access to all resources When it executes Then no other scenarios are running concurrently ``` -------------------------------- ### Gherkin DataTable Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/datatable/README.md A basic Gherkin DataTable with string values. ```gherkin | firstName | lastName | birthDate | | Annie M. G. | Schmidt | 1911-03-20 | | Roald | Dahl | 1916-09-13 | | Astrid | Lindgren | 1907-11-14 | ``` -------------------------------- ### Run Cucumber Features with JUnit 5 Console Launcher Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v5.0.0.md This is an example output from the JUnit 5 Console Launcher when running Cucumber features. It shows the hierarchical structure of discovered and executed features and scenarios. ```text ╷ └─ Cucumber ✔ ├─ A feature with scenario outlines ✔ │ ├─ A scenario ✔ │ ├─ A scenario outline ✔ │ │ ├─ With some text ✔ │ │ │ ├─ Example #1 ✔ │ │ │ └─ Example #2 ✔ │ │ └─ With some other text ✔ │ │ ├─ Example #1 ✔ │ │ └─ Example #2 ✔ │ └─ A scenario outline with one example ✔ │ └─ Examples ✔ │ ├─ Example #1 ✔ │ └─ Example #2 ✔ └─ A feature with a single scenario ✔ └─ A single scenario ✔ Test run finished after 2588 ms [ 8 containers found ] [ 0 containers skipped ] [ 8 containers started ] [ 0 containers aborted ] [ 8 containers successful ] [ 0 containers failed ] [ 8 tests found ] [ 0 tests skipped ] [ 8 tests started ] [ 0 tests aborted ] [ 8 tests successful ] [ 0 tests failed ] ``` -------------------------------- ### PicoContainer Step Definitions Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Example of step definitions using PicoContainer for dependency injection. The Belly class is automatically injected into the Step Definitions constructor. ```java package com.example.app; public class Belly { private int cukes; public void eat(int cukes) { this.cukes += cukes; } public int getCukes() { return cukes; } } ``` ```java package com.example.stepdefs; import com.example.app.Belly; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import static org.junit.jupiter.api.Assertions.assertEquals; public class BellyStepDefinitions { private final Belly belly; // PicoContainer injects Belly automatically public BellyStepDefinitions(Belly belly) { this.belly = belly; } @Given("I have {int} cukes in my belly") public void i_have_cukes_in_my_belly(int cukes) { belly.eat(cukes); } @When("I wait {int} hour(s)") public void i_wait_hours(int hours) { // Simulate time passing } @Then("my belly should have {int} cukes") public void my_belly_should_have_cukes(int expected) { assertEquals(expected, belly.getCukes()); } } ``` -------------------------------- ### Gherkin DocString Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v5.0.0.md DocStrings allow passing multi-line text blocks to step definitions, often used for JSON or XML payloads. ```gherkin Given some more information """json { "produce": "Cucumbers", "weight": "5 Kilo", "price": "1€/Kilo" } """ ``` -------------------------------- ### Injecting Services in Step Definitions Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-spring/README.md Example of injecting a service into a step definition class when the application context is managed by Cucumber-Spring. ```java package com.example.app; public class MyStepDefinitions { @Autowired private MyService myService; // Each scenario will have a new instance of MyService } ``` -------------------------------- ### Localized Date Transformer Setup Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java/README.md Configure a DateTimeFormatter with the scenario's language and locale to parse dates localized to the feature file's language. This is typically set up in a @Before hook. ```java package com.example.app; import io.cucumber.java.Before; import io.cucumber.java.ParameterType; import io.cucumber.java.Scenario; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Locale; public class TransformerDefinitions { private DateTimeFormatter formatter; @Before public void updateFormatter(final Scenario scenario) { String language = scenario.getLanguage(); Locale locale = new Locale.Builder().setLanguage(language).build(); formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy").withLocale(locale); } @ParameterType(value = "\\d{1,2} \\w+ \\d{4}") public LocalDate localizedDate(String value) { return LocalDate.parse(value, formatter); } } ``` -------------------------------- ### List Supported Properties Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v6.0.0.md Run the Cucumber CLI with the help flag to view all supported system properties. ```shell mvn exec:java \ -Dexec.classpathScope=test \ -Dexec.mainClass=io.cucumber.core.cli.Main \ -Dexec.args="--help" ``` -------------------------------- ### IDEA Application Run Configuration - Working Directory Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Set the working directory for the application run configuration. Adjust slashes for Windows. ```bash $MODULE_DIR$/target/ ``` -------------------------------- ### Cucumber Report URL Output Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v6.5.0.md Example of the console output provided by Cucumber after a successful report upload. ```text ┌──────────────────────────────────────────────────────────────────────────┐ │ View your Cucumber Report at: │ │ https://reports.cucumber.io/reports/f318d9ec-5a3d-4727-adec-bd7b69e2edd3 │ │ │ │ This report will self-destruct in 24h unless it is claimed or deleted. │ └──────────────────────────────────────────────────────────────────────────┘ ``` -------------------------------- ### Configure JUnit Runner for Cucumber Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Basic setup for a JUnit test class to execute all Cucumber features. ```java import cucumber.junit.Cucumber; import org.junit.runner.RunWith; @RunWith(Cucumber.class) public class RunCukesTest { } ``` -------------------------------- ### Format Source Code with Spotless Source: https://github.com/cucumber/cucumber-jvm/blob/main/CONTRIBUTING.md Command to trigger automatic source code formatting using the Spotless plugin. ```bash mvn install ``` -------------------------------- ### Run Specific Scenario with Maven Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Use this Maven command to run a specific scenario on line 10 of example.feature, including the Cucumber engine and pretty plugin. ```shell mvn test -Dsurefire.includeJUnit5Engines=cucumber -Dcucumber.plugin=pretty -Dcucumber.features=path/to/example.feature:10 ``` -------------------------------- ### Run Specific Scenario with Gradle Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Execute this Gradle command to run a specific scenario on line 10 of example.feature, passing Cucumber properties. ```shell gradle test --rerun-tasks --info -Dcucumber.plugin=pretty -Dcucumber.features=path/to/example.feature:10 ``` -------------------------------- ### Configure Multiple Contexts with JUnit 5 Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-spring/README.md Use the JUnit Platform Suite to define specific packages and glue configurations for test execution. ```java package com.example; import org.junit.platform.suite.api.ConfigurationParameter; import org.junit.platform.suite.api.SelectPackages; import org.junit.platform.suite.api.Suite; import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME; @Suite @SelectPackages("com.example.application.one") @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.application.one") public class ApplicationOneTest { } ``` -------------------------------- ### Implement BeforeAll and AfterAll Hooks Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java/README.md Use static methods annotated with @BeforeAll and @AfterAll to execute logic before and after all scenarios. ```java package io.cucumber.example; import io.cucumber.java.AfterAll; import io.cucumber.java.BeforeAll; public class StepDefinitions { @BeforeAll public static void beforeAll() { // Runs before all scenarios } @AfterAll public static void afterAll() { // Runs after all scenarios } } ``` -------------------------------- ### Cucumber Project Structure with Implicit Glue Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v4.0.0.md Illustrates a standard project structure where the runner assumes the glue path is its current package. ```text src/test/java |- RunCukes.java // implicit @CucumberOptions(glue={"login", "signup", "common"}, ....) |- login | |- login.feature | |- LoginSteps.java |- signup | |- signup.feature | |- SignupSteps.java |- common | |- CommonSteps.java | |- SharedSteps.java ``` -------------------------------- ### Get Scenario ID in Cucumber JVM Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v2.0.0.md The `getId` method now returns the string format `:`. ```java scenario.getId() ``` -------------------------------- ### IDEA Application Run Configuration - Program Arguments Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Provide program arguments for running Cucumber tests, including the feature file path, glue code, and formatter. Note that $FilePath$ needs manual replacement. ```bash $FilePath$ --glue com.your.gluecode.path --format gherkin.formatter.PrettyFormatter ``` -------------------------------- ### CLI Execution: Basic Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Basic command to run Cucumber tests from the command line, specifying glue code and feature file location. ```bash java -cp "target/test-classes:target/classes:lib/*" io.cucumber.core.cli.Main \ --glue com.example.stepdefs \ src/test/resources/features ``` -------------------------------- ### Declare Parameter Type Transformer Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java8/README.md Declare step definition parameter types using `ParameterType`. This example defines a transformer for an 'amount' type. ```java package com.example.app; import io.cucumber.java8.En; import static org.junit.jupiter.api.Assertions.assertEquals; public class StepDefinitions implements En { public StepDefinitions() { ParameterType("amount", "(\d+\.\d+)\s([a-zA-Z]+)", (String[] values) -> new Amount(new BigDecimal(values[0]), Currency.getInstance(values[1]))); } } ``` -------------------------------- ### Cucumber Project Structure with Extra Glue Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v4.0.0.md Demonstrates using the extraGlue property to include additional glue paths alongside the default package-based glue. ```text src/test/java |- login | |- RunCukes.java // @CucumberOptions(extraGlue={"common"}) implicit glue="login" | |- login.feature | |- LoginSteps.java | |- LoginPicoFactoryConfiguration.java | |- LoginTypeRegistryConfiguration.java |- signup | |- RunCukes.java // @CucumberOptions(extraGlue={"common"}) implicit glue="signup" | |- signup.feature | |- SignupSteps.java | |- SignupPicoFactoryConfiguration.java | |- SignupTypeRegistryConfiguration.java |- common | |- CommonSteps.java | |- SharedSteps.java | |- CommonPicoFactoryConfiguration.java | |- CommonTypeRegistryConfiguration.java ``` -------------------------------- ### BeforeStep and AfterStep Hooks Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java/README.md Use @BeforeStep and @AfterStep annotations to execute methods before and after each step. These hooks can optionally accept a Step argument. ```java package io.cucumber.example; import io.cucumber.java.AfterStep; import io.cucumber.java.BeforeStep; import io.cucumber.java.Scenario; public class StepDefinitions { @BeforeStep("not @zukini") public void before(Scenario scenario) { scenario.log("Runs before each step in scenarios *not* tagged with @zukini"); } @AfterStep public void after(Scenario scenario) { scenario.log("Runs after each step"); } } ``` -------------------------------- ### Get Lowercase Status Name in Cucumber JVM Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v2.0.0.md To obtain the lowercase string representation of the scenario status, similar to v1.2.5, use `scenario.getStatus().lowerCaseName()`. ```java scenario.getStatus().lowerCaseName() ``` -------------------------------- ### Configure Gradle JavaExec Task for JUnit Platform CLI Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Add this to your build.gradle.kts to define a JavaExec task for the ConsoleLauncher. It depends on testClasses and sets up the classpath and main class. ```kotlin tasks { val consoleLauncherTest by registering(JavaExec::class) { dependsOn(testClasses) val reportsDir = file("$buildDir/test-results") outputs.dir(reportsDir) classpath = sourceSets["test"].runtimeClasspath main = "org.junit.platform.console.ConsoleLauncher" args("--scan-classpath") args("--include-engine", "cucumber") args("--reports-dir", reportsDir) } test { dependsOn(consoleLauncherTest) exclude("**/*") } } ``` -------------------------------- ### Declare Data Table Type Transformer Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java8/README.md Declare data table types by calling `DataTableType` in the constructor. This example transforms a map entry into a Grocery object. ```java package com.example.app; import io.cucumber.java8.En; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; public class StepDefinitions implements En { public StepDefinitions() { DataTableType((Map row) -> new Grocery( row.get("name"), Price.fromString(row.get("price")) )); } } ``` -------------------------------- ### BeforeStep/AfterStep with Step Argument Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java/README.md Access step details like keyword and text within BeforeStep and AfterStep hooks by including a Step argument. ```java package io.cucumber.example; import io.cucumber.java.AfterStep; import io.cucumber.java.BeforeStep; import io.cucumber.java.Scenario; import io.cucumber.java.Step; public class StepDefinitions { @BeforeStep public void beforeStep(Scenario scenario, Step step) { scenario.log("About to run: " + step.getKeyword() + step.getText()); scenario.log("Step is on line: " + step.getLine()); } @AfterStep public void afterStep(Scenario scenario, Step step) { scenario.log("Finished: " + step.getText()); } } ``` -------------------------------- ### Data Table Type Transformer Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java/README.md Convert data table entries into custom Java objects using @DataTableType. This example transforms a map of strings into an Author object. ```java package com.example.app; import io.cucumber.datatable.DataTable; import io.cucumber.java.DataTableType; import java.util.List; import java.util.Map; public class StepDefinitions { @DataTableType public Author authorEntryTransformer(Map entry) { return new Author( entry.get("firstName"), entry.get("lastName"), entry.get("birthDate")); } @Given("a list of authors in a table") public void aListOfAuthorsInATable(List authors) { } } ``` -------------------------------- ### Configure Java Logging via System Property Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-core/README.md Use this system property to specify a custom logging configuration file for debugging. ```text -Djava.util.logging.config.file=path/to/logging.properties ``` -------------------------------- ### Configure Multiple Contexts with JUnit 4 or TestNG Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-spring/README.md Use separate test runner classes with specific glue and feature paths to execute different application contexts. ```java package com.example; import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions(glue = "com.example.application.one", features = "classpath:com/example/application.one") public class ApplicationOneTest { } ``` -------------------------------- ### Java Transpose DataTable Example Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java8/README.md Demonstrates transposing a data table in Cucumber-JVM to create a User object. The `.transpose()` method is called on the DataTable before converting it to a list of User objects. ```java package com.example.app; import io.cucumber.datatable.DataTable; import io.cucumber.java8.En; import java.util.List; import java.util.Map; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; public class StepDefinitions implements En { public StepDefinitions() { DataTableType((Map entry) -> new User( entry.get("firstname"), entry.get("lastname"), entry.get("nationality") )); Given("the user is", (DataTable authorsTable) -> { User user = authorsTable.transpose().asList(User.class); // user = User(firstname="Roberto", lastname="Lo Giacco", nationality="Italian") }); } } ``` -------------------------------- ### Declare Default Parameter Transformer with Jackson Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java8/README.md Use `DefaultParameterTransformer` with an object mapper like Jackson to transform string representations to Java objects. This example uses `ObjectMapper` for conversion. ```java package com.example.app; import com.fasterxml.jackson.databind.ObjectMapper; import io.cucumber.java8.En; public class StepDefinitions implements En { public StepDefinitions() { final ObjectMapper objectMapper = new ObjectMapper(); DefaultParameterTransformer((fromValue, toValueType) -> objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType)) ); } } ``` -------------------------------- ### Implement Scenario API and Attachments Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Access scenario metadata and attach logs, screenshots, or data files during test execution. ```java package com.example.stepdefs; import io.cucumber.java.After; import io.cucumber.java.Before; import io.cucumber.java.Scenario; import io.cucumber.java.en.When; public class ScenarioStepDefinitions { private Scenario scenario; @Before public void before(Scenario scenario) { this.scenario = scenario; scenario.log("Starting: " + scenario.getName()); scenario.log("Tags: " + scenario.getSourceTagNames()); scenario.log("URI: " + scenario.getUri()); scenario.log("Line: " + scenario.getLine()); } @When("I perform an action") public void i_perform_action() { // Log during execution scenario.log("Performing action..."); // Attach text scenario.attach("Debug info: action completed", "text/plain", "action-log"); // Attach screenshot byte[] screenshot = captureScreenshot(); scenario.attach(screenshot, "image/png", "step-screenshot"); // Attach JSON data String jsonData = "{\"status\": \"success\", \"timestamp\": \"2024-01-15T10:30:00Z\"}"; scenario.attach(jsonData.getBytes(), "application/json", "response-data"); } @After public void after(Scenario scenario) { if (scenario.isFailed()) { byte[] screenshot = captureScreenshot(); scenario.attach(screenshot, "image/png", "failure-screenshot"); } scenario.log("Status: " + scenario.getStatus()); } } ``` -------------------------------- ### Configure beans.xml for CDI support Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-deltaspike/README.md Place this file in the classpath (META-INF) to enable CDI support for step definitions. ```xml ``` -------------------------------- ### Generate Cucumber Project with Maven Archetype Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-archetype/README.md Use this Maven command to generate a new Cucumber project. Ensure you have Maven installed. Replace ${cucumber.version} with the desired Cucumber version. ```shell mvn archetype:generate \ -DarchetypeGroupId=io.cucumber \ -DarchetypeArtifactId=cucumber-archetype \ -DarchetypeVersion=${cucumber.version} ``` -------------------------------- ### Gradle Configuration for Cucumber JVM Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Configure Cucumber JVM dependencies and test task properties using Kotlin DSL. This setup enables parallel execution and custom reporting. ```kotlin // build.gradle.kts plugins { java } repositories { mavenCentral() } dependencies { testImplementation(platform("io.cucumber:cucumber-bom:7.34.0")) testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("io.cucumber:cucumber-java") testImplementation("io.cucumber:cucumber-junit-platform-engine") testImplementation("org.junit.platform:junit-platform-suite") testImplementation("org.junit.jupiter:junit-jupiter") } tasks.test { useJUnitPlatform() systemProperty("cucumber.junit-platform.naming-strategy", "long") systemProperty("cucumber.plugin", "pretty,html:build/reports/cucumber.html") systemProperty("cucumber.execution.parallel.enabled", "true") systemProperty("cucumber.execution.parallel.config.fixed.parallelism", "4") // Pass through system properties from command line systemProperty("cucumber.filter.tags", System.getProperty("cucumber.filter.tags") ?: "") systemProperty("cucumber.features", System.getProperty("cucumber.features") ?: "") } ``` -------------------------------- ### Configure Apache OpenWebBeans for CDI SE Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-jakarta-cdi/README.md Add these dependencies to your `pom.xml` to configure Apache OpenWebBeans as the CDI SE implementation. Ensure you use the correct `xbean.version` and `openwebbeans.version`. ```xml org.apache.xbean xbean-finder-shaded ${xbean.version} test org.apache.xbean xbean-asm7-shaded ${xbean.version} test org.apache.openwebbeans openwebbeans-impl ${openwebbeans.version} test jakarta * * org.apache.openwebbeans openwebbeans-spi ${openwebbeans.version} test jakarta * * org.apache.openwebbeans openwebbeans-se ${openwebbeans.version} jakarta test * * ``` -------------------------------- ### Implement Step Definition with Injection Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-picocontainer/README.md A step definition class using constructor injection to receive a Belly instance. ```java package com.example.app; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; public class StepDefinition { private final Belly belly; public StepDefinitions(Belly belly) { this.belly = belly; } @Given("I have {int} {word} in my belly") public void I_have_n_things_in_my_belly(int n, String what) { belly.setContents(Collections.nCopies(n, what)); } @Then("there are {int} cukes in my belly") public void checkCukes(int n) { assertEquals(belly.getContents(), Collections.nCopies(n, "cukes")); } } ``` -------------------------------- ### Configure CDI SE Implementations Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-cdi2/README.md Add the required CDI SE implementation dependency for your project. ```xml org.apache.openwebbeans openwebbeans-se 2.0.10 test ``` ```xml org.jboss.weld.se weld-se-core 3.1.6.Final test ``` -------------------------------- ### Java DataTableType for Empty Cells Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java8/README.md Configures Cucumber-JVM to interpret '[blank]' as an empty string when creating Author objects from a data table. This setup is done within the StepDefinitions class. ```java package com.example.app; import io.cucumber.datatable.DataTable; import io.cucumber.java8.En; import java.util.List; import java.util.Map; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; public class StepDefinitions implements En { public StepDefinitions() { DataTableType("[blank]", (Map entry) -> new Author( entry.get("name"), entry.get("first publication") )); Given("some authors", (DataTable authorsTable) -> { List authors = authorsTable.asList(Author.class); // authors = [Author(name="Aspiring Author", firstPublication=null), Author(name="Ancient Author", firstPublication=)] }); } } ``` -------------------------------- ### Configure Maven Antrun Plugin for JUnit Platform CLI Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Add this to your pom.xml to execute the JUnit Platform ConsoleLauncher. Ensure the junit-platform-console dependency is included. ```xml .... org.junit.platform junit-platform-console ${junit-platform.version} test org.apache.maven.plugins maven-antrun-plugin CLI-test integration-test run ``` -------------------------------- ### JUnit 4 Cucumber Test Runner Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v7.0.0.md Example of a JUnit 4 test class used to run Cucumber features. It utilizes the @RunWith(Cucumber.class) annotation and specifies feature files and glue code. ```java package com.example; import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions(glue = "com.example.application", features = "classpath:com/example/application") public class RunCucumberTest { } ``` -------------------------------- ### Hooks: Before and After Scenarios/Steps in Java Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Hooks execute code before and after scenarios or steps, and can be conditional using tag expressions. They accept a Scenario parameter for logging and accessing scenario metadata. ```java package com.example.app; import io.cucumber.java.After; import io.cucumber.java.AfterStep; import io.cucumber.java.Before; import io.cucumber.java.BeforeStep; import io.cucumber.java.Scenario; public class HookDefinitions { @Before public void setUp(Scenario scenario) { scenario.log("Starting scenario: " + scenario.getName()); } @Before("@database") public void setUpDatabase() { // Only runs for scenarios tagged with @database DatabaseHelper.startTransaction(); } @After public void tearDown(Scenario scenario) { if (scenario.isFailed()) { byte[] screenshot = takeScreenshot(); scenario.attach(screenshot, "image/png", "failure-screenshot"); } } @After("@database") public void rollbackDatabase() { DatabaseHelper.rollbackTransaction(); } @BeforeStep public void beforeStep(Scenario scenario) { scenario.log("About to execute step"); } @AfterStep public void afterStep(Scenario scenario) { scenario.log("Step completed"); } } ``` -------------------------------- ### Configure Custom Data Table Types in Java Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v3.0.0.md Implement TypeRegistryConfigurer to define custom data table types. This example shows how to map rows to a Grocery object using explicit field extraction. ```java public class TypeRegistryConfiguration implements TypeRegistryConfigurer { @Override public Locale locale() { return ENGLISH; } @Override public void configureTypeRegistry(TypeRegistry typeRegistry) { typeRegistry.defineDataTableType(new DataTableType( Grocery.class, (Map row) -> new Grocery( row.get("name"), Price.fromString(row.get("price")) ) )); } } ``` -------------------------------- ### Configure Cucumber via CLI Properties Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v5.0.0.md Pass configuration options to Cucumber using Maven system properties. ```shell mvn clean test -Dcucumber.options="--strict --monochrome" ``` ```shell mvn clean test -Dcucumber.options='--strict --monochrome --tags "not @ignored"' ``` ```shell mvn clean test \ -Dcucumber.execution.strict=true \ -Dcucumber.ansi-colors.disabled=true \ -Dcucumber.filter.tags="not @ignored" ``` -------------------------------- ### CLI Execution: With Plugins and Filtering Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Command to run Cucumber with multiple plugins for reporting (pretty, HTML, JSON) and filtering tests by tags and name patterns. ```bash java -cp "target/test-classes:target/classes:lib/*" io.cucumber.core.cli.Main \ --glue com.example.stepdefs \ --plugin pretty \ --plugin html:target/cucumber-report.html \ --plugin json:target/cucumber.json \ --tags "@smoke and not @wip" \ --name ".*Login.*" \ src/test/resources/features ``` -------------------------------- ### Initialize Cucumber Timeline Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-core/src/main/resources/io/cucumber/core/plugin/timeline/index.html Executes the preparation functions for the Cucumber Timeline report once the DOM is fully loaded. ```javascript $(document).ready(function () { CucumberHTML.PrepareData(); CucumberHTML.PreparePage(); }); ``` -------------------------------- ### Configure Weld SE for CDI Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-jakarta-cdi/README.md Add the `weld-se-core` dependency to your `pom.xml` to use Weld as the CDI SE implementation. Specify the desired version. ```xml org.jboss.weld.se weld-se-core 4.0.0 test ``` -------------------------------- ### Configure OpenWebBeans container dependencies Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-deltaspike/README.md Required dependencies for using the OpenWebBeans CDI container. ```xml org.apache.deltaspike.cdictrl deltaspike-cdictrl-owb ${deltaspike.version} test org.apache.openwebbeans openwebbeans-impl ${owb.version} test javax.annotation jsr250-api 1.0 test ``` -------------------------------- ### Use Repeatable Step Annotations Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v5.0.0.md Apply multiple step definition annotations to a single method to support different phrasing for the same logic. ```java package com.example; import io.cucumber.java.en.Given; public class StepDefinitions { @Given("a step definition") @Given("another way to express the same thing") public void a_step_definition(){ } } ``` -------------------------------- ### Configure Default Transformers with Jackson Source: https://context7.com/cucumber/cucumber-jvm/llms.txt Implement default transformers to enable automatic conversion of data tables and parameters into POJOs using an ObjectMapper. ```java package com.example.app; import com.fasterxml.jackson.databind.ObjectMapper; import io.cucumber.java.DefaultDataTableCellTransformer; import io.cucumber.java.DefaultDataTableEntryTransformer; import io.cucumber.java.DefaultParameterTransformer; import java.lang.reflect.Type; public class DefaultTransformers { private final ObjectMapper objectMapper = new ObjectMapper(); @DefaultParameterTransformer @DefaultDataTableEntryTransformer @DefaultDataTableCellTransformer public Object defaultTransformer(Object fromValue, Type toValueType) { return objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType)); } } ``` -------------------------------- ### Create Cucumber JUnit Runner Class Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit/README.md Create an empty Java class annotated with `@RunWith(Cucumber.class)` and `@CucumberOptions` to configure the runner. Glue code is assumed to be in the same package by default. ```java package com.example; import io.cucumber.junit.CucumberOptions; import io.cucumber.junit.Cucumber; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions(plugin = "message:target/cucumber-report.ndjson") public class RunCucumberTest { } ``` -------------------------------- ### Implement Step Definition for Data Table Source: https://github.com/cucumber/cucumber-jvm/blob/main/release-notes/v5.0.0.md Step definition receiving a list of Author objects from a data table. ```java package com.example; import io.cucumber.java.en.Given; import java.util.List; public class StepDefinitions { @Given("some great authors") public void some_authors(List authors){ /* * authors = [ * Author(fullName="Terry Pratchet", born=1948-04-28, died=2015-03-12) * Author(fullName="Neil Gaiman", born=1960-11-10, died=null), * ] */ } } ``` -------------------------------- ### Tagged Scenarios in Gherkin Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-junit-platform-engine/README.md Demonstrates tagging scenarios with @Smoke and @Ignore, and @Sanity for execution control. ```gherkin @Smoke @Ignore Scenario: A tagged scenario Given I tag a scenario When I select tests with that tag for execution Then my tagged scenario is executed @Sanity Scenario: Another tagged scenario Given I tag a scenario When I select tests with that tag for execution Then my tagged scenario is executed ``` -------------------------------- ### Share State Between Steps Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-spring/README.md Inject scenario-scoped components into multiple step definition classes to share state. ```java package com.example.app; import org.springframework.beans.factory.annotation.Autowired; import io.cucumber.java.en.Given; public class UserStepDefinitions { @Autowired private UserService userService; @Autowired private TestUserInformation testUserInformation; @Given("there is a user") public void there_is_as_user() { User testUser = userService.createUser(); testUserInformation.setTestUser(testUser); } } public class PurchaseStepDefinitions { @Autowired private PurchaseService purchaseService; @Autowired private TestUserInformation testUserInformation; @When("the user makes a purchase") public void the_user_makes_a_purchase(){ Order order = .... User user = testUserInformation.getTestUser(); purchaseService.purchase(user, order); } } ``` -------------------------------- ### IDEA External Tool Program Path Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Specify the Java Development Kit (JDK) path for the external tool. Adjust slashes for Windows and consider quotes if the path contains spaces. ```bash $JDKPath$/bin/java ``` -------------------------------- ### IDEA External Tool Working Directory Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Set the working directory for the external tool. Adjust slashes for Windows. ```bash $ModuleFileDir$/target ``` -------------------------------- ### IDEA Application Run Configuration - Main Class Source: https://github.com/cucumber/cucumber-jvm/wiki/IDE-support Specify 'cucumber.api.cli.Main' as the main class for running Cucumber tests as a Java application in IntelliJ IDEA. ```bash cucumber.api.cli.Main ``` -------------------------------- ### Define Step Definitions Source: https://github.com/cucumber/cucumber-jvm/blob/main/cucumber-java/README.md Annotate methods with @Given, @When, or @Then to map Gherkin steps to Java code. ```java package com.example.app; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import static org.junit.jupiter.api.Assertions.assertEquals; public class CalculatorStepDefinitions { private RpnCalculator calc; @Given("a calculator I just turned on") public void a_calculator_I_just_turned_on() { calc = new RpnCalculator(); } @When("I add {int} and {int}") public void adding(int arg1, int arg2) { calc.push(arg1); calc.push(arg2); calc.push("+"); } @Then("the result is {int}") public void the_result_is(double expected) { assertEquals(expected, calc.value()); } } ```