Skip to content

Instantly share code, notes, and snippets.

@dmcg
Created June 10, 2011 14:22
Show Gist options
  • Save dmcg/1018925 to your computer and use it in GitHub Desktop.
Save dmcg/1018925 to your computer and use it in GitHub Desktop.
GivenWhenThenFeatureSpec
class LoginFeature extends GivenWhenThenFeatureSpec with ShouldMatchers with OneInstancePerTest {
feature("Admin Login") {
scenario("Incorrect password") {
// You can provide the code for a step in a block
given("user visits", the[AdminHomePage]) {
startPage(pageClass)
}
// or provide matchers in the action method to define what should happen
then(the[SignInPage], "is displayed")
// or prototype the action in the local block before moving it to action
when("username", "admin", "and password", "wrong password", "are entered") {
x: Any => x match {
case ("username", username:String, "and password", password:String, "are entered") =>
form.setValue("username", username)
form.setValue("password", password)
form.submit()
}
}
// these are matched in action
then(the[SignInPage], "is displayed")
and("An error message", "Sign in failed", "is displayed")
}
}
def the[T: ClassManifest]: Class[T] = classManifest[T].erasure.asInstanceOf[Class[T]]
def action(tokens: Any) {
tokens match {
case (pageClass:Class[Page], "is displayed") =>
assertRenderedPage(pageClass)
case ("An error message", error:String, "is displayed") =>
assertErrorMessages(Array(error))
case _ =>
System.err.println("No match found for tokens " + tokens)
pending
}
}
}
import org.scalatest.FeatureSpec
trait GivenWhenThenFeatureSpec extends FeatureSpec {
def action(tokens: Any)
import org.scalatest._
def given(tokens: Any)(implicit p: Processor) = informAndProcess(tokens, GivenWhenThen.given _, p)
def when(tokens: Any)(implicit p: Processor) = informAndProcess(tokens, GivenWhenThen.when _, p)
def then(tokens: Any)(implicit p: Processor) = informAndProcess(tokens, GivenWhenThen.then _, p)
def and(tokens: Any)(implicit p: Processor) = informAndProcess(tokens, GivenWhenThen.and _, p)
def informAndProcess(tokens: Any, outputFn: (String) => Unit, p: Processor) {
inform(outputFn, tokens)
p.process(tokens)
}
protected def inform(outputFn: (String) => Unit, tokens: Any) {
val message = tokens match {
case x: Product =>
x.productIterator.map { case "" => "[empty]"; case x => x} .mkString(" ")
case x: Any => x.toString
}
outputFn(message)
}
// see http://stackoverflow.com/questions/6296059/how-can-i-overload-a-scala-method-by-block-type
trait Processor {
def process(tokens: Any)
}
protected class NoArgsBlockProcessor(block: => Any) extends Processor {
def process(tokens: Any) { block }
}
protected class TokensArgBlockProcessor(block: Any => Any) extends Processor {
def process(tokens: Any) { block(tokens) }
}
protected implicit object NoBlockProcessor extends Processor {
def process(tokens: Any) { action(tokens) }
}
implicit def NoArgsBlockToProcessor(block: => Any) = new NoArgsBlockProcessor(block)
implicit def TokensArgBlockToProcessor(block: Any => Any) = new TokensArgBlockProcessor(block)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment