Testing request with CSRF Token in Play framework 2.5 (Scala)
Asked Answered
D

1

11

I'm stuck on a little problem with my functionnal testing.

I have a Play! 2.5 scala project in which I added CSRF verification on some forms, the associated scala-test units test failed, as expected, with the error :

java.lang.RuntimeException: No CSRF token present!

I'm using FakeRequest with routes in order to test them :

val fakeRequest   = FakeRequest(GET, s"/backOffice/login")
val Some(result)  = route(app, fakeRequest)

How could I add the CRSF Token in order to render my test successful again ?

(Thank you, and sorry for bad english, I'm not native)

Diahann answered 25/10, 2016 at 23:30 Comment(3)
You could override you application.conf and set some headers for bypassing CSRF, like here. Or look at this answer.Implosion
Hi, thanks for answering me ! I should have precised that I'm also testing templates, and that I'm doing CSRF protection on a per action basis (The second case in the documentation, not the first one with a filter). Due to this, I can't just bypass CSRF as my template need a CSRF token to be present in the FakeRequest, like in second link, which I had already tested (should have precised that too, sorry), but it's for play 2.2.1, and Intellij is yelling at me "Cannot resolve symbol SignedTokenProvider" Have you an idea how I could do that in play 2.5 ?Diahann
Found a solution and made a trait :) look to the answer I added if you're interested ^^Diahann
D
11

Update : Like haui said in his comment :

Seems like they added something similar in play version 2.6. There you can use import play.api.test.CSRFTokenHelper._ FakeRequest().withCSRFToken (Scala) and CSRFTokenHelper.addCSRFToken(requestBuilder) (Java) as explained in the Migration guide

For people who are still in 2.5.6, my answer still apply :

So, after looking in Play-scala classes for a certain time, I finally found a way to adapt this answer : https://mcmap.net/q/1018602/-testing-scala-play-2-2-1-controllers-with-csrf-protection to Play 2.5.6

I even made a trait, so if someone need it one day, here it is :

import play.api.Application
import play.api.test.FakeRequest
import play.filters.csrf.CSRF.Token
import play.filters.csrf.{CSRFConfigProvider, CSRFFilter}

import scala.language.postfixOps

trait CSRFTest {
  def addToken[T](fakeRequest: FakeRequest[T])(implicit app: Application) = {
    val csrfConfig     = app.injector.instanceOf[CSRFConfigProvider].get
    val csrfFilter     = app.injector.instanceOf[CSRFFilter]
    val token          = csrfFilter.tokenProvider.generateToken

    fakeRequest.copyFakeRequest(tags = fakeRequest.tags ++ Map(
      Token.NameRequestTag  -> csrfConfig.tokenName,
      Token.RequestTag      -> token
    )).withHeaders((csrfConfig.headerName, token))
  }
}

To use it, simply extend your test class with it, like this :

class LoginSpec extends PlaySpec with OneAppPerSuite /* or whatever OneApp */ with CSRFTest

then, instead of calling

val fakeRequest = FakeRequest(/* params */)

simply call

val fakeRequest = addToken(FakeRequest(/* params */))

I tried to make it look like the addToken{} in the Controller :)

Diahann answered 26/10, 2016 at 10:15 Comment(1)
Seems like they added something similar in play version 2.6. There you can use FakeRequest().withCSRFToken (Scala) and CSRFTokenHelper.addCSRFToken(requestBuilder) (Java) as explained in the Migration guideBark

© 2022 - 2024 — McMap. All rights reserved.