Placeholders

Most built-in steps can use placeholders in their arguments, those will be automatically resolved from the session:

import com.github.agourlay.cornichon.CornichonFeature

class PlaceholderFeature extends CornichonFeature {

  def feature =
  Feature("Placeholders examples") {

    Scenario("abstract favorite superheroes") {

      Given I save("favorite-superhero" -> "Batman")

      Then assert session_value("favorite-superhero").is("Batman")

      When I get("http://localhost:8080/superheroes/<favorite-superhero>")

      Then assert body.is(
        """
        {
          "name": "<favorite-superhero>",
          "realName": "Bruce Wayne",
          "city": "Gotham city",
          "publisher": "DC"
        }
        """
      )

      And I save_body_path("city" -> "batman-city")

      Then assert session_value("batman-city").is("Gotham city")

      Then assert body.is(
        """
        {
          "name": "<favorite-superhero>",
          "realName": "Bruce Wayne",
          "city": "<batman-city>",
          "publisher": "DC"
        }
        """
      )
    }
  }
}

It is also possible to inject random values inside placeholders using:

post("http://url.io/somethingWithAnId").withBody(
"""
  {
    "id" : "<random-uuid>"
  }
""")

If you save a value under the same key multiple times, the session will behave like a Multimap by appending the values.

It becomes then possible to retrieve past values:

Custom extractors

In some cases it makes sense to declare extractors to avoid code duplication when dealing with session values. Once registered, they can be used as <extractor-name> in any step.

An extractor describes using a JsonPath how to build a value from an existing value in the session.

For instance if most of your JSON responses contain a field id and you want to use it as a placeholder without always having to manually extract and save the value:

   override def registerExtractors = Map(
     "response-id" -> JsonMapper(HttpService.SessionKeys.lastResponseBodyKey, "id")
   )

It is now possible to use <response-id> or <response-id[integer]> in the steps definitions.

It works for all keys in Session, let's say we also have objects registered under keys customer & product:

   override def registerExtractors = Map(
     "response-version" -> JsonMapper(HttpService.SessionKeys.lastResponseBodyKey, "version"),
     "customer-street" -> JsonMapper("customer", "address.street"),
     "product-first-rating" -> JsonMapper("product", "rating[0].score")
   )

Other mapper types

In addition to JsonMapper, several other mapper types are available for custom extractors:

"build-number" -> SimpleMapper(() => BuildInfo.version)
"uppercased-name" -> TextMapper("name", _.toUpperCase)
"full-name" -> SessionMapper(s =>
  for {
    first <- s.get("first-name")
    last <- s.get("last-name")
  } yield s"$first $last"
)
"random-city" -> RandomMapper(rc =>
  List("Gotham", "Metropolis", "Star City")(rc.nextInt(3))
)
"visit-count" -> HistoryMapper("visited-pages", history => history.size.toString)