Configuration
Parameter types​
Parameter types let you convert parameters from Cucumber expressions to objects.
- Java
- Kotlin
- Scala
- JavaScript
- Ruby
Data table and doc string types let you convert data tables and doc strings to objects. Like step definitions, type definitions are part of the glue. When placed on the glue path Cucumber will detect them automatically.
For example, the following class registers a custom "Author" data table type:
package com.example;
import io.cucumber.java.DataTableType;
import io.cucumber.java.en.Given;
import java.util.List;
import java.util.Map;
public class StepDefinitions {
@DataTableType
public Author authorEntry(Map<String, String> entry) {
return new Author(
entry.get("firstName"),
entry.get("lastName"),
entry.get("famousBook"));
}
@Given("There are my favorite authors")
public void these_are_my_favourite_authors(List<Author> authors) {
// step implementation
}
}
This class registers a custom "Book" type from an expression:
package com.example;
import io.cucumber.java.ParameterType;
import io.cucumber.java.en.Given;
public class StepDefinitions {
@ParameterType(".*")
public Book book(String bookName) {
return new Book(bookName);
}
@Given("{book} is my favorite book")
public void this_is_my_favorite_book(Book book) {
// step implementation
}
}
This class registers a custom type for a doc string:
package com.example;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.java.DocStringType;
import io.cucumber.java.en.Given;
public class StepsDefinitions {
private static ObjectMapper objectMapper = new ObjectMapper();
@DocStringType
public JsonNode json(String docString) throws JsonProcessingException {
return objectMapper.readValue(docString, JsonNode.class);
}
@Given("Books are defined by json")
public void books_are_defined_by_json(JsonNode books) {
// step implementation
}
}
For lambda-defined step definitions, there are DataTableType
, ParameterType
and DocStringType
functions:
package com.example;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.java8.En;
import java.util.Map;
public class LambdaStepDefinitions implements En {
private static ObjectMapper objectMapper = new ObjectMapper();
public LambdaStepDefinitions() {
DataTableType((Map<String, String> entry) -> new Author(
entry.get("firstName"),
entry.get("lastName"),
entry.get("famousBook")
));
ParameterType("book", ".*", (String bookName) -> new Book(bookName));
DocStringType("json", (String docString) ->
objectMapper.readValue(docString, JsonNode.class));
}
}
Using the @DefaultParameterTransformer
, @DefaultDataTableEntryTransformer
and @DefaultDataTableCellTransformer
annotations, it is also possible to plug in an object mapper. The object mapper (Jackson in this example) will handle the conversion of anonymous parameter types and data table entries:
package com.example;
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 StepDefinitions {
private final ObjectMapper objectMapper = new ObjectMapper();
@DefaultParameterTransformer
@DefaultDataTableEntryTransformer
@DefaultDataTableCellTransformer
public Object transformer(Object fromValue, Type toValueType) {
return objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType));
}
}
For lambda-defined step definitions, there are DefaultParameterTransformer
, DefaultDataTableCellTransformer
and DefaultDataTableEntryTransformer
methods:
package com.example;
import io.cucumber.java8.En;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Type;
public class LambdaStepDefinitions implements En {
public LambdaStepDefinitions() {
ObjectMapper objectMapper = new ObjectMapper();
DefaultParameterTransformer((String fromValue, Type toValueType) ->
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType)));
DefaultDataTableCellTransformer((fromValue, toValueType) ->
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType)));
DefaultDataTableEntryTransformer((fromValue, toValueType) ->
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType)));
}
}
Data table and doc string types let you convert data tables and doc strings to objects. Like step definitions, type definitions are part of the glue. When placed on the glue path Cucumber will detect them automatically.
For example, the following class registers a custom "Author" data table type:
package com.example
import io.cucumber.java.DataTableType
import io.cucumber.java.en.Given
import kotlin.streams.toList
class StepDefinitions {
@DataTableType
fun authorEntry(entry: Map<String, String>): Author {
return Author(
entry["firstName"],
entry["lastName"],
entry["famousBook"])
}
@Given("There are my favorite authors")
fun these_are_my_favourite_authors(authors: List<Author>) {
// step implementation
}
}
This class registers a custom "Book" type from an expression:
package com.example
import io.cucumber.java.ParameterType
import io.cucumber.java.en.Given
class StepDefinitions {
@ParameterType(".*")
fun book(bookName: String): Book {
return Book(bookName)
}
@Given("{book} is my favorite book")
fun this_is_my_favorite_book(book: Book) {
// step implementation
}
}
This class registers a custom type for a doc string:
package com.example
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import io.cucumber.java.DocStringType
import io.cucumber.java.en.Given
class StepsDefinitions {
companion object {
private val objectMapper = ObjectMapper()
}
@DocStringType
@Throws(JsonProcessingException::class)
fun json(docString: String): JsonNode {
return objectMapper.readValue(docString, JsonNode::class)
}
@Given("Books are defined by json")
fun books_are_defined_by_json(books: JsonNode) {
// step implementation
}
}
For lambda-defined step definitions, there are DataTableType
, ParameterType
and DocStringType
functions:
package com.example
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import io.cucumber.java8.En
class LambdaStepDefinitions : En {
init {
val objectMapper = ObjectMapper()
ParameterType("book", ".*") { s : String ->
Book(s)
}
DataTableType { entry: Map<String, String> ->
Author(entry["firstName"], entry["lastName"], entry["famousBook"])
}
DocStringType("json") { docString: String ->
objectMapper.readValue(docString, JsonNode::class)
}
}
}
Using the @DefaultParameterTransformer
, @DefaultDataTableEntryTransformer
and @DefaultDataTableCellTransformer
annotations, it is also possible to plug in an object mapper. The object mapper (Jackson in this example) will handle the conversion of anonymous parameter types and data table entries:
package com.example
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
class StepDefinitions {
private val objectMapper = ObjectMapper()
@DefaultParameterTransformer
@DefaultDataTableEntryTransformer
@DefaultDataTableCellTransformer
fun transformer(fromValue: Any, toValueType: Type): Any {
return objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
}
For lambda-defined step definitions, there are DefaultParameterTransformer
, DefaultDataTableCellTransformer
and DefaultDataTableEntryTransformer
methods:
import com.fasterxml.jackson.databind.ObjectMapper
import io.cucumber.java8.En
import java.lang.reflect.Type
class LambdaStepDefinitions : En {
init {
val objectMapper = ObjectMapper()
DefaultParameterTransformer { fromValue: String, toValueType: Type ->
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
DefaultDataTableCellTransformer { fromValue, toValueType ->
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
DefaultDataTableEntryTransformer { fromValue, toValueType ->
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
}
}
Data table and doc string types let you convert data tables and doc strings to objects. Like step definitions, type definitions are part of the glue. When placed on the glue path Cucumber will detect them automatically.
For example, the following class registers a custom "Author" data table type:
package com.example
import io.cucumber.scala.{ScalaDsl, EN}
class StepDefinitions extends ScalaDsl with EN {
DataTableType { entry: Map[String, String] =>
Author(
entry("firstName"),
entry("lastName"),
entry("famousBook"))
}
Given("There are my favorite authors") { authors: List[Author] =>
// step implementation
}
}
This class registers a custom "Book" type from an expression:
package com.example
import io.cucumber.scala.{ScalaDsl, EN}
class StepDefinitions extends ScalaDsl with EN {
ParameterType("book", ".*") { bookName: String =>
Book(bookName)
}
Given("{book} is my favorite book") { book: Book =>
// step implementation
}
}
This class registers a custom type for a doc string:
package com.example
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper
import io.cucumber.scala.{ScalaDsl, EN}
object StepsDefinitions {
private val objectMapper = ObjectMapper()
}
class StepsDefinitions extends ScalaDsl with EN {
DocStringType("json") { docString: String =>
objectMapper.readValue(docString, classOf[JsonNode])
}
Given("Books are defined by json") { books: JsonNode =>
// step implementation
}
}
Using the DefaultParameterTransformer
, DefaultDataTableEntryTransformer
and DefaultDataTableCellTransformer
methods, it is also possible to plug in an object mapper. The object mapper (Jackson in this example) will handle the conversion of anonymous parameter types and data table entries:
package com.example
import com.fasterxml.jackson.databind.ObjectMapper
import io.cucumber.scala.ScalaDsl
import java.lang.reflect.Type
class StepDefinitions extends ScalaDsl {
private val objectMapper = ObjectMapper()
DefaultParameterTransformer { (fromValue: String, toValueType: Type) =>
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
DefaultDataTableCellTransformer { (fromValue: String, toValueType: Type) =>
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
DefaultDataTableEntryTransformer { (fromValue: Map[String, String], toValueType: Type) =>
objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType))
}
}
If you want to, you can use the predefined JacksonDefaultDataTableEntryTransformer
trait which defines default transformers using Jackson Scala Module.
See the cucumber-js docs on GitHub for more on working with parameter types and data tables in JavaScript.
A parameter type lets you transform an argument from a string to another type before it's passed to the step definition.
For example, let's define our own "Person" type:
ParameterType(
name: 'person',
regexp: /[A-Z][a-z]+/,
transformer: -> (name) { Person.new(name) }
)
Here's an example of how to use this in a step definition:
Then /^a user {person} should have {int} followers$/ do |person, count|
assert(person.is_a?(Person))
end
If you try to use a type that has not yet been defined, you will see an error similar to:
The parameter type "person" is not defined.
Profiles​
- Java
- Kotlin
- Scala
- JavaScript
- Ruby
Cucumber profiles are not available on Cucumber-JVM. However, it is possible to set configuration options using Maven profiles
For instance, we can configure separate profiles for scenarios which are to be run in separate environments like so:
<profiles>
<profile>
<id>dev</id>
<properties>
<cucumber.filter.tags>@dev and not @ignore</cucumber.filter.tags>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<cucumber.filter.tags>@qa</cucumber.filter.tags>
</properties>
</profile>
</profiles>
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<systemPropertyVariables>
<cucumber.filter.tags>${cucumber.filter.tags}</cucumber.filter.tags>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
To mimick similar behavior using Gradle, see the Gradle docs on Migrating Maven profiles and properties.
Cucumber profiles are not available on Cucumber-JVM. However, it is possible to set configuration options using Maven profiles
For instance, we can configure separate profiles for scenarios which are to be run in separate environments like so:
<profiles>
<profile>
<id>dev</id>
<properties>
<cucumber.filter.tags>@dev and not @ignore</cucumber.filter.tags>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<cucumber.filter.tags>@qa</cucumber.filter.tags>
</properties>
</profile>
</profiles>
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<systemPropertyVariables>
<cucumber.filter.tags>${cucumber.filter.tags}</cucumber.filter.tags>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
To mimick similar behavior using Gradle, see the Gradle docs on Migrating Maven profiles and properties.
Cucumber profiles are not available on Cucumber-JVM. However, it is possible to set configuration options using Maven profiles
For instance, we can configure separate profiles for scenarios which are to be run in separate environments like so:
<profiles>
<profile>
<id>dev</id>
<properties>
<cucumber.filter.tags>@dev and not @ignore</cucumber.filter.tags>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<cucumber.filter.tags>@qa</cucumber.filter.tags>
</properties>
</profile>
</profiles>
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<systemPropertyVariables>
<cucumber.filter.tags>${cucumber.filter.tags}</cucumber.filter.tags>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
To mimick similar behavior using Gradle, see the Gradle docs on Migrating Maven profiles and properties.
You can specify configuration options for Cucumber in a cucumber.yml
or cucumber.yaml
file.
This file must be in a .config
directory, or config
subdirectory of your current working directory.
config/cucumber.yml
## ##YAML Template
html_report: --format progress --format html --out=features_report.html
bvt: --tags @bvt
Defining a template requires a name and then the command-line options that you want to execute with this profile.
The example above generates two profiles:
html_report
, with a list of command-line options that specify new output formats, andbvt
, which executes all Features and Scenarios tagged with@bvt
.
Cucumber-Rails creates a cucumber.yml
file in the project config directory containing a number of predefined profiles,
one of which is the default profile. When Cucumber is run from the command line, it is usually necessary to provide both
the directory name containing the root directory of the tree containing feature files and the directory name containing
references to the necessary library files. In a typical project, cucumber --require features features/some/path
will suffice.
Repetitious usages can be added to user-defined profiles contained in the project's cucumber.yml
file.
To execute the profile, use:
\[user@system project] cucumber --profile html_report
\[user@system project] cucumber -p bvt
Use the flag --profile
or -p
to execute Cucumber with a profile.
You can still use other command line arguments alongside --profile
or -p
,
if desired.
\[user@system project] cucumber --profile html_report --tags ~@wip
Multiple profiles can even be specified together. The following executes all
Features and Scenarios tagged @bvt
, with the specified progress and HTML
output.
\[user@system project] cucumber -p html_report -p bvt
Chances are you’ll want to execute Cucumber with a particular profile most of the time.
The Cucumber configuration file uses a default
profile to provide this functionality.
When you specify a default
profile, you are telling Cucumber to use the default
command-line options whenever you don't explicitly specify a different profile.
Using the same example, perhaps we want the html_report
profile to be our default execution.
1. config/cucumber.yml
## ##YAML Template
default: --profile html_report --profile bvt
html_report: --format progress --format html --out=features_report.html
bvt: --tags @bvt
\[user@system project] cucumber
With this setup, Cucumber will now use both the bvt
profile and html_report
profile, testing all Features and Scenarios tagged with @bvt
, along with the
progress output and HTML output.
The cucumber.yml
file is preprocessed by ERB (Embedded RuBy). This allows you to use Ruby code
to generate values in the cucumber.yml
file.
So, if you have several profiles with similar values, you might do this:
1. config/cucumber.yml
## ##YAML Template
<% common = "--tags ~@wip --strict" %>
default: <%= common %> features
html_report: <%= common %> --format html --out=features_report.html features
Environment variables​
- Java
- Kotlin
- Scala
- JavaScript
- Ruby
env
file.env
file.env
file.env
file.You can use environment variables in the profile argument list, just as you would normally specify them on the command-line.
1. config/cucumber.yml
\##YAML Template
2. ## ie profile executes the browser features with Internet Explorer
default: --profile html_report --profile bvt
html_report: --format progress --format html --out=features_report.html
bvt: --tags @bvt
ie: BROWSER=IE
When running Cucumber, it can sometimes be handy to pass special values to Cucumber for your step definitions to use.
You can do this on the command line:
cucumber FOO=BAR --format progress features
You can now pick up ENV\['FOO']
in Ruby (for example, in env.rb
, or a Step Definition) and perform actions according to the value.
You can also do this in cucumber.yml
.
For example, the following sets up a profile that runs the specified Tag and sets an environment variable:
baz: --tags @mytag FOO=BAR
Local Cucumber customisation code in support/env.rb
itself as that file is typically
overwritten by script/generate cucumber:install | rails g cucumber
. Customisations that
must be loaded before the rest of Cucumber initialises must be placed at the beginning of the env.rb file
.
Every file ending in .rb
that is found in features/support is loaded by Cucumber. Therefore, if you place local
customisations in any .rb
file in that directory, they will get loaded. However, be advised that in
Cucumber < 4.x, the --dry-run
option only excludes files in features/support
that match the regexp /env\\..\*/
(note that the trailing dot is significant). So a file with local customisations called my_locals.rb
will be loaded regardless.
In Cucumber 4.x, all support files, including env.rb
files, are loaded.
If you put custom files inside features/support
that you do not wish loaded when you do a dry-run with Cucumber,
you can use the --exclude
flag to ensure they aren't loaded. In Cucumber versions < 4.x, you can also prefix the filenames
with env
, as in env.local.rb
. Note that a file called local_env.rb
, for example, does not match the regex
above and therefore will be loaded in all versions of Cucumber unless specifically excluded.
As a matter of good practice you should always run script/generate cucumber | rails g cucumber:install
whenever you
install an updated version of Cucumber or cucumber-rails. However, this overwrites features/support/env.rb
.
In order to keep any custom configurations from your env.rb
file, check in your env.rb
along with the rest of your version
controlled files and be prepared to diff and merge changes to env.rb
between versions of Cucumber-Rails.