Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues when migrating to Cucumber 3.x.x/4.x.x from cucumber 2.x.x #1478

Closed
cliviu opened this issue Oct 7, 2018 · 8 comments · Fixed by #1492
Closed

Issues when migrating to Cucumber 3.x.x/4.x.x from cucumber 2.x.x #1478

cliviu opened this issue Oct 7, 2018 · 8 comments · Fixed by #1492

Comments

@cliviu
Copy link
Contributor

cliviu commented Oct 7, 2018

Summary

In cucumber-jvm 2.x.x, I had a step defined like this:

    @Then("^his country risk factor should be (.*)$")
    public void his_country_risk_factor_should_be(float rating) {
    } 

When running the tests with Cucumber 3.x.x , I got this error

cucumber.runtime.CucumberException: Failed to invoke acceptancetests.reporting_controls.StepDefinitions.his_country_risk_factor_should_be(float) in ..., caused by java.lang.IllegalArgumentException: argument type mismatch
        at cucumber.runtime.Utils$1.call(Utils.java:29)
        at cucumber.runtime.Timeout.timeout(Timeout.java:16)
        at cucumber.runtime.Utils.invoke(Utils.java:20)
        at cucumber.runtime.java.JavaStepDefinition.execute(JavaStepDefinition.java:48)
        at cucumber.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:50)
        at cucumber.runner.TestStep.executeStep(TestStep.java:63)
        at cucumber.runner.TestStep.run(TestStep.java:49)
        at cucumber.runner.PickleStepTestStep.run(PickleStepTestStep.java:43)
        at cucumber.runner.TestCase.run(TestCase.java:44)
        at cucumber.runner.Runner.runPickle(Runner.java:40)
        at cucumber.runtime.junit.PickleRunners$NoStepDescriptions.run(PickleRunners.java:146)
        at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:68)
        at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:23)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:73)

Expected Behavior

  • existing cucumber-jvm tests will run with no change when upgrading to cucumber-jvm 3.x.x/4.x.x

Current Behavior

  • exception thrown when running the old tests with the new cucumber implementation

Possible Solution

  • the only solution that I have found is to modify the step definition like this :
@Then("his country risk factor should be {float}")
  public void his_country_risk_factor_should_be(float rating) {
  } 

Context & Motivation

The problem is that upgrading to newer cucumber version breaks the existing tests. For some projects, updating a large number of tests can be a real problem.

@aslakhellesoy
Copy link
Contributor

Cucumber uses semantic versioning, which means that a major version increment has backwards incompatible changes. You should expect to have to make changes when upgrading a major version.

In v3 the type conversion happened in Cucumber, based on the type information from the method's parameters. In v4 the type conversion happens in the Cucumber-Expressions library, which doesn't have access to the method's parameters.

It is possible to implicitly refer to parameter types from stepdefs using regular expressions by using capture group patterns identical to a parameter type.

If you change (.*) to (-?\d*[.,]\d+) the built-in {float} parameter type will kick in. Beware that this is not a documented part of the API and may change.

We could make a change to Cucumber-Expressions so that Expression#match(String) becomes Expression#match(String,List<Type>). This would allow Cucumber to pass in types from the method parameters.

WDYT @mpkorstanje?

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Oct 7, 2018

In principle I could see that work for regular expressions. The type hint
would also allow us to type check cucumber expressions too to create clear error messages.

But as of yet I don't quite see how the type hint and type indicated by the cucumber expression should interact. Or how this system can give clear feedback on what it does, tried to do and why it failed when it does.

The hint should ofc. be optional to handle weakly typed JVM Lang's.

Executing the transform to the hinted type does require an object mapper. And here we should avoid all the mistakes by the XStream implementation. So:

  1. The object mapper should be pluggable.
  2. The object mapper should be configurable.
  3. The same object mapper should be used for datatables.
  4. The default provided object mapper should be bare bones and well documented. Just enough to handle all the basic types and thus not nessary when cucumber expressions are used.
  5. The default object mapper comes with cucumber-expressions and can be overridden. We install this as the default object mapper for datatable cells too.

