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.
This problem arises because play.api.mvc.Action[A] contains these two apply methods:
// What you're hoping for
def apply(request: Request[A]): Future[Result]
// What actually gets called
def apply(rh: RequestHeader): Iteratee[Array[Byte], Result]
This arises because Request[A] extends RequestHeader, and the A in this case makes all the difference. If it's not the right type, you'll end up calling the wrong apply.
When you use ActionBuilder with a BodyParser[A], you create an Action[A]. As a result, you'll need a Request[A] to test. parse.json returns a BodyParser[JsValue], so you need a Request[JsValue].
// In FakeRequest object
def apply(): FakeRequest[AnyContentAsEmpty.type]
FakeRequest() doesn't get you the type you need. Fortunately:
// In FakeRequest class
def withBody[B](body: B): FakeRequest[B]
So, start writing your test by using a placeholder for the body:
"should be valid" in {
val controller = new TestController()
val body: JsValue = ??? // Change this once your test compiles
// Could do these lines together, but this shows type signatures
val request: Request[JsValue] = FakeRequest().withBody(body)
val result: Future[Result] = controller.index().apply(request)
/* assertions */
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With