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

✨ feat: implement scalatest integration #373

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ val cucumberVersion = "7.17.0"
val jacksonVersion = "2.17.0"
val mockitoScalaVersion = "1.17.31"
val junitVersion = "4.13.2"
val scalatestVersion = "3.2.18"

// Projects and settings

Expand All @@ -64,6 +65,7 @@ lazy val root = (project in file("."))
)
.aggregate(
cucumberScala.projectRefs ++
cucumberScalatest.projectRefs ++
integrationTestsCommon.projectRefs ++
integrationTestsJackson.projectRefs ++
integrationTestsPicoContainer.projectRefs ++
Expand Down Expand Up @@ -122,6 +124,17 @@ lazy val cucumberScala = (projectMatrix in file("cucumber-scala"))
)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

lazy val cucumberScalatest = (projectMatrix in file("scalatest"))
.settings(commonSettings)
.settings(
name := "cucumber-scalatest",
libraryDependencies ++= Seq(
"io.cucumber" % "cucumber-core" % cucumberVersion,
"org.scalatest" %% "scalatest" % scalatestVersion
)
)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

// Integration tests
lazy val integrationTestsCommon =
(projectMatrix in file("integration-tests/common"))
Expand Down Expand Up @@ -167,6 +180,19 @@ lazy val integrationTestsPicoContainer =
.dependsOn(cucumberScala % Test)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

lazy val integrationTestsScalatest =
(projectMatrix in file("integration-tests/scalatest"))
.settings(commonSettings)
.settings(
name := "integration-tests-scalatest",
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % scalatestVersion % Test
),
publishArtifact := false
)
.dependsOn(cucumberScala % Test, cucumberScalatest % Test)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

// Examples project
lazy val examples = (projectMatrix in file("examples"))
.settings(commonSettings)
Expand Down Expand Up @@ -200,12 +226,12 @@ releaseProcess := Seq[ReleaseStep](
runTest,
setReleaseVersion,
// the 2 following steps are part of the Cucumber release process
//commitReleaseVersion,
//tagRelease,
// commitReleaseVersion,
// tagRelease,
releaseStepCommandAndRemaining("publishSigned"),
releaseStepCommand("sonatypeBundleRelease"),
setNextVersion
// the 2 following steps are part of the Cucumber release process
//commitNextVersion,
//pushChanges
// commitNextVersion,
// pushChanges
)
89 changes: 89 additions & 0 deletions integration-tests/scalatest/src/test/resources/cukes/cukes.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
Feature: Cukes

Scenario: in the belly
Given I have 4 "cukes" in my belly
Then I am "happy"

Scenario: Int in the belly
Given I have eaten an int 100
Then I should have one hundred in my belly

Scenario: Long in the belly
Given I have eaten a long 100
Then I should have long one hundred in my belly

Scenario: String in the belly
Given I have eaten "numnumnum"
Then I should have numnumnum in my belly

Scenario: Double in the belly
Given I have eaten 1.5 doubles
Then I should have one and a half doubles in my belly

Scenario: Float in the belly
Given I have eaten 1.5 floats
Then I should have one and a half floats in my belly

Scenario: Short in the belly
Given I have eaten a short 100
Then I should have short one hundred in my belly

Scenario: Byte in the belly
Given I have eaten a byte 2
Then I should have two byte in my belly

Scenario: BigDecimal in the belly
Given I have eaten 1.5 big decimals
Then I should have one and a half big decimals in my belly

Scenario: BigInt in the belly
Given I have eaten 10 big int
Then I should have a ten big int in my belly

Scenario: Char in the belly
Given I have eaten char 'C'
Then I should have character C in my belly

Scenario: Boolean in the belly
Given I have eaten boolean true
Then I should have truth in my belly

Scenario: DataTable in the belly
Given I have the following foods :
| FOOD | CALORIES |
| cheese | 500 |
| burger | 1000 |
| fries | 750 |
Then I am "definitely happy"
And have eaten 2250.0 calories today