If you want to jak shave this doing the bare bones mapper and type hint for regular expressions aswell as the type checking for cucumber expressions should be a good start.

I think the other stuff requires breaking changes anyway.

@mpkorstanje
Copy link
Contributor

Comes to mind that cucumber expressions currently transforms a list of capture groups to objects.

For most cases this is a single string so for all the basic types cucumber expressions could also use the bare bones object mapper with String --> Object, and for multiple String[] -> Object. Assuming there is no expression defined ofc.

This would avoid allot of annoying inconsistencies and would let us extract the locale from the parameter type registery.

@mpkorstanje
Copy link
Contributor

And with that in mind an anonymous cucumber expression parameter {} that translates to (.*) that only uses the type hint would be good too.

@cliviu
Copy link
Contributor Author

cliviu commented Oct 8, 2018

Thank you very much for your explanations ! Please let me know in this thread if there is any chance of supporting this backward compatibility in one of the next versions. As I said, there are some projects outthere which are having troubles upgrading a large number of tests. Thanks !

@mlvandijk
Copy link
Member

Related: cucumber/docs#142

mpkorstanje pushed a commit to cucumber/common that referenced this issue Oct 13, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit to cucumber/common that referenced this issue Oct 13, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit that referenced this issue Oct 27, 2018
mpkorstanje added a commit to cucumber/common that referenced this issue Oct 27, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit to cucumber/common that referenced this issue Oct 27, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit to cucumber/common that referenced this issue Oct 27, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit to cucumber/common that referenced this issue Oct 27, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit to cucumber/common that referenced this issue Oct 27, 2018
Introduces the anonymous parameter to cucumber expressions. This is
a breaking change because we're installing a new expression in the
parameter type registry.

\#\# Details ##

Installs the anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```
For Javascript and Ruby this will merely returns the captured text as
a string.

However for strongly typed languages like Java and Go this make this
allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example in Java the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #493

\#\# Motivation and Context \#\#

To make it easier to upgrade from Cucumber-JVM v3 to v4.
See cucumber/cucumber-jvm#1478 for details.
mpkorstanje added a commit that referenced this issue Oct 27, 2018
Cucubumber expressions installs the  anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```

This allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #1478
mpkorstanje added a commit that referenced this issue Oct 29, 2018
Cucubumber expressions installs the  anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```

This allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #1478
mpkorstanje added a commit that referenced this issue Oct 29, 2018
Cucubumber expressions installs the  anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```

This allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #1478
mpkorstanje added a commit that referenced this issue Oct 29, 2018
Cucubumber expressions installs the  anonymous parameter type into the registry:
```java
ParameterType(
  name: ""
  regexps: [\.*\]
  transformer: s -> s
  useForSnippets: false
  preferForRegexMatch: true
)
```

This allows the step definition to hint the type to which the captured text
should be converted. When used in conjunction with an object mapper
this makes it easier to quickly define step definitions without the need
to define parameter types for each type. For example the following
will work without the need to configure additional parameter types.

```java
Given("^there is some date (.*)$", (Date a) -> { })

Given("there is some date {}", (Date a) -> { })

Given("there is some transaction {} {}", (BigDecimal a, Currency b) -> { })

Given("there is some type {}", (TypeEnum a) -> { })
```

To make the dynamic transform possible type hints are passed to the cucumber
expression when matching a step. Using these hints the `s -> s` transform is
replaced with `s -> defaultTransform.transform(s, typeHint)`. A simple
implementation of the `defaultTransform` is provided that supports a selection
of primitives but should generally speaking be replaced with a proper object mapper.

Fixes: #1478
@mpkorstanje
Copy link
Contributor

4.2.0 has been released. Release notes can be found here:

https://github.com/cucumber/website/pull/317

@lock
Copy link

lock bot commented Oct 31, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants