Reputation: 39389
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:
Auth::loginUsingId($id)
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"
Upvotes: 1
Views: 3345
Reputation: 231
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:
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\"")
);
}
Upvotes: 4
Reputation: 413
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"
.
Upvotes: 0