Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@cucumber/cucumber-expressions

cucumber5.8mMIT18.0.1TypeScript support: included

Cucumber Expressions - a simpler alternative to Regular Expressions

cucumber, steps, regexp, regex

readme

test-go test-java test-javascript test-python test-ruby test-dotnet

Cucumber Expressions

Cucumber Expressions is an alternative to Regular Expressions with a more intuitive syntax.

Try Cucumber Expressions in your browser.

Cucumber supports both Cucumber Expressions and Regular Expressions for defining Step Definitions, but you cannot mix Cucumber Expression syntax with Regular Expression syntax in the same expression.

On platforms that don't have a literal syntax for regular expressions (such as Java), Cucumber will create a Cucumber Expression by default. To use Regular Expressions, add anchors (starting with ^ and ending with $) or forward slashes (/). For more information, see Cucumber Expression - Java Heuristics.

Introduction

Let's write a Cucumber Expression that matches the following Gherkin step (the Given keyword has been removed here, as it's not part of the match).

I have 42 cucumbers in my belly

The simplest Cucumber Expression that matches that text would be the text itself, but we can also write a more generic expression, with an int output parameter:

I have {int} cucumbers in my belly

When the text is matched against that expression, the number 42 is extracted from the {int} output parameter and passed as an argument to the step definition.

The following text would not match the expression:

I have 42.5 cucumbers in my belly

This is because 42.5 has a decimal part, and doesn't fit into an int. Let's change the output parameter to float instead:

I have {float} cucumbers in my belly

Now the expression will match the text, and the float 42.5 is extracted.

Parameter types

Text between curly braces reference a parameter type. Cucumber comes with the following built-in parameter types:

Parameter Type Description
{int} Matches integers, for example 71 or -19. Converts to a 32-bit signed integer if the platform supports it.
{float} Matches floats, for example 3.6, .8 or -9.2. Converts to a 32 bit float if the platform supports it.
{word} Matches words without whitespace, for example banana (but not banana split).
{string} Matches single-quoted or double-quoted strings, for example "banana split" or 'banana split' (but not banana split). Only the text between the quotes will be extracted. The quotes themselves are discarded. Empty pairs of quotes are valid and will be matched and passed to step code as empty strings.
{} anonymous Matches anything (/.*/).
{bigdecimal} Matches the same as {float}, but converts to a BigDecimal if the platform supports it.
{double} Matches the same as {float}, but converts to a 64 bit float if the platform supports it.
{biginteger} Matches the same as {int}, but converts to a BigInteger if the platform supports it.
{byte} Matches the same as {int}, but converts to an 8 bit signed integer if the platform supports it.
{short} Matches the same as {int}, but converts to a 16 bit signed integer if the platform supports it.
{long} Matches the same as {int}, but converts to a 64 bit signed integer if the platform supports it.

Java

The Anonymous Parameter

The anonymous parameter type will be converted to the parameter type of the step definition using an object mapper. Cucumber comes with a built-in object mapper that can handle all numeric types as well as. Enum.

To automatically convert to other types it is recommended to install an object mapper. See cucumber-java - Default Transformers to learn how.

Number formats

Java supports parsing localised numbers. I.e. in your English feature file you can format a-thousand-and-one-tenth as '1,000.1; while in French you would format it as '1.000,1'.

Parsing is facilitated by Javas DecimalFormat and includes support for the scientific notation. Unfortunately the default localisation include symbols that can not be easily written on a regular keyboard. So a few substitutions are made:

  • The minus sign is always hyphen-minus - (ascii 45).
  • If the decimal separator is a period (. ascii 46) the thousands separator is a comma (, ascii 44). So '1 000.1' and '1’000.1' should always be written as '1,000.1'.
  • If the decimal separator is a comma (, ascii 44) the thousands separator is a period (. ascii 46). So '1 000,1' or '1’000,1' should always be written as '1.000,1'.

