Search code examples
scalaplayframeworkspecs2playframework-2.2

Unable to test controller using Action.async


I'm trying to test controller, which is using new Action.async. Following documentation I have excluded part under controller I want to test to separate trait with type reference:

trait UserController { this: Controller =>
  def index() = Action { /* snip */ }
  def register() = Action.async(parse.json) { request => /* snip */ }
}

Documentation states that I'm supposed to test it as:

object UsersControllerSpec extends PlaySpecification with Results {
  class TestController() extends Controller with UserController
    "index action" should {
      "should be valid" in {
        val controller = new TestController()
        val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
        /* assertions */
      }
    }
  }
}

For index() method it works perfectly, unfortunately I'm not able to do the same with register(), as applying FakeRequest on it returns instance of Iteratee[Array[Byte], SimpleResult]. I've noticed it has run() method that returns Future[SimpleResult] but no matter how I build FakeRequest it returns with 400 without any content or headers. Seems to me like content of FakeRequest is disregarded at all. Am I supposed to feed request body to iteratee somehow and then run it? I couldn't find any example how could I do that.


Solution

  • For me works this:

    import concurrent._
    import play.api.libs.json._
    import play.api.mvc.{SimpleResult, Results, Controller, Action}
    import play.api.test._
    import ExecutionContext.Implicits.global
    
    trait UserController {
      this: Controller =>
      def index() = Action {
        Ok("index")
      }
    
      def register() = Action.async(parse.json) {
        request =>
          future(Ok("register: " + request.body))
      }
    }
    
    object UsersControllerSpec extends PlaySpecification with Results {
    
      class TestController() extends Controller with UserController
    
      "register action" should {
        "should be valid" in {
          val controller = new TestController()
          val request = FakeRequest().withBody(Json.obj("a" -> JsString("A"), "b" -> JsString("B")))
          val result: Future[SimpleResult] = controller.register()(request)
          /* assertions */
          contentAsString(result) === """register: {"a":"A","b":"B"}"""
        }
      }
    }