vicaba
vicaba

Reputation: 2876

Playframework test. FakeRequest sent with empty body always (scala)

I've been struggling several hours and every time I send a FakeRequest, it seems that the FakeApplication receives an empty body. However, if I try to run the play application and I send a normal request to localhost, everything works as expected, I receive the text I sent as a response.

enter image description here

Another test of the test that I have done is sending a custom response (not the same it receives) from the controller, like a string "a".

My test code looks like:

      val controller = app.injector.instanceOf(classOf[CreateRecordController])
  val js = Json.obj()
  val result = controller.apply().apply(
    FakeRequest(POST, "/api/v1/record/")
      .withHeaders(Headers(CONTENT_TYPE -> "application/json"))
      .withJsonBody(js)
  )

  val content = contentAsJson(result)

  info.apply(s"content was $content")

The last statement prints: "content was" and an html page saying: "For request 'POST /api/v1/record/' [Invalid Json: No content to map due to end-of-input at [Source: akka.util.ByteIterator$ByteArrayIterator$$anon$1@5fdfe8cf; line: 1, column: 0]]" -> So the content is empty.

My action handler in the controller is:

  def apply: Action[JsValue] = Action.async(parse.json) { implicit request =>

          Future.successful(BadRequest(request.body).withHeaders("Content-type" -> "application/json"))

   }

Am I missing something?

Play version: 2.6.2

Upvotes: 4

Views: 2224

Answers (2)

saheb
saheb

Reputation: 599

Here you go, give this a read first - https://www.playframework.com/documentation/2.6.x/ScalaEssentialAction

Controller

  def work = Action.async(parse.json) { implicit request =>
    Future.successful(BadRequest(request.body).withHeaders((CONTENT_TYPE, "application/json")))
  }

Test

class ApplicationSpec extends PlaySpec with Results with GuiceOneAppPerTest with Injecting {
    "Application" should {
        "work" in {
          implicit lazy val materializer: Materializer = app.materializer
          val controller = new Application(inject[ControllerComponents])
          val body = Json.obj()
          val result = call(controller.work(), FakeRequest(POST, "/work").withHeaders((CONTENT_TYPE, "application/json")).withJsonBody(body))
          contentAsJson(result) mustBe body
        }
      }
    }

Upvotes: 3

vicaba
vicaba

Reputation: 2876

It seems that if the content is passed to the FakeRequest at construction time it works as expected. What I've seen is that if I pass a JsValue as the body at construction time, the FakeRequest is of type FakeRequest[JsValue] which works fine. But if the method .withBodyAsJson is used, the type becomes FakeRequest[AnyContentAsJson]. It may be a bug.

Upvotes: 2

Related Questions