Skip to content

Commit c97c300

Browse files
committed
✨ feat: implement scalatest integration
1 parent 6157a05 commit c97c300

File tree

16 files changed

+1002
-0
lines changed

16 files changed

+1002
-0
lines changed

build.sbt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ val mockitoScalaVersion = "1.17.45"
4545
val junitVersion = "4.13.2"
4646
val junitJupiterVersion = "5.13.4"
4747
val junitPlatformVersion = "1.13.4"
48+
val scalatestVersion = "3.2.18"
4849

4950
// Projects and settings
5051

@@ -73,6 +74,7 @@ lazy val root = (project in file("."))
7374
)
7475
.aggregate(
7576
cucumberScala.projectRefs ++
77+
cucumberScalatest.projectRefs ++
7678
integrationTestsCommon.projectRefs ++
7779
integrationTestsJackson.projectRefs ++
7880
integrationTestsPicoContainer.projectRefs ++
@@ -133,6 +135,17 @@ lazy val cucumberScala = (projectMatrix in file("cucumber-scala"))
133135
)
134136
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))
135137

138+
lazy val cucumberScalatest = (projectMatrix in file("scalatest"))
139+
.settings(commonSettings)
140+
.settings(
141+
name := "cucumber-scalatest",
142+
libraryDependencies ++= Seq(
143+
"io.cucumber" % "cucumber-core" % cucumberVersion,
144+
"org.scalatest" %% "scalatest" % scalatestVersion
145+
)
146+
)
147+
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))
148+
136149
// Integration tests
137150
lazy val integrationTestsCommon =
138151
(projectMatrix in file("integration-tests/common"))
@@ -184,6 +197,19 @@ lazy val integrationTestsPicoContainer =
184197
.dependsOn(cucumberScala % Test)
185198
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))
186199

