Question

I’m trying to create some tests for a Laravel application using Behat. Many of the tests require that a logged-in user sees specific data. My approach was this:

  • Log in as a user with a particular ID with Auth::loginUsingId($id)
  • Go to a particular URL in my app
  • Check that the content I’m expecting is there

Now, in my Behat context, although Auth::check() returns true, the filter I have set up doesn’t seem to see this. Auth::check() in that context returns false, and thus attempts to authenticate (via OAuth to the API my app talks to).

How can I go about testing my app as a logged-in user?

My Behat context file, in case it’s of help:

<?php

use Behat\Behat\Context\ClosuredContextInterface;
use Behat\Behat\Context\TranslatedContextInterface;
use Behat\Behat\Context\BehatContext;
use Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;

/**
 * Features context.
 */
class FeatureContext extends MinkContext
{
    /**
     * Laravel application instance.
     *
     * @var Illuminate\Foundation\Application
     */
    protected $app;

    /**
     * @static
     * @beforeSuite
     */
    public static function bootstrapLaravel()
    {
        $unitTesting = true;
        $testEnvironment = true;

        $app = require_once __DIR__ . '/../../../../bootstrap/start.php';
        $app->boot();
    }

    /**
     * Initializes context.
     * Every scenario gets its own context object.
     *
     * @param array $parameters context parameters (set them up through behat.yml)
     */
    public function __construct(array $parameters)
    {
    }

    /**
     * @Given /^I am logged in as user ID (\d+)$/
     */
    public function iAmLoggedInAsUserId($id)
    {
        Auth::loginUsingId($id);
    }
}

And a sample test feature:

Feature: Sample Feature

  Scenario: View groups a member is associated with
    Given I am logged in as user ID 49
    And I am on "/group"
    Then I should see "Lorem Ipsum"
Was it helpful?

Solution

The problem you have is that the iAmLoggedInAsUserId method performs calls on the laravel framework directly, where as your subsequent instructions are browser/mink based. This is like having a PHP script which you run from the command line which sets (for its execution) the logged in user to 123, and then going to a web browser - user 123 wouldn't be logged in in that context.

You need to find a way for the code-based authentication to persist to your browser test.

Possible options:

  • An aggregate instruction for iAmLoggedInAsUserId which goes to the login page, and performs the login.
  • Hijack the session being used by mink, and update it to be logged in
  • A local-only work around which lets you, say, set a header to contain a user ID, and your code, only when running locally, uses this as the logged in user

Ideally, you should write a test to test logging in, however that is structured (i.e. option 1) and then re-use that for your tests which require a logged in user. The other two options are simply ideas if you use-case doesn't permit the first.

Edit: The following is an example aggregate instruction, this particular version requires the user exist in the system. You could however force a user to exist before hand, and if it was added as part of the test, delete it once the test is completed using the @AfterFeature hook:

/**
 * @Given /I am logged in with the username "([^"]*)" and password "([^"]*)"/
 */
public function loginWithEmailAndPassword($username, $password)
{
    //$this->ensureUserExistsWithEmailAndPassword($email, $password);

    return array(
        new Behat\Behat\Context\Step\Given("I am on \"/login\""),
        new Behat\Behat\Context\Step\When("I fill in \"login_username\" with \"$username\""),
        new Behat\Behat\Context\Step\When("I fill in \"login_password\" with \"$password\""),
        new Behat\Behat\Context\Step\When("I press \"Login\""),
        new Behat\Behat\Context\Step\Then("I should see \"Welcome\"")
    );
}

OTHER TIPS

Behat is a separate process to the browser session that it is spawning, so logging in like that won't work.

What I normally do is describe the steps for logging in as a test user. Something like the following.

Given I am on the login page
And I fill in "username" with "testuser"
And I fill in "password" with "testpassword"
And I press "Log in"
Then I should be logged in as "testuser"

You can set that up as a background in behat that will run before each scenario.

I'd probably also reduce the steps down to a method in your FeatureContext that can be called in a single step, something like Given I am logged in as "testuser".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top