5

I would like to create a behat definition to authenticate a user using a cookie.

It works with the Behat BrowserKitDriver, when there is no @javascript tag on the behat scenario. But it did not work with the Behat Selenium2Driver, when there is the @javascript tag like here.

I used the symfony-demo application for demonstrate my tests.

What's wrong in my definition ?

/**
 * @Given I am logged in as :username
 */
public function iAmLoggedInAs($username)
{
    $driver = $this->getSession()->getDriver();
    $session = $this->kernel->getContainer()->get('session');
    $user = $this->kernel->getContainer()->get('security.user.provider.concrete.database_users')->loadUserByUsername($username);
    $providerKey = 'secured_area';

    $token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
    $session->set('_security_'.$providerKey, serialize($token));
    $session->save();

    if ($driver instanceof BrowserKitDriver) {
        $client = $driver->getClient();
        $cookie = new Cookie($session->getName(), $session->getId());
        $client->getCookieJar()->set($cookie);
    } else if ($driver instanceof Selenium2Driver) {
        $this->visitPath('/');
    } else {
        throw new \Exception('Unsupported Driver');
    }

    $this->getSession()->setCookie($session->getName(), $session->getId());
}

I just want that my last behat test works.
I don't know if I'm clear... ask if not.

If you can do a Pull Request with a fix it will be perfect.

8
  • @javascript enables javascript and BrowserKitDriver cannot evaluate javascript. Do you receive any error? Commented Jun 9, 2016 at 21:59
  • When I set @javascript, the driver is not BrowserKitDriver but Selenium2Driver. There is no error, javascript is correctly executed but I'm not logged to the application. Commented Jun 9, 2016 at 22:22
  • Have you tried an echo for cookies before and after trying to set the cookie.Also make sure the page is loaded before trying to set cookie. Have you tried to both @insulated and @javascript? Does your cookie is a HttpOnly cookie? If the cookie has the HttpOnly flag you may be forbidden to set cookies via JavaScript as a protection against XSS attacks. Commented Jun 13, 2016 at 19:53
  • Have you tried setting the cookie before you visit a page? Commented Jun 14, 2016 at 9:58
  • @lauda I tried to display the cookie: in FeatureContext.php with var_dump($driver->getWebDriverSession()->getAllCookies()); but also in twig: the result. It's odd that there are 2 cookies: PHPSESSID & MOCKSESSID. The cookie is not httpOnly (see the result page). Commented Jun 14, 2016 at 11:45

2 Answers 2

4

You have a few ways

Option 1. Just Use Mink

  • If you use Mink, your Context will extend RawWebContext or WebContext so you can access to the Mink Session with getSession().

  • Then, use setCookie.

As you can see, luckily for us, and this is the point with working with Mink, Cookie Manipulation is supported by many drivers

// ...
$this->visitPath('/');
$this->getSession()->setCookie(
    $session->getName(),
    $session->getId()
);

Note 1: Mind you, the following are not the same thing:

Note 2: Want to see your cookies?

var_dump($driver->getClient()->getCookieJar());

Option 2. Access Selenium2 Session

Don't hesitate to dive in the code to see how Selenium2 WebDriver Session works.

You will surely find absolute joy and peace of mind.

else if ($driver instanceof Selenium2Driver) {
      $this->visitPath('/');
      $cookie =  array(
           "domain" => "", <----- You can even add your domain here 
           "name" => $session->getName(), 
           "value" => $session->getId(),
           "path" => "/",
           "secure" => False
      );
      $driver->getWebDriverSession()->setCookie($cookie);
} 

Note 3: Want to see your cookies?

var_dump($driver->getWebDriverSession()->getAllCookies());
Sign up to request clarification or add additional context in comments.

2 Comments

fancy answer but it does not work... I can't believe that there is no single solution for Behat tests using Selenium driver and Symfony, this is not a rare setup, it's actually very common one...
Option 1 worked for me, but you have to load a page first. What I do is load a page (any page of your website), then set the cookies, then load the page you need the cookies on. I use $this->getPage('MyPage')->open(); to load a first page "manually", then set the cookies as noted above.
-1

Here you are the code I am using for automatically authenticate as a USER. This allows me saving a lot of time (login test should be made anyway in another feature file):

Sample Scenario into a YOUR_FILE.feature example file:

  Scenario: List Backend Products
    Given I auto authenticate as "YOUR_USER_NAME"
    Then  I go to "http://YOUR_SITE/backend/products"
    Then  I should see "Backend Products Management"

 

 /**
 * @Given /^I auto authenticate as "([^"]*)"$/
 */
public function iAutoAuthenticateAs($userName)
{
    $user = $this->getContainer()->get('fos_user.user_manager')->findUserByUsername($userName);
    $providerKey = $this->getContainer()->getParameter('fos_user.firewall_name');
    $token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());

    $context = $this->getContainer()->get('security.token_storage');
    $session = $this->getContainer()->get('session');

    $context->setToken($token);
    $session->set('_security_'.$providerKey, serialize($token));
    $session->save();

    $this->getSession()->setCookie($session->getName(), $session->getId());
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.