Search code examples
regexcucumber-java

Are cucumber expressions interact somehow with regular expression?


After moving from Cucumber-JVM 2.X to Cucumber-JVM 5.5.0 I'm faced problem with existing step defs which use regular expression and optional capture group.
For version 2.X when there is no optional text in gherkin step then step definition method got null value.
For version 5.5.0 if I don't supply optional text in gherkin step then I ended up with exception.

Scenario

Scenario: cucumber expression vs regular expression
  And text aaaa text2
  And text text2

GlueCode

@Given("^text(?: (.+))? text2$")
public void optionalCaptureGroup(String optionalGroup) {
    System.out.println(optionalGroup);
}


@ParameterType(".+")
public String paramType1(String s) {
    return s;
}

Exception

 io.cucumber.core.exception.CucumberException: Could not convert arguments for step [^text(?: (.+))? text2$] defined at 'migrate.ParameterTypeStepDefinition.optionalCaptureGroup(java.lang.String)'.
The details are in the stacktrace below.
    at io.cucumber.core.runner.PickleStepDefinitionMatch.couldNotConvertArguments(PickleStepDefinitionMatch.java:119)
    at io.cucumber.core.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:56)
    at io.cucumber.core.runner.TestStep.executeStep(TestStep.java:64)
    at io.cucumber.core.runner.TestStep.run(TestStep.java:49)
    at io.cucumber.core.runner.PickleStepTestStep.run(PickleStepTestStep.java:46)
    at io.cucumber.core.runner.TestCase.run(TestCase.java:51)
    at io.cucumber.core.runner.Runner.runPickle(Runner.java:66)
    at io.cucumber.core.runtime.Runtime.lambda$run$2(Runtime.java:100)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
    at java.util.concurrent.FutureTask.run(FutureTask.java)
    at io.cucumber.core.runtime.Runtime$SameThreadExecutorService.execute(Runtime.java:243)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
    at io.cucumber.core.runtime.Runtime.lambda$run$3(Runtime.java:100)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.stream.SliceOps$1$1.accept(SliceOps.java:204)
    at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359)
    at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at io.cucumber.core.runtime.Runtime.run(Runtime.java:101)
    at io.cucumber.core.cli.Main.run(Main.java:75)
    at io.cucumber.core.cli.Main.main(Main.java:31)
Caused by: io.cucumber.cucumberexpressions.CucumberExpressionException: ParameterType {paramType1} failed to transform [] to class java.lang.String
    at io.cucumber.cucumberexpressions.ParameterType.transform(ParameterType.java:237)
    at io.cucumber.cucumberexpressions.Argument.getValue(Argument.java:67)
    at io.cucumber.core.stepexpression.ExpressionArgument.getValue(ExpressionArgument.java:15)
    at io.cucumber.core.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:47)
    ... 25 more
Caused by: io.cucumber.core.backend.CucumberBackendException: Failed to invoke public java.lang.String migrate.ParameterTypeStepDefinition.paramType1(java.lang.String)
    at io.cucumber.java.Invoker.invoke(Invoker.java:29)
    at io.cucumber.java.JavaParameterTypeDefinition.execute(JavaParameterTypeDefinition.java:81)
    at io.cucumber.cucumberexpressions.ParameterType.transform(ParameterType.java:233)
    ... 28 more
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at io.cucumber.java.Invoker.invoke(Invoker.java:27)
    ... 30 more

My questions are:
1. why I'm getting exception about wrong number of arguments - were there any changes in handling of optional capturing group since version 2.X?
2. Why cucumber want to interact with custom type parameter in the case when step definition use pure regular expression?


Solution

  • So I deleted my previous answer because it was wrong. Looks like there is a bug in the way Cucumber handles optional parameter types.

    You can work around it by defining a parameter type that takes an array as an argument.

        @ParameterType(value = ".+")
        public String paramType1(String... s) {
            if (s.length > 0) {
                return s[0];
            }
            return null;
        }
    

    Normally this would be used for parameter types with multiple capture groups but it works in these circumstances too.

        @ParameterType(value = "([a-z]+)([0-9]+)")
        public String paramType1(String... s) {
    
        }