If support for your preferred language could be improved, please create an issue!

Custom Parameter types

Cucumber Expressions can be extended so they automatically convert output parameters to your own types. Consider this Cucumber Expression:

I have a {color} ball

If we want the {color} output parameter to be converted to a Color object, we can define a custom parameter type in Cucumber's configuration.

The table below explains the various arguments you can pass when defining a parameter type.

Argument Description
name The name the parameter type will be recognised by in output parameters.
regexp A regexp that will match the parameter. May include capture groups.
type The return type of the transformer.
transformer A function or method that transforms the match from the regexp. Must have arity 1 if the regexp doesn't have any capture groups. Otherwise the arity must match the number of capture groups in regexp.
useForSnippets / use_for_snippets Defaults to true. That means this parameter type will be used to generate snippets for undefined steps. If the regexp frequently matches text you don't intend to be used as arguments, disable its use for snippets with false.
preferForRegexpMatch / prefer_for_regexp_match Defaults to false. Set to true if you have step definitions that use regular expressions, and you want this parameter type to take precedence over others during a match.

Java

@ParameterType("red|blue|yellow")  // regexp
public Color color(String color){  // type, name (from method)
    return new Color(color);       // transformer function
}

Kotlin

@ParameterType("red|blue|yellow")   // regexp
fun color(color: String): Color {   // name (from method), type
    return Color(color)             // transformer function
}                                    

Scala

ParameterType("color", "red|blue|yellow") { color: String => // name, regexp
    Color(color)                                             // transformer function, type
}                                    

JavaScript / TypeScript

import { defineParameterType } from '@cucumber/cucumber'

defineParameterType({
    name: 'color',
    regexp: /red|blue|yellow/,
    transformer: s => new Color(s)
})

The transformer function may return a Promise.

Ruby

ParameterType(
  name:        'color',
  regexp:      /red|blue|yellow/,
  type:        Color,
  transformer: ->(s) { Color.new(s) }
)

.NET / SpecFlow

[StepArgumentTransformation("(red|blue|yellow)")]
public Color ConvertColor(string colorValue)
{
    return new Color(colorValue);
}

Note: Currently the parameter name cannot be customized, so the custom parameters can only be used with the type name, e.g. {Color}.

Python

ParameterType(
  name=        "color",
  regexp=      "red|blue|yellow",
  type=        Color,
  transformer= lambda s: Color(s),
)

Optional text

It's grammatically incorrect to say 1 cucumbers, so we should make the plural s optional. That can be done by surrounding the optional text with parentheses:

I have {int} cucumber(s) in my belly

That expression would match this text:

I have 1 cucumber in my belly

It would also match this text:

I have 42 cucumbers in my belly

In Regular Expressions, parentheses indicate a capture group, but in Cucumber Expressions they mean optional text.

Alternative text

Sometimes you want to relax your language, to make it flow better. For example:

I have {int} cucumber(s) in my belly/stomach

This would match either of those texts:

I have 1 cucumber in my belly
I have 1 cucumber in my stomach
I have 42 cucumbers in my stomach
I have 42 cucumbers in my belly

Alternative text only works when there is no whitespace between the alternative parts.

Escaping