Scenario: DataTable with args in the belly
Given I have a table the sum of all rows should be 400 :
| ROW |
| 20 |
| 80 |
| 300 |

Scenario: Argh! a snake - to be custom mapped
Given I see in the distance ... =====>
Then I have a snake of length 6 moving east
And I see in the distance ... <====================
Then I have a snake of length 21 moving west

Scenario: Custom object with string constructor
Given I have a person Bob
Then he should say "Hello, I'm Bob!"

Scenario: Custom objects in the belly
Given I have eaten the following cukes
| Color | Number |
| Green | 1 |
| Red | 3 |
| Blue | 2 |
Then I should have eaten 6 cukes
And they should have been Green, Red, Blue

Scenario: Did you know that we can handle call by name and zero arity
Given I drink gin and vermouth
gaeljw marked this conversation as resolved.
Show resolved Hide resolved
When I shake my belly
Then I should have lots of martinis
10 changes: 10 additions & 0 deletions integration-tests/scalatest/src/test/scala/RunCukesTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package cukes

import io.cucumber.scalatest.{CucumberSuite, CucumberSuiteOptions}

class RunCukesTest extends CucumberSuite with CucumberSuiteOptions {

override def featuresPath: Seq[String] = Nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about Functor Option to express something that could be ... could be


override def gluePackages: Seq[String] = Nil
}
185 changes: 185 additions & 0 deletions integration-tests/scalatest/src/test/scala/StepDefs.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import io.cucumber.datatable.DataTable
import io.cucumber.scala.{EN, ScalaDsl}
import model.{Cukes, Person, Snake}
import org.junit.Assert.assertEquals

import java.util.{List => JList, Map => JMap}
import scala.annotation.nowarn
import scala.jdk.CollectionConverters._

