Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep session in subsequent Java calls to Play 2.0's fakeRequest

I'm looking for a way to preserve the session when using Play 2.0's fakeRequest in my Java tests, but my attempts fail while invoking methods in the Scala-based JARs.

Based on a pull request mentioned in the Scala question Add values to Session during testing (FakeRequest, FakeApplication), I figured the following might work in Java:

public Session getSession(Result result) {
  play.api.mvc.Cookies scalaCookies =
      play.api.test.Helpers.cookies(result.getWrappedResult());
  play.api.mvc.Cookie scalaSessionCookie =
      scalaCookies.get(play.api.mvc.Session.COOKIE_NAME()).get();
  scala.Option<play.api.mvc.Cookie> optionalCookie =
      scala.Option.apply(scalaSessionCookie);

  // Compiles fine, but fails with NoSuchMethodError:
  play.api.mvc.Session scalaSession =
      play.api.mvc.Session.decodeFromCookie(optionalCookie);

  return new play.mvc.Http.Session(Scala.asJava(scalaSession.data()));
}

This compiles just fine, but while running the tests it gets me:

java.lang.NoSuchMethodError: 
  play.api.mvc.Session.decodeFromCookie(Lscala/Option;)Lplay/api/mvc/Session;

Being a total Scala newby, I really have no idea if I'm even close. The Scala Session does expose (trait) that method through CookieBaker, I think.

Note that I am not necessarily looking for a way to get the above code running; the above is really just the first (possible) step to get the session. Next I'd probably try to use something like play.api.mvc.Session.encodeAsCookie(session) to pass it to the subsequent requests. Like for the ZenTasks demo:

@Test
public void testLoginAndMore() {
  Helpers.running(Helpers.fakeApplication(Helpers.inMemoryDatabase()), 
  new Runnable() {
    public void run() {
      Map<String, String> data = new HashMap<String, String>();
      data.put("email", "[email protected]");
      data.put("password", "secret");

      Result result = 
        callAction(controllers.routes.ref.Application.authenticate(),
          fakeRequest().withFormUrlEncodedBody(data));
      assertThat(status(result)).isEqualTo(Status.SEE_OTHER);
      assertThat(redirectLocation(result)).isEqualTo("/");

      // All fine; we're logged in. Now somehow preserve the cookie. This
      // does NOT do the trick:
      Session session = getSession(result);
      // ...subsequent callAction(..)s, somehow passing the session cookie 
    }
  });
}

For 1.x, Playframework Secure module: how do you “log in” to test a secured controller in a FunctionalTest? helps, but things seem to have changed in 2.0, and I never used 1.x.

like image 691
Arjan Avatar asked Dec 27 '22 03:12

Arjan


2 Answers

Not much magic needed after all. The following simply preserves the HTTP header that sets the cookies, and passes that in the next request:

Map<String, String> data = new HashMap<String, String>();
data.put("email", "[email protected]");
data.put("password", "secret");

Result result = callAction(controllers.routes.ref.Application.authenticate(),
  fakeRequest().withFormUrlEncodedBody(data));

assertThat(status(result)).isEqualTo(Status.SEE_OTHER);
assertThat(redirectLocation(result)).isEqualTo("/");
// All fine; we're logged in. Preserve the cookies:
String cookies = header(HeaderNames.SET_COOKIE, result);

// Fetch next page, passing the cookies
result = routeAndCall(fakeRequest(GET, redirectLocation(result))
  .withHeader(HeaderNames.COOKIE, cookies));

assertThat(status(result)).isEqualTo(Status.OK);
assertThat(contentAsString(result).contains("Guillaume Bort"));

(See the first version of this very answer for some information about getting only the PLAY_SESSION cookie, and parsing that. That's hardly needed though.)

like image 121
3 revs Avatar answered Jan 25 '23 15:01

3 revs


It's really easy with the current version of Play to use the session in your tests. You can use the cookies(Result result) static helper method.

// Route that sets some session data to be used in subsequent requests
Result result = callAction(...);
Http.Cookie[] cookies = FluentIterable.from(cookies(result)).toArray(Http.Cookie.class);

FakeRequest request = new FakeRequest(GET, "/someRoute").withCookies(cookies);
callAction(controllers.routes.ref.Application.requestNeedingSession(), request);
like image 45
Alex Garibay Avatar answered Jan 25 '23 17:01

Alex Garibay