If you ever need to match () or {} literally, you can escape the opening ( or { with a backslash:

I have {int} \{what} cucumber(s) in my belly \(amazing!)

This expression would match the following examples:

I have 1 {what} cucumber in my belly (amazing!)
I have 42 {what} cucumbers in my belly (amazing!)

You may have to escape the \ character itself with another \, depending on your programming language. For example, in Java, you have to use escape character \ with another backslash.

I have {int} \\{what} cucumber(s) in my belly \\(amazing!)

Then this expression would match the following example:

I have 1 \{what} cucumber in my belly \(amazing!)
I have 42 \{what} cucumbers in my belly \(amazing!)

The / character will always be interpreted as an alternative, unless escaped, such as with \/.

Architecture

See ARCHITECTURE.md

Acknowledgements

The Cucumber Expression syntax is inspired by similar expression syntaxes in other BDD tools, such as Turnip, Behat and Behave.

Big thanks to Jonas Nicklas, Konstantin Kudryashov and Jens Engel for implementing those libraries.

The Tiny-Compiler-Parser tutorial by Yehonathan Sharvit inspired the design of the Cucumber expression parser.

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

Unreleased

18.0.1 - 2024-10-28

Fixed

  • [Python] Release process didn't release to pypi correctly

18.0.0 - 2024-10-24

Changed

  • [Ruby] Minimum supported ruby is now 2.7+ (#308)

17.1.0 - 2024-03-21

Added

  • [Java] Assume numbers use either a comma or period for the thousands separator instead of non-breaking spaces. (#290)

Fixed

  • [Java] Parse negative numbers in Norwegian (and 59 other languages) (#290)
  • [Python] Remove support for Python 3.7 and extend support to 3.12 (#280)
  • [Python] The ParameterType constructor's transformer should be optional (#288)

17.0.2 - 2024-02-20

Changed

  • [Python] Updated the release workflow to use trusted publisher (#263, #264)
  • [Ruby] Added subsidiary rubocop gems (RSpec/Rake/Performance), and did some initial refactoring (#247)
  • Additional information for alternation inside optional error message on how to fix (#260)

Fixed

  • Removed repeated 'the' from error message for use of alternations inside optionals (#252)
  • [Python] Missing keyword argument defaults in parameter type class (#259)
  • [Ruby] Added an explicit dependency on bigdecimal gem, to fix Ruby 3.4-pre builds where the gem has changed its status from default to bundled (#273)

17.0.1 - 2023-11-24

Fixed

  • [JavaScript] Fix import paths lacking file suffix (#243)
  • [Ruby] Fixed up Layout rubocop autofixes

17.0.0 - 2023-10-06

Changed

  • [JavaScript] Added TypeScript source to the package (#211)
  • [Ruby] Minimum supported ruby is now 2.5+ (#232)
  • [Ruby] Large suite wide refactor for basic rubocop compliance (#233 #235)
  • [Ruby] Expose ParameterType#transformer as a new public reader (#234)
  • [Ruby] Remove ParameterType#prefer_for_regexp_match? and ParameterType#use_for_snippets? -> Use their standard reader equivalents instead (Remove the ?) (#234)

16.1.2 - 2023-01-17

Fixed

  • [Java] Improve cucumber expression creation performance (#202)

16.1.1 - 2022-12-08

Fixed

  • [Java] Improve expression creation performance (#187, #189)

16.1.0 - 2022-11-28

Added

  • [Java] Enabled reproducible builds
  • [JavaScript] Added ParameterType.builtin. This is to allow JSON serialization of only the non-builtin parameter types.

16.0.1 - 2022-11-06

Fixed

  • [JavaScript] The ParameterType constructor's transform, useForSnippets and preferForRegexpMatch should be optional. (#178)

16.0.0 - 2022-06-12

Changed

  • [JavaScript] The ParameterType constructor's regexps parameter has a new type: type Regexps = StringOrRegExp | readonly StringOrRegExp[]; type StringOrRegExp = string | RegExp.

15.2.0 - 2022-05-24

Added

  • [JavaScript] Add ParameterInfo (#124)

Fixed

  • [.NET] Fix casing in "word" parameter type constant

15.1.1 - 2022-04-21

Fixed

  • [JavaScript] Make CucumberExpression.ast public (it was accidentally private in 15.1.0)

15.1.0 - 2022-04-21

Added

  • [JavaScript] Add CucumberExpression.ast and expose the AST types.

15.0.2 - 2022-03-15

Fixed

  • Add missing name field in CommonJS package file (#87)

15.0.1 - 2022-01-04

Fixed

  • Fixed release scripts

15.0.0 - 2022-01-04

Added

  • [Ruby,JavaScript,Go] Add bigdecimal, biginteger parameter types (#42)
  • [.NET] Implementation of Cucumber Expressions by porting the Java parser (#1743)
  • [Python] Added Python Cucumber Expressions (#65)

Changed

  • [Go] Parameters of type {float} are now parsed as float32 (previously it was float64). Use {double} if you need float64. (#42)

14.0.0 - 2021-10-12

Changed

  • TypeScript: Group#value can no longer be undefined (#16)
  • TypeScript: Argument is no longer generic (#16)
  • Go: Module renamed to match github repository(#24)

13.1.3 - 2021-09-24

Fixed

  • Fix release for the Go implementation

13.1.2 - 2021-09-24

Fixed

  • Fix release for the Go implementation
  • Minor fixes in the README.md links to documentation

13.1.1 - 2021-09-24

Fixed

  • Fix misc release actions

13.1.0 - 2021-09-24

Added

  • [JavaScript] Support for EcmaScript modules (aka ESM). (#1743)

13.0.1 - 2021-09-15

Changed

Fixed

Removed

  • Remove deprecated CucumberExpressionGenerator#generateExpression method. (#1752)

12.1.3 - 2021-09-01

Fixed

12.1.2 - 2021-08-17

Changed

  • [Go] Move module paths to point to monorepo (#1550)
  • [Java] Upgraded apiguardian to v1.1.2

12.1.1 - 2021-04-06

Fixed

  • [Ruby] use Array#select instead of Array#filter. The latter is an alias that was introduced in Ruby 2.6.0. (aslakhellesoy)

12.1.0 - 2021-04-06

Added

  • [Ruby] Add UndefinedParameterTypeError#undefined_parameter_type_name (#1460 aslakhellesoy)

12.0.1 - 2021-04-06

Fixed

  • [JavaScript] Fix issue with some files may not appear in published package (#1452)
  • [Java] Support character in BuiltInParameterTransformer. (#1405)

12.0.0 - 2021-02-09

Changed

11.0.2 - 2021-02-09

Fixed

  • [JavaScript] revert breaking changes in 11.0.1 (#1352)

11.0.1 - 2021-02-07

Fixed

11.0.0 - 2020-12-10

Added

Changed

  • Some expressions that were valid in previous versions may now be invalid
  • Some expressions that were invalid in previous versions may now be valid

Fixed

  • [Go, Java, JavaScript, Ruby] New handwritten parser, which fixes several long-standing bugs. (#601 #726 #767 #770 #771 mpkorstanje)
  • [Go] Support for Go 1.15

Removed

  • [JavaScript] Removed webpacked JavaScript from distribution

10.3.0 - 2020-08-07

Added

  • [JavaScript] export GeneratedExpression

10.2.2 - 2020-07-30

Fixed

10.2.1 - 2020-06-23

Fixed

10.2.0 - 2020-05-28

Added

  • [Java] Add support for Optional (#1006 gaeljw, mpkorstanje)
  • [Java] Enable consumers to find our version at runtime using clazz.getPackage().getImplementationVersion() by upgrading to cucumber-parent:2.1.0 (#976 aslakhellesoy)

10.1.0 - 2020-04-14

Changed

  • [Java] CucumberExpression and RegularExpression are now public.

Fixed

  • [Java] Minor performance improvement for matching regular expressions steps.

10.0.0 - 2020-03-31

Changed

  • [JavaScript] All array return values and function parameters are now declared as TypeScript ReadOnlyArray

9.0.0 - 2020-02-14

Added

  • [JavaScript, Ruby] Added ExpressionFactory, which is now the preferred way to create Expression instances.

Deprecated

  • [Ruby] CucumberExpression and RegularExpression constructors should not be used directly. Use ExpressionFactory#create_expression instead.

Removed

  • [Java, JavaScript] CucumberExpression and RegularExpression are no longer part of the public API.
  • [JavaScript] remove support for Node 8, which is now EOL

8.3.1 - 2020-01-10

8.3.0 - 2019-12-10

Added

  • [JavaScript] export Argument, Group and Expression types

8.2.1 - 2019-11-11

Fixed

  • Fix webpack packaging (simplify by assigning to window.CucumberExpressions)

8.2.0 - 2019-11-11

Added

8.1.0 - 2019-10-31

Added

  • Expose Argument#getParameterType() method. Needed by Cucumber protobuf formatters. (#781 aslakhellesoy)

8.0.2 - 2019-10-28

Fixed

  • [Go] Change Go module name to github.com/cucumber/cucumber-expressions-go/v8 (aslakhellesoy)
  • Fix captured empty strings being undefined (#746 #754 davidjgoss)

8.0.1 - 2019-10-07

Fixed

8.0.0 - 2019-08-11

Added

Changed

Fixed

7.0.2 - 2019-06-15

Fixed

  • Support Boolean in BuiltInParameterTransformer (#604 tommywo)

7.0.0 - 2019-03-22

Fixed

  • Javascript release process
  • Version numbering 🙈

6.6.2 - 2019-03-22

6.2.3 - 2019-03-22

Fixed

  • Ruby release process working again

6.2.2 - 2019-03-16

Changed

Fixed

6.2.1 - 2018-11-30

Fixed

  • (Java) Improve heuristics for creating Cucumber/Regular Expressions from strings (#515 #518 aslakhellesoy)

6.2.0 - 2018-10-28

Added

6.1.2 - 2018-10-11

6.1.1 - 2018-10-11

Fixed

  • (Java) Add the ability to supply an alternative algorithm for compiling java.util.regex.Pattern to work around a limitation on Android (and other platforms). (#494 #498 lsuski)

6.1.0 - 2018-09-23

Added

  • (Java) Added ParameterType.fromEnum(MyEnumClass.class) to make it easier to register enums. (#423 aslakhellesoy)

Fixed

  • java: The text between () (optional text) can be unicode. (#473 savkk
  • The built-in {word} parameter type handles unicode (any non-space character) (#471 savkk
  • Parenthesis inside character class should not be treated as capture group. (#454 #461 #463 #464 aidamanna spicalous)

Removed

6.0.1 - 2018-06-14

Added

  • Allow ParameterType with no name (nil, null, ""). Useful when the Parameter Type is only used in conjunction with Regular Expressions. (#387 #410 aslakhellesoy)

Fixed

6.0.0 - 2018-05-30

Changed

  • Throw an error if a parameter type is used inside optional text parenthesis, or with alternative text. (#360 aslakhellesoy)

Fixed

5.0.19 - 2018-05-24

Fixed

  • java: Escape closing braces to avoid PatternSyntaxException on Android

5.0.18 - 2018-05-21

Changed

  • java: The {byte} parameter type no longer uses hexadecimal, but uses the same pattern as {short}, {int} and {long}.

Fixed

  • The / character can be escaped with \/ in order to keep a literal / rather than interpreting it as alternation character. Generated expressions will use \/ if the original text contains /. (#391 #392 aslakhellesoy)

5.0.17 - 2018-04-12

Changed

  • java: Swapped 2 parameters in a ParameterType constructor to make it consistent with overloaded constructors.

5.0.16 - 2018-04-12

Changed

  • java: Renamed {bigint} to {biginteger} ([mpkorstanje, aslakhellesoy])
  • java: The API uses Transformer for transforms with 0-1 capture groups, and CaptureGroupTransformer for 2+ capture groups.

Fixed

  • java: Better error message when users leave anchors (^ and $) in their regular expressions (aslakhellesoy)
  • java: {bigdecimal} would only match integers ([mpkorstanje, aslakhellesoy])
  • java: {byte} is suggested in snippets (mpkorstanje)

5.0.15 - 2018-04-08

Added

Changed

5.0.14 - 2018-04-04

Added

Fixed

  • Generated expressions escape ( and { if they were present in the text. (#345 aslakhellesoy)

Removed

5.0.13 - 2018-01-21

Fixed

  • Fixed yet another regression introduced by #324 and simplified capture group parsing in TreeRegexp to reduce likelihood of more bugs.

5.0.12 - 2018-01-19

Fixed

5.0.11 - 2018-01-19

Fixed

5.0.10 - 2018-01-19

Fixed

5.0.7 - 2017-11-29

Fixed

  • ruby: Only disallow Regexp::EXTENDED, Regexp::IGNORECASE and Regexp::MULTILINE in ParameterType regexps. Other flags such as Regexp::NOENCODING and Regexp::FIXEDENCODING are OK.

5.0.6 - 2017-11-28

Fixed

  • javascript: Backport RegExp#flags for Node 4.x

5.0.5 - 2017-11-28

Fixed

  • ruby: Fix typo in ParameterType error message. (#306 aslakhellesoy, luke-hill)
  • Ignore ParameterTypes with optional capture groups when generating snippets. Trying to do so caused an infinite loop. (#307 aslakhellesoy)
  • Throw an error when ParameterType regexps have flags. Flags are not allowed because only the source of the regexp is used to build a new regexp for the entire Cucumber Expression. See #308. (aslakhellesoy)

5.0.4 - 2017-11-28

Fixed

  • Cucumber Expressions with alternation (I said Alpha1/Beta1) now works with more than just letters - it works with anything that isn't a space. (#303 by aslakhellesoy)

5.0.3 - 2017-11-06

Fixed

5.0.2 - 2017-10-20

Fixed

5.0.0 - 2017-10-10

Changed

  • ruby, javascript: A transformer function can run in the context of a world object. Argument#value now takes an object as argument (renamed to Argument#getValue in js) (#284 by aslakhellesoy)

4.0.4 - 2017-10-05

Changed

Fixed

4.0.3 - 2017-07-24

Fixed

  • javascript: Expose Argument.group and fix start and end accessors in Group

4.0.2 - 2017-07-14

Fixed

  • javascript: Make it work on Node 4 and browser (Use Array.indexOf instead of Array.includes) (#237 by aslakhellesoy)

4.0.1 - 2017-07-14

Fixed

4.0.0 - 2017-06-28

Added

Changed

Fixed

Removed

  • Remove support for {name:type} syntax which was deprecated in #117 and released in 2.0.0. (#180 by aslakhellesoy)
  • Removed support for {undefined} parameter types. If a parameter type is not defined, and error will be raised.

3.0.0 - 2017-03-08

Added

  • Alternative text: I have a cat/dog/fish (by aslakhellesoy)
  • type / constructorFunction: Makes it simpler to use in languages without static types
  • transform: Leave arguments unchanged, return as string (by aslakhellesoy)
  • ParameterType can be constructed with null/nil arguments for

Changed

  • Parameter -> ParameterType
  • ParameterRegistry -> ParameterTypeRegistry
  • addParameter -> defineParameterType
  • Renamed API:
  • Stricter conflict checks when defining parameters (#121 by aslakhellesoy)

Fixed

Removed

  • java: Drop support for Java 7 (Java 8 or higher is required)

2.0.1 - 2017-02-17

Added

Changed

Fixed

Removed

2.0.0 - 2017-02-17

Added

Changed

Fixed

Removed

1.0.4 - 2017-01-20

Added

Changed

  • ruby: Use Integer instead of Fixnum

Fixed

  • Handle multiple capture group regexps for matching (#102 by gpichot)
  • Make the tests pass on Ruby 2.4.0 (as well as older rubies)

Removed

1.0.3 - 2016-11-25

Added

Changed

Fixed

Removed

1.0.2 - 2016-11-23

Added

Changed

Fixed

Removed

1.0.1 - 2016-09-28

Added

  • First stable release!