/** Test step definitions to exercise Scala cucumber
*/
@nowarn
class CukesStepDefinitions extends ScalaDsl with EN {

var calorieCount = 0.0
var intBelly: Int = 0
var longBelly: Long = 0L
var stringBelly: String = ""
var doubleBelly: Double = 0.0
var floatBelly: Float = 0.0f
var shortBelly: Short = 0.toShort
var byteBelly: Byte = 0.toByte
var bigDecimalBelly: BigDecimal = BigDecimal(0)
var bigIntBelly: BigInt = BigInt(0)
var charBelly: Char = 'A'
var boolBelly: Boolean = false
var snake: Snake = null
var person: Person = null
var cukes: JList[Cukes] = null
var gin: Int = 13
var vermouth: Int = 42
var maritinis: Int = 0

Given("""I have {} {string} in my belly""") { (howMany: Int, what: String) =>
}

Given("""^I have the following foods :$""") { (table: DataTable) =>
val maps: JList[JMap[String, String]] =
table.asMaps(classOf[String], classOf[String])
calorieCount =
maps.asScala.map(_.get("CALORIES")).map(_.toDouble).fold(0.0)(_ + _)
}
And("""have eaten {double} calories today""") { (calories: Double) =>
assertEquals(calories, calorieCount, 0.0)
}

Given("""I have eaten an int {int}""") { (arg0: Int) =>
intBelly = arg0
}
Then("""^I should have one hundred in my belly$""") { () =>
assertEquals(100, intBelly)
}

Given("""I have eaten a long {long}""") { (arg0: Long) =>
longBelly = arg0
}
Then("""^I should have long one hundred in my belly$""") { () =>
assertEquals(100L, longBelly)
}

Given("""^I have eaten "(.*)"$""") { (arg0: String) =>
stringBelly = arg0
}
Then("""^I should have numnumnum in my belly$""") { () =>
assertEquals("numnumnum", stringBelly)
}

Given("""I have eaten {double} doubles""") { (arg0: Double) =>
doubleBelly = arg0
}
Then("""^I should have one and a half doubles in my belly$""") { () =>
assertEquals(1.5, doubleBelly, 0.0)
}

Given("""I have eaten {} floats""") { (arg0: Float) =>
floatBelly = arg0
}
Then("""^I should have one and a half floats in my belly$""") { () =>
assertEquals(1.5f, floatBelly, 0.0)
}

Given("""I have eaten a short {short}""") { (arg0: Short) =>
shortBelly = arg0
}
Then("""^I should have short one hundred in my belly$""") { () =>
assertEquals(100.toShort, shortBelly)
}

Given("""I have eaten a byte {byte}""") { (arg0: Byte) =>
byteBelly = arg0
}
Then("""^I should have two byte in my belly$""") { () =>
assertEquals(2.toByte, byteBelly)
}

Given("""I have eaten {bigdecimal} big decimals""") {
(arg0: java.math.BigDecimal) =>
bigDecimalBelly = arg0
}
Then("""^I should have one and a half big decimals in my belly$""") { () =>
assertEquals(BigDecimal(1.5), bigDecimalBelly)
}

Given("""I have eaten {biginteger} big int""") {
(arg0: java.math.BigInteger) =>
bigIntBelly = arg0.intValue()
}
Then("""^I should have a ten big int in my belly$""") { () =>
assertEquals(BigInt(10), bigIntBelly)
}

Given("""I have eaten char '{char}'""") { (arg0: Char) =>
charBelly = 'C'
}
Then("""^I should have character C in my belly$""") { () =>
assertEquals('C', charBelly)
}

Given("""I have eaten boolean {boolean}""") { (arg0: Boolean) =>
boolBelly = arg0
}
Then("""^I should have truth in my belly$""") { () =>
assertEquals(true, boolBelly)
}

Given("""I have a table the sum of all rows should be {int} :""") {
(value: Int, table: DataTable) =>
assertEquals(
value,
table
.asList(classOf[String])
.asScala
.drop(1)
.map(String.valueOf(_: String).toInt)
.foldLeft(0)(_ + _)
)
}

Given("""I see in the distance ... {snake}""") { (s: Snake) =>
snake = s
}
Then("""^I have a snake of length (\d+) moving (.*)$""") {
(size: Int, dir: String) =>
assertEquals(size, snake.length)
assertEquals(Symbol(dir), snake.direction)
}

Given("""I have a person {person}""") { (p: Person) =>
person = p
}

Then("""^he should say \"(.*)\"""") { (s: String) =>
assertEquals(person.hello, s)
}

Given("^I have eaten the following cukes$") { (cs: JList[Cukes]) =>
cukes = cs
}

Then("""I should have eaten {int} cukes""") { (total: Int) =>
assertEquals(total, cukes.asScala.map(_.number).sum)
}

And("^they should have been (.*)$") { (colors: String) =>
assertEquals(colors, cukes.asScala.map(_.color).mkString(", "))
}

Given("^I drink gin and vermouth$") { () =>
gin = 13
vermouth = 42
}

When("^I shake my belly$") { // note the lack of () =>
maritinis += vermouth * gin
}

Then("^I should have lots of martinis$") { () =>
assertEquals(13 * 42, maritinis)
}
}

@nowarn
class ThenDefs extends ScalaDsl with EN {
Then("""^I am "([^"]*)"$""") { (arg0: String) => }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import io.cucumber.scala.ScalaDsl
import model.{Cukes, Person, Snake}

class TypeRegistryConfiguration extends ScalaDsl {

/** Transforms an ASCII snake into an object, for example:
*
* {{{
* ====> becomes Snake(length = 5, direction = 'east)
* ==> becomes Snake(length = 3, direction = 'east)
* }}}
*/
ParameterType("snake", "[=><]+") { s =>
val size = s.length
val direction = s.toList match {
case '<' :: _ => Symbol("west")
case l if l.last == '>' => Symbol("east")
case _ => Symbol("unknown")
}
Snake(size, direction)
}

ParameterType("person", ".+") { s =>
Person(s)
}

ParameterType("boolean", "true|false") { s =>
s.trim.equals("true")
}

ParameterType("char", ".") { s =>
s.charAt(0)
}

DataTableType { (map: Map[String, String]) =>
Cukes(map("Number").toInt, map("Color"))
}

}
Loading
Loading