FakeRequest with withAuthenticator returns unauthorized error


#1

I’m using a Silhouette v4.0 library with play framework 2.5.
And have been trying to write test code using play specs2.
But, I get the following error with my test class as below.

Error Message

    [error] could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]
            .withAuthenticator[DefaultEnv](identity.loginInfo)
                                          ^

Here’s the test class

    package controllers
    
    import com.google.inject.AbstractModule
    import org.joda.time.DateTime
    import org.specs2.specification.Scope
    import org.specs2.matcher._
    import org.specs2.mock._
    import play.api.test._
    import play.api.libs.json._
    import play.api.libs.json.Json
    import play.api.libs.json.Reads._
    import play.api.libs.functional.syntax._
    import play.api.libs.concurrent.Execution.Implicits._
    import play.api.libs.mailer.{ MailerClient, Email }
    import play.api.inject.guice.GuiceApplicationBuilder
    import play.api.inject.bind
    import com.mohiva.play.silhouette.test._
    import com.mohiva.play.silhouette.api._
    import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository
    import com.mohiva.play.silhouette.api.util._
    import com.mohiva.play.silhouette.impl.providers._
    import net.codingwell.scalaguice.ScalaModule
    import utils.auth.DefaultEnv

    class TestControllerSpec extends PlaySpecification with Mockito {
      "case" in new Context {
        new WithApplication(application) {
          val request = FakeRequest(POST, "/api/test")
            .withAuthenticator[DefaultEnv](identity.loginInfo) // <-
          val result = route(app, request).get
          status(result) must be equalTo OK
        }
      }
    
      trait Context extends Scope {
        val identity = User(
          loginInfo = LoginInfo(..)
          ..
        )

        implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))

        class FakeModule extends AbstractModule with ScalaModule {
          def configure() = {
            bind[Environment[DefaultEnv]].toInstance(env)
          }
        }

        lazy val application = new GuiceApplicationBuilder()
          .overrides(new FakeModule)
          .build
      }
    }

There are some other test classes similar to this class are properly able to compile and execute.
It’s kind of implicit problem with scope…?
Therefore, I tried to import all the same as another test class which’s able to compile properly. But, still unable to compile.
Missing some import?

I could resolve this problem with following code.
But, Now I get the 401 unauthorized error instead. (seems the onNotAuthenticated of SecuredErrorHandler class is called)

      new WithApplication(application) {
        val identity = User(LoginInfo(...))
        implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
        val request = FakeRequest(POST, "/api/test")
          .withAuthenticator(identity.loginInfo)

        val result = route(app, request).get
        status(result) must be equalTo OK
      }

#2

Hi,

you must bind your FakeEnvironment[DefaultEnv] so that it gets injected into your controller. Otherwise only your test code uses it and not your app.

Please see this seed for a working example.

Best regards,
Christian


#3

Hi Christian.

Actually, I have the FakeEnvironment[DefaultEnv] in Context trait which’s in my first example.

So, it seems that the basic problem is implicit error of DefaultEnv?
Fundamentally, It’s really weird that why I get the following error with only one case.
As I wrote, I have test classes almost the same as TestControllerSpec class.
And those are working properly.
Is something necessary in controller class which’s target of testing?

    [error] could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]
            .withAuthenticator[DefaultEnv](identity.loginInfo)
                                          ^

Best regards,
Yusuke