cucumber / cucumber-jvm-scala Goto Github PK
View Code? Open in Web Editor NEWCucumber Scala
Home Page: https://cucumber.io/
License: MIT License
Cucumber Scala
Home Page: https://cucumber.io/
License: MIT License
From cucumber/cucumber-jvm#1075
Summary
I have found that the Scala step classes are required to have a no-args constructor, but I'd like to be able to have my glue classes depend on one another like the Java glue can.
From the Java docs:
we strongly recommend you include one of the Dependency Injection modules as well. This allows you to share state between Step Definitions without resorting to static variables (a common source of flickering scenarios).
val dslClasses = packages flatMap { classFinder.getDescendants(classOf[ScalaDsl], _) } filter { cls => try { cls.getDeclaredConstructor() true } catch { case e : Throwable => false } }
This
filter
will silently ignore any Step classes which do not have a no-args constructor.See also #755 for another difference between Scala and Java here.
Expected Behavior
- I'd expect to be able to add a Glue class as a constructor param to a Step class, and have the DI framework create and inject an instance, like the Java API allows:
class MySteps(connector: MyConnector) { Given("""^some setup$"""){ () => connector.something() } }
- Also, I think that the
filter
above ought to print a warning when a Glue class that inherits fromScalaDsl
is rejected for having the wrong constructor, as it took me a while to figure out what was going on here.Current Behavior
- Any
ScalaDsl
classes with constructors like that shown above are not loaded into the backend- No warning is currently given.
Possible Solution
I should think that most of the
JavaBackend.loadGlue
code could be used directly by the ScalaBackend, instead of its own less fully-featured version (some allowances are currently made in the ScalaBackend for "MODULE$" fields, but I don't immediately see why that's necessary).Steps to Reproduce (for bugs)
Hopefully the above is clear enough; please let me know if not.
Context & Motivation
I'm starting a new Scala proejct and I'd like to use
cucumber-jvm
. I have experience usingcucumber-jvm
on Java projects and Scala experience.Your Environment
n/a
It's important to give accurate documentation to our users and sometimes documentation is not updated, leading to pieces of code copy/pasted by users from the documentation that don't work.
Use mdoc which is quite standard in Scala ecosystem.
N/A
Context
I believe the issue might not be related to cucumber-jvm-scala because I only reproduce it when using sbt as build tool rather than maven but I feel it's better to enter an issue here in case someone have the issue in the future.
We'll link to another issue in another project if the fix is not part of this project.
Issue
Given we have two scenarios with the same name (Scenario: a scenario name
) in the same file
When I run sbt test
And one of them is failing but not the other
Then the result is "SUCCESS" instead of "ERROR"
It seems that only the result of the first test is considered, thus depending on order of tests the result is different.
Reproduction
Clone https://github.com/gaeljw/cucumber-jvm-scala-issue-duplicate-scenarios/tree/master and run sbt test
What about Maven?
As mentionned, I cannot reproduce with the same project (Scala) using Maven (https://github.com/gaeljw/cucumber-jvm-scala-issue-duplicate-scenarios/tree/maven)
See "Recommended Scalac Flags for 2.12" https://tpolecat.github.io/2017/04/25/scalac-flags.html
We need to check if the list can be applied for Scala 2.11 and 2.13 as well.
EDIT:
Even though the method and parameter names are quite explicit, we should add documentation in the Scala DSL so that users can be sure of what are the purpose of parameters.
We should migrate from Travis to GitHub Actions. Travis is no longer supporting Open Source.
Describe the bug
The following hook definition:
Before {
someMethodThatReturnInt()
}
will NOT define a hook because it will be interpreted as Before(someMethodThatReturnInt())
and a missing body.
This it not exactly a bug but this can be quite confusing for users.
To Reproduce
object MySteps extends ScalaDsl with EN {
Before {
println("Before hook")
1 // Silly but for the reproduction purpose
}
}
Create a feature file with 2 scenarios and a dumb step definition. Check that the before hook is printed only once.
Expected behavior
I would expect that a warning/error is raised at compile time, or that the body is actually interpreted as the hook body rather than something providing the order of the hook.
Depending on how we can fix that, we will consider other options.
Versions:
Additional context
To be more confusing, I think it will work as a side effect when hooks are defined in class but not in objects because glue classes are reinstantiated at each scenario while glue objects are not.
Other definitions (like ParameterType) should be checked as well..
cucumber 3.0 brings interesting features for scala users (and finally drops XStream).
Not sure what's going on here, but I see a bunch of different repos for cucumber-scala
: https://search.maven.org/#search%7Cga%7C1%7Ccucumber-scala
There are several listed as "Latest version" 2.0.1 or 1.2.5, but with ArtifactId listed as cucumber-scala_2.9
, cucumber-scala_2.10
, cucumber-scala_2.11
, cucumber-scala_2.12
From: cucumber/cucumber-jvm#755
From https://groups.google.com/forum/#!topic/cukes/eOhisAzEvQo, written by @tristanmccarthy:
"The problem I am hitting is that step def classes appear to be instantiated only once, at the start of the test run. Based on reading around (and previous experience with Java) I'd expect the glue code classes to be instantiated once per scenario instead, and the way I am trying to set everything up requires this."
"...I've stuck a quick and dirty example up on github for some context:
https://github.com/tristanmccarthy/cucumber-scala-webtest"
Especially the project_structure.md
file.
Any plans to support Scala 2.13?
Describe the bug
When one or more scenarios failed, we don't get a list of failed scenarios:
like
Failed scenarios:
classpath:features/myfile.feature:12# <my_scenario_description 1>
classpath:features/myfile.feature:15# <my_scenario_description 2>
To Reproduce
Run feature file with a failing test.
Expected behavior
Failed scenarios should be listed in the end, as it helps developers to identify quickly especially when there is a huge number of tests.
** cucumber Version being used**
"io.cucumber" % "cucumber-core" % "6.2.2"
"io.cucumber" % "cucumber-junit" % "6.2.2"
"io.cucumber" %% "cucumber-scala" % "6.2.2"
The same thing was working when the cucumber version was 5.7.0
.
I am not sure if this change was introduced on purpose in version 6 or above. Please suggest if this can be achieved by any configuration change (such as CucumberOptions
).
Thanks in advance.
Describe the bug
State management required for cucumber-Scala. like how cucumber-java+ cucumber-picocontainer handling state management
To Reproduce
This world class in the state need within scenario to record the state after each step and global background setup
class world{
var globalFlag: String = _
var scenarioFlag : String = _
var result : String = _
}
below is the stepDefinition class contains all glue code and step definition
class stepDefinition(implicit world : World) extends scalaDsl with En{
Given("do this"){
(input : String) => { world.scenarioFlag = input }
}
}
getting exception trying to inject world instance to step definition. where its works fine in cucumber-java and cucumber-piococontainer
Expected behavior
should get world instance available in the step definition class
Versions:
From cucumber/cucumber-jvm#948
I have a step definition as
Given( """^I am logged in(?: as (.+))?$""") { (user: String) => // do something }
And my feature file step is
Given I am logged in
Then I am getting an error
scala.MatchError: List(null) (of class scala.collection.immutable.$colon$colon) at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:253) at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:251) at cucumber.api.scala.ScalaDsl$StepBody$$anonfun$apply$2.applyOrElse(ScalaDsl.scala:95) at cucumber.api.scala.ScalaDsl$StepBody$$anonfun$apply$2.applyOrElse(ScalaDsl.scala:95) at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) at cucumber.runtime.scala.ScalaStepDefinition.execute(ScalaStepDefinition.scala:71) at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37) at cucumber.runtime.Runtime.runStep(Runtime.java:298) at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44) at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39) at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:48) at cucumber.runtime.model.CucumberFeature.run(CucumberFeature.java:154) at cucumber.runtime.Runtime.run(Runtime.java:120) at cucumber.runtime.Runtime.run(Runtime.java:108) at cucumber.api.cli.Main.run(Main.java:36) at cucumber.api.cli.Main.main(Main.java:18) 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:483) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) at β½.Given I am logged in(/Users/anshulbajpai/projects/payments-frontend/features/spike.feature:319)
Ideally, I'd expect the control to go into the step definition with null value for
user
parameter.
step: And a message is sent with a mobile
glue: Then("a message is sent (with|without) a mobile") { withOrWithout: String =>
error message: io.cucumber.junit.UndefinedStepException: The step 'a message is sent with a mobile' is undefined.
Step should be picked and "with" or "without" should be the captured value
Cucumber Scala 8.9.0
Cucumber core 7.7.0
Scenario: Regex capture
Given wte
And a message is sent with a mobile
and
Then("a message is sent (with|without) a mobile") { withOrWithout: String =>
assert(withOrWithout == "with"
}
the error:
2022-09-12 09:56:22.644 [error] Test SomeFeature - SomeFeature failed: io.cucumber.junit.UndefinedStepException: The step 'a message is sent with a mobile' is undefined.
2022-09-12 09:56:22.644 [error] You can implement this step using the snippet(s) below:
2022-09-12 09:56:22.644 [error]
2022-09-12 09:56:22.644 [error] Then("""a message is sent with a mobile""") { () =>
2022-09-12 09:56:22.644 [error] // Write code here that turns the phrase above into concrete actions
2022-09-12 09:56:22.644 [error] throw new io.cucumber.scala.PendingException()
2022-09-12 09:56:22.644 [error] }
2022-09-12 09:56:22.644 [error] , took 8.307 sec
As Scala 3.1.2 brings forward compatibility feature, it would be nice to compile the project with latest Scala 3 version (3.1.2 as of now) and target an output version of 3.0.2 so that users not yet on 3.1.x can still use the lib.
N/A
N/A
This requires sbt 1.7+ (currently 1.7.0-M2 supports it, so we could start the work in a branch and wait for stable 1.7 or even consider releasing with 1.7.0-M2 if no issue raised during tests).
Related to #50
I would like to have convenience methods for converting a DataTable to Scala types:
Given("My expression") { (table: DataTable) =>
table.asScalaMaps
// Instead of something like:
table.asMaps().asScala.map(_.asScala)
}
Also considering that DataTable can contain null
values but null
is not expected in Scala, we should probably filter out the null
values.
This text was originally generated from a template, then edited by hand. You can modify the template here.
What's the problem you've observed? π€
Releases are not automated, this means we have to run the build scripts on maintainers' local machines, and also means that credentials for releases have to be copied onto those machines.
Do you have a proposal for making it better? π¦
Implement a GitHub action, based on a protected release/vX.Y.Z
branch as we have done in other repos (see cucumber/common#1688)
At the moment we canβt tell whether the build is passing ir failing, which makes it impossible to merge othet PRs.
Just upgrade Scala version to 2.13.2 (latest available) :)
Is your feature request related to a problem? Please describe.
Since version 6.x, we can benefit of extension methods to the Datatable
class to map them to Scala collection types easily. But it assumes that we are converting only to basic types and always wrap the values in an Option
.
This is not necessary for custom types registered with a DataTableType
as we can assume that a scala DataTableType
never returns null
.
Describe the solution you'd like
We should be able to do map a Datatable
to a list of custom types not wrapped in Option
.
DataTableType { map: Map[String,String] =>
// map to CustomType
}
Given("the following table as Scala List of custom type") { (table: DataTable) =>
// We want this:
val data: Seq[CustomType] = table.asScalaRawList[CustomType]
// Instead of:
val data: Seq[Option[CustomType]] = table.asScalaList[CustomType]
// ...
}
From comment from @ckorakidis at #50 (comment)
Can't use DataTable:
io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to Map<java.lang.String, boolean>
I use it like:dataTable.asScalaMap[String, Boolean]
in StepDefinitions which extends EN and have importedio.cucumber.scala.Implicits._
Cucumber should be able to convert to a map with Boolean
(Scala or Java) values.
Cucumber Scala 8.9.0
Cucumber core 7.7.0
Scenario: As Map of boolean
Given the following table as Scala Map with boolean
| row1 | true |
| row2 | |
| row3 | false |
Given("the following table as Scala Map with boolean") { (table: DataTable) =>
val data: Map[String, Option[Boolean]] =
table.asScalaMap[String, Boolean]
val expected = Map(
"row1" -> Some(true),
"row2" -> None,
"row3" -> Some(false)
)
assert(data == expected)
}
The error:
io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to Map<java.lang.String, boolean>.
[error] Please review these problems:
[error]
[error] - There was no table entry transformer registered for boolean.
[error] Please consider registering a table entry transformer.
[error]
[error] - There was no table cell transformer registered for boolean.
[error] Please consider registering a table cell transformer.
[error]
[error] - There was no default table cell transformer registered to transform boolean.
[error] Please consider registering a default table cell transformer.
[error]
Replacing Boolean
with java.lang.Boolean
does not help, the same error is still present:
io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to Map<java.lang.String, java.lang.Boolean>.
[error] Please review these problems:
[error]
[error] - There was no table entry transformer registered for java.lang.Boolean.
[error] Please consider registering a table entry transformer.
[error]
[error] - There was no table cell transformer registered for java.lang.Boolean.
[error] Please consider registering a table cell transformer.
[error]
[error] - There was no default table cell transformer registered to transform java.lang.Boolean.
[error] Please consider registering a default table cell transformer.
[error]
N/A
Since version 8.2.7, only artifact for Scala 2.13 is published to Maven repositories.
Cross builds for Scala 2.12 and 3.x are not published anymore.
See https://mvnrepository.com/artifact/io.cucumber/cucumber-scala
I believe the Cucumber Scala should provide an easy way to map Datatables to case classes.
case class MyCaseClass(a: Int, b: String)
Given("expression") { (data:Datatable) =>
val myData = data.asLists(classOf[MyCaseClass])
}
I'm not sure if this should be part of Cucumber Scala by default (if it's possible) or this has to be an optional feature that users can enable by inheriting a trait
for instance. I guess it depends on how it's implemented π€
This was possible in with version 2.x and as far as I know, for now, it has to be implemented with custom transformers and/or type registry.
Example of implementation in Cucumber Scala 4.7:
trait TypeRegistry extends TypeRegistryConfigurer {
override def locale(): Locale = Locale.ENGLISH
override def configureTypeRegistry(typeRegistry: api.TypeRegistry): Unit = {
val transformer = new DefaultTransformer()
typeRegistry.setDefaultDataTableEntryTransformer(transformer)
typeRegistry.setDefaultDataTableCellTransformer(transformer)
typeRegistry.setDefaultParameterTransformer(transformer)
}
}
class DefaultTransformer
extends ParameterByTypeTransformer
with TableEntryByTypeTransformer
with TableCellByTypeTransformer {
var objectMapper: ObjectMapper = new ObjectMapper()
objectMapper.registerModule(DefaultScalaModule)
override def transform(s: String, `type`: Type): AnyRef = {
objectMapper.convertValue(s, objectMapper.constructType(`type`))
}
override def transform[T](entry: JMap[String, String], `type`: Class[T], cellTransformer: TableCellByTypeTransformer): T = {
objectMapper.convertValue(entry, objectMapper.constructType(`type`))
}
override def transform[T](value: String, cellType: Class[T]): T = {
objectMapper.convertValue(value, objectMapper.constructType(cellType))
}
}
Scala 3.x is on its way (http://dotty.epfl.ch/blog/2020/09/21/naming-schema-change.html).
Even though users of Scala 3.x projects should be able to use Cucumber Scala compiled with Scala 2.x, it would be nice if Cucumber Scala was cross compiled to Scala 3.x as well.
That being said, there is for now no support of Scala 3 with the Scala Maven plugin (davidB/scala-maven-plugin#393), thus if we want to move forward we have two options:
sbt
insteadI would tend to vote for the 2nd option, as AFAIK the majority of Scala libraries are built with sbt
which offers way more convenience especially from cross-builiding projects to multiple versions of Scala. It could also help Scala developers contribute more easily with a known project structure instead of the "home-made" Maven structure we have for now.
β But as of today we rely on Maven also for releasing the project and I don't know if we want to keep it like this or not.
π‘ An intermediate step could be to still use Maven for the top level commands (build, release...) but delegate to sbt
the actual build. This is something I've seen working quite well using the Exec Maven plugin.
Any thought on the topic appreciated! @mpkorstanje maybe π
Is your feature request related to a problem? Please describe.
When definiting a DataTableType
we might have to handle null
values (empty values from the Gherkin table).
It should be possible to say that you want Option
s instead and let the lib deal with the null
s.
Describe the solution you'd like
Instead of doing something like that:
DataTableType { map: Map[String, String] =>
val val1 = Option(map("key1")) // <- Option to wrap the null
}
It should be possible to define the transformer like this:
DataTableType { map: Map[String, Option[String]] =>
val val1 = map("key1") // No need to wrap!
}
Additional context
Obviously the current transformers should be kept for compatibility and users who know they don't have null
values.
We should consider using a code formatter at some point.
Scalafmt looks like a good choice but open to any suggestion.
Obvisouly, as long as number of contributors is quite low, this is not a priority.
I'm not sure if the gpg.sh
script is used anymore after #269 was merged.
If it isn't - maybe delete it?
If it is used, please beware that I've renamed GPG_SIGNING_KEY_PASSPHRASE
to GPG_PASSPHRASE
in the secrets
repo on keybase.
Is your feature request related to a problem? Please describe.
Jackson Scala module has some flaws and using it with the JacksonDefaultDataTableEntryTransformer
to automatically map datatables does not always work.
For instance issues with Option
s: FasterXML/jackson-module-scala#459
Describe the solution you'd like
It could be nice to propose other alternatives to Jackson, more Scala friendly.
A first alternative with support for basic case classes would be enough for a start IMHO.
This means we "just" need to build a case class instance given a Map[String, String]
of values and a Java Type
reference.
Describe alternatives you've considered
N/A
Additional context
N/A
If possible we should support hooks without parameters.
For instance instead of writing that:
Before { _ =>
// Some code
}
We should be able to write this:
Before {
// Some code
}
The Scala DSL does not support adding types or transformers easily.
We should be able to do something like the Java8 implementation:
DataTableType("[blank]", (Map<String, String> entry) -> {
Person person = new Person();
person.first = entry.get("first");
person.last = entry.get("last");
return person;
});
ParameterType("optional", "[a-z]*", args -> Optional.of(args));
For instance:
class MySteps extends ScalaDsl with EN {
DataTableType("[blank]", entry => Person(entry("first"), entry("last")))
ParameterType("optional", "[a-z]*", args => Option(args))
}
Describe the solution you'd like
A integration library "cucumber-scalatest" that would remove the need for "cucumber-junit" and runs the Cucumber scenarios as Scalatest instances.
From cucumber/cucumber-jvm#922
@Transform in Scala DSL does not work and I have to define my own class using XStreamConverter to make it work.
class MyClassConverter extends Transformer[MyClass] { //implementation of Transform function } def given(@Transform(classOf[MyClassConverter]) c: MyClass) { //Some Code } Given("""^I have my (.*) as part of my given $""".stripMargin) { given _ }This does not pick
MyClassConverter
as a converter forMyClass
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
The Scala source code used for the three Scala versions (2.11, 2.12, 2.13) is the same.
While this works fine, this brings some warnings in the Scala 2.13 build as well as boilerplate code.
We should consider targeting Scala 2.13 as the main Scala version and provide some backward compatibility code for earlier versions.
The first step will be to identify the extent of this change.
Optionally but it would preferable to avoid it, we could also have 3 whole different codebase but it would be a pain to maintain.
This issue provides visibility into Renovate updates and their statuses. Learn more
This repository currently has no open or pending branches.
We haven't had the time, or expertise to keep to the Scala implementation up to date. So we're looking for one or more new maintainers. The tasks are roughly:
If you are interested - comment on this issue!
Describe the solution you'd like
I would like to be be able to write such steps definitions:
Given("the following authors as entries") { (authors: Seq[Author]) =>
// Some code
}
Rather than having to use Java types:
Given("the following authors as entries") { (authors: java.util.List[Author]) =>
// Some code
}
Same goes for List[List[]]
or List[Map[]]
.
Describe alternatives you've considered
Depending on the faisability, an alternative would be to provide in Cucumer Scala, some implicit methods to convert from DataTable
to Scala types. And promote this usage in the documentation.
Additional note
This must not be a breaking change, if people rely on Java Types, their code should obvisouly still continue to work.
Instead of having a piece of Groovy code inside the pom.xml
, we shoud rely on an external file.
See https://github.com/cucumber/cucumber-jvm/blob/master/java/pom.xml#L72
This way, we will benefit from IDE capabilities when reading the file and it will make the POM easier as well.
I have a cucumber test suite which has some tests
I run the tests using command
sbt "testOnly <cucumber_class_name>"
And one of the cucumber tests fail an assertion and console shows
Failed scenarios:
classpath:features/my_cucumber_scenario.feature:31# <my test description>
19 Scenarios (1 failed, 18 passed)
88 Steps (1 failed, 87 passed)sts 214s
3m18.224s
But in the end the console shows
Total 80, Failed 0, Errors 0, Passed 80
Since one of the tests failed, in the final output it should have shown
Failed 1
(Or something like that). But it is showing all passed instead due to which my build on travis is not failing.
How to solve this problem ? Is there a solution in cucumber ?
My dependencies are
"io.cucumber" % "cucumber-core" % "5.7.0",
"io.cucumber" % "cucumber-junit" % "5.7.0"
"io.cucumber" %% "cucumber-scala" % "5.7.0"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.