200+
lazy val integrationTestsScalatest =
201+
(projectMatrix in file("integration-tests/scalatest"))
202+
.settings(commonSettings)
203+
.settings(
204+
name := "integration-tests-scalatest",
205+
libraryDependencies ++= Seq(
206+
"org.scalatest" %% "scalatest" % scalatestVersion % Test
207+
),
208+
publishArtifact := false
209+
)
210+
.dependsOn(cucumberScala % Test, cucumberScalatest % Test)
211+
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))
212+
187213
// Examples project
188214
lazy val examplesJunit4 = (projectMatrix in file("examples/examples-junit4"))
189215
.settings(commonSettings)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
Feature: Cukes
2+
3+
Scenario: in the belly
4+
Given I have 4 "cukes" in my belly
5+
Then I am "happy"
6+
7+
Scenario: Int in the belly
8+
Given I have eaten an int 100
9+
Then I should have one hundred in my belly
10+
11+
Scenario: Long in the belly
12+
Given I have eaten a long 100
13+
Then I should have long one hundred in my belly
14+
15+
Scenario: String in the belly
16+
Given I have eaten "numnumnum"
17+
Then I should have numnumnum in my belly
18+
19+
Scenario: Double in the belly
20+
Given I have eaten 1.5 doubles
21+
Then I should have one and a half doubles in my belly
22+
23+
Scenario: Float in the belly
24+
Given I have eaten 1.5 floats
25+
Then I should have one and a half floats in my belly
26+
27+
Scenario: Short in the belly
28+
Given I have eaten a short 100
29+
Then I should have short one hundred in my belly
30+
31+
Scenario: Byte in the belly
32+
Given I have eaten a byte 2
33+
Then I should have two byte in my belly
34+
35+
Scenario: BigDecimal in the belly
36+
Given I have eaten 1.5 big decimals
37+
Then I should have one and a half big decimals in my belly
38+
39+
Scenario: BigInt in the belly
40+
Given I have eaten 10 big int
41+
Then I should have a ten big int in my belly
42+
43+
Scenario: Char in the belly
44+
Given I have eaten char 'C'
45+
Then I should have character C in my belly
46+
47+
Scenario: Boolean in the belly
48+
Given I have eaten boolean true
49+
Then I should have truth in my belly
50+
51+
Scenario: DataTable in the belly
52+
Given I have the following foods :
53+
| FOOD | CALORIES |
54+
| cheese | 500 |
55+
| burger | 1000 |
56+
| fries | 750 |
57+
Then I am "definitely happy"
58+
And have eaten 2250.0 calories today
59+
60+
Scenario: DataTable with args in the belly
61+
Given I have a table the sum of all rows should be 400 :
62+
| ROW |
63+
| 20 |
64+
| 80 |
65+
| 300 |
66+
67+
Scenario: Argh! a snake - to be custom mapped
68+
Given I see in the distance ... =====>
69+
Then I have a snake of length 6 moving east
70+
And I see in the distance ... <====================
71+
Then I have a snake of length 21 moving west
72+
73+
Scenario: Custom object with string constructor
74+
Given I have a person Bob
75+
Then he should say "Hello, I'm Bob!"
76+
77+
Scenario: Custom objects in the belly
78+
Given I have eaten the following cukes
79+
| Color | Number |
80+
| Green | 1 |
81+
| Red | 3 |
82+
| Blue | 2 |
83+
Then I should have eaten 6 cukes
84+
And they should have been Green, Red, Blue
85+
86+
Scenario: Did you know that we can handle call by name and zero arity
87+
Given I drink gin and vermouth
88+
When I shake my belly
89+
Then I should have lots of martinis
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package cukes
2+
3+
import io.cucumber.scalatest.{CucumberSuite, CucumberSuiteOptions}
4+
5+
class RunCukesTest extends CucumberSuite with CucumberSuiteOptions {
6+
7+
override def featuresPath: Seq[String] = Nil
8+
9+
override def gluePackages: Seq[String] = Nil
10+
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import io.cucumber.datatable.DataTable
2+
import io.cucumber.scala.{EN, ScalaDsl}
3+
import model.{Cukes, Person, Snake}
4+
import org.junit.Assert.assertEquals
5+
6+
import java.util.{List => JList, Map => JMap}
7+
import scala.annotation.nowarn
8+
import scala.jdk.CollectionConverters._
9+
10+
/** Test step definitions to exercise Scala cucumber
11+
*/
12+
@nowarn
13+
class CukesStepDefinitions extends ScalaDsl with EN {
14+
15+
var calorieCount = 0.0
16+
var intBelly: Int = 0
17+
var longBelly: Long = 0L
18+
var stringBelly: String = ""
19+
var doubleBelly: Double = 0.0
20+
var floatBelly: Float = 0.0f
21+
var shortBelly: Short = 0.toShort
22+
var byteBelly: Byte = 0.toByte
23+
var bigDecimalBelly: BigDecimal = BigDecimal(0)
24+
var bigIntBelly: BigInt = BigInt(0)
25+
var charBelly: Char = 'A'
26+
var boolBelly: Boolean = false
27+
var snake: Snake = null
28+
var person: Person = null
29+
var cukes: JList[Cukes] = null
30+
var gin: Int = 13
31+
var vermouth: Int = 42
32+
var maritinis: Int = 0
33+
34+
Given("""I have {} {string} in my belly""") { (howMany: Int, what: String) =>
35+
}
36+
37+
Given("""^I have the following foods :$""") { (table: DataTable) =>
38+
val maps: JList[JMap[String, String]] =
39+
table.asMaps(classOf[String], classOf[String])
40+
calorieCount =
41+
maps.asScala.map(_.get("CALORIES")).map(_.toDouble).fold(0.0)(_ + _)
42+
}
43+
And("""have eaten {double} calories today""") { (calories: Double) =>
44+
assertEquals(calories, calorieCount, 0.0)
45+
}
46+
47+
Given("""I have eaten an int {int}""") { (arg0: Int) =>
48+
intBelly = arg0
49+
}
50+
Then("""^I should have one hundred in my belly$""") { () =>
51+
assertEquals(100, intBelly)
52+
}
53+
54+
Given("""I have eaten a long {long}""") { (arg0: Long) =>
55+
longBelly = arg0
56+
}
57+
Then("""^I should have long one hundred in my belly$""") { () =>
58+
assertEquals(100L, longBelly)
59+
}
60+
61+
Given("""^I have eaten "(.*)"$""") { (arg0: String) =>
62+
stringBelly = arg0
63+
}
64+
Then("""^I should have numnumnum in my belly$""") { () =>
65+
assertEquals("numnumnum", stringBelly)
66+
}
67+
68+
Given("""I have eaten {double} doubles""") { (arg0: Double) =>
69+
doubleBelly = arg0
70+
}
71+
Then("""^I should have one and a half doubles in my belly$""") { () =>
72+
assertEquals(1.5, doubleBelly, 0.0)
73+
}
74+
75+
Given("""I have eaten {} floats""") { (arg0: Float) =>
76+
floatBelly = arg0
77+
}
78+
Then("""^I should have one and a half floats in my belly$""") { () =>
79+
assertEquals(1.5f, floatBelly, 0.0)
80+
}
81+
82+
Given("""I have eaten a short {short}""") { (arg0: Short) =>
83+
shortBelly = arg0
84+
}
85+
Then("""^I should have short one hundred in my belly$""") { () =>
86+
assertEquals(100.toShort, shortBelly)
87+
}
88+
89+
Given("""I have eaten a byte {byte}""") { (arg0: Byte) =>
90+
byteBelly = arg0
91+
}
92+
Then("""^I should have two byte in my belly$""") { () =>
93+
assertEquals(2.toByte, byteBelly)
94+
}
95+
96+
Given("""I have eaten {bigdecimal} big decimals""") {
97+
(arg0: java.math.BigDecimal) =>
98+
bigDecimalBelly = arg0
99+
}
100+
Then("""^I should have one and a half big decimals in my belly$""") { () =>
101+
assertEquals(BigDecimal(1.5), bigDecimalBelly)
102+
}
103+
104+
Given("""I have eaten {biginteger} big int""") {
105+
(arg0: java.math.BigInteger) =>
106+
bigIntBelly = arg0.intValue()
107+
}
108+
Then("""^I should have a ten big int in my belly$""") { () =>
109+
assertEquals(BigInt(10), bigIntBelly)
110+
}
111+
112+
Given("""I have eaten char '{char}'""") { (arg0: Char) =>
113+
charBelly = 'C'
114+
}
115+
Then("""^I should have character C in my belly$""") { () =>
116+
assertEquals('C', charBelly)
117+
}
118+
119+
Given("""I have eaten boolean {boolean}""") { (arg0: Boolean) =>
120+
boolBelly = arg0
121+
}
122+
Then("""^I should have truth in my belly$""") { () =>
123+
assertEquals(true, boolBelly)
124+
}
125+
126+
Given("""I have a table the sum of all rows should be {int} :""") {
127+
(value: Int, table: DataTable) =>
128+
assertEquals(
129+
value,
130+
table
131+
.asList(classOf[String])
132+
.asScala
133+
.drop(1)
134+
.map(String.valueOf(_: String).toInt)
135+
.foldLeft(0)(_ + _)
136+
)
137+
}
138+
139+
Given("""I see in the distance ... {snake}""") { (s: Snake) =>
140+
snake = s
141+
}
142+
Then("""^I have a snake of length (\d+) moving (.*)$""") {
143+
(size: Int, dir: String) =>
144+
assertEquals(size, snake.length)
145+
assertEquals(Symbol(dir), snake.direction)
146+
}
147+
148+
Given("""I have a person {person}""") { (p: Person) =>
149+
person = p
150+
}
151+
152+
Then("""^he should say \"(.*)\"""") { (s: String) =>
153+
assertEquals(person.hello, s)
154+
}
155+
156+
Given("^I have eaten the following cukes$") { (cs: JList[Cukes]) =>
157+
cukes = cs
158+
}
159+
160+
Then("""I should have eaten {int} cukes""") { (total: Int) =>
161+
assertEquals(total, cukes.asScala.map(_.number).sum)
162+
}
163+
164+
And("^they should have been (.*)$") { (colors: String) =>
165+
assertEquals(colors, cukes.asScala.map(_.color).mkString(", "))
166+
}
167+
168+
Given("^I drink gin and vermouth$") { () =>
169+
gin = 13
170+
vermouth = 42
171+
}
172+
173+
When("^I shake my belly$") { // note the lack of () =>
174+
maritinis += vermouth * gin
175+
}
176+
177+
Then("^I should have lots of martinis$") { () =>
178+
assertEquals(13 * 42, maritinis)
179+
}
180+
}
181+
182+
@nowarn
183+
class ThenDefs extends ScalaDsl with EN {
184+
Then("""^I am "([^"]*)"$""") { (arg0: String) => }
185+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import io.cucumber.scala.ScalaDsl
2+
import model.{Cukes, Person, Snake}
3+
4+
class TypeRegistryConfiguration extends ScalaDsl {
5+
6+
/** Transforms an ASCII snake into an object, for example:
7+
*
8+
* {{{
9+
* ====> becomes Snake(length = 5, direction = 'east)
10+
* ==> becomes Snake(length = 3, direction = 'east)
11+
* }}}
12+
*/
13+
ParameterType("snake", "[=><]+") { s =>
14+
val size = s.length
15+
val direction = s.toList match {
16+
case '<' :: _ => Symbol("west")
17+
case l if l.last == '>' => Symbol("east")
18+
case _ => Symbol("unknown")
19+
}
20+
Snake(size, direction)
21+
}
22+
23+
ParameterType("person", ".+") { s =>
24+
Person(s)
25+
}
26+
27+
ParameterType("boolean", "true|false") { s =>
28+
s.trim.equals("true")
29+
}
30+
31+
ParameterType("char", ".") { s =>
32+
s.charAt(0)
33+
}
34+
35+
DataTableType { (map: Map[String, String]) =>
36+
Cukes(map("Number").toInt, map("Color"))
37+
}
38+
39+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package model
2+
3+
case class Cukes(number: Int, color: String)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package model
2+
3+
/** Test model for a "Person"
4+
* @param name
5+
* of person
6+
*/
7+
case class Person(name: String) {
8+
9+
def hello = {
10+
"Hello, I'm " + name + "!"
11+
}
12+
13+
}

0 commit comments

Comments
 (0)