There are some occasions when I want my Drupal Behat tests to perform some action as a user that already exists on the Drupal site. For example, I have a test install profile with some Default Content (users, nodes, taxonomy terms, etc.), and it already has a large set of default test data set up on the site for the benefit of developers who need to work on theming/site building.
Rather than define a ton of extra Behat steps to re-create all this test content and these test users, I just want Behat to log in as an existing user and perform actions with the pre-existing content.
Note that this might not be a good idea depending on the structure or philosophy of your site's testing. As a general principle, state should be avoided—and that includes things like 'having a set of default stuff already existing before a test runs'. However, in the real world there are situations where it's a ton easier to just use the state that exists ?.
The problem
Out of the box, the Drupal API Driver lets you create a user in a Scenario and then use that created user, like so:
Scenario: Login as a user created during this scenario
Given users:
| name | status |
| Test user | 1 |
When I am logged in as "Test user"
Then I should see the link "Log out"
But if you try to log in as an existing user, e.g.:
Scenario: Login as an existing user
Given I am logged in as "Existing user"
Then I should see the link "Log out"
You'll get the error:
Exception: No user with Existing user name is registered with the driver. in /var/www/html/vendor/drupal/drupal-extension/src/Drupal/DrupalUserManager.php:57
The Solution
There are two ways you can solve this problem:
- You can write a bunch of steps to go to the login page, fill in a username and password, and click 'Log In', then do the rest of your scenario.
- You can write your own step definition, e.g.
iAmLoggedInAsUser()
.
The first option is okay, but then you have to store a password somewhere in your code (which just feels dirty, even if it's just for testing), and it's a few extra steps every time you want to run a scenario as that user!
For the second option, I quickly found the following issue in the Drupal Extension's issue queue: Use drush user-login to login user. Taking some of the examples from there, I came up with the following step definition in my FeatureContext.php file:
<?php
/**
* @Given I am logged in as user :name
*/
public function iAmLoggedInAsUser($name) {
$domain = $this->getMinkParameter('base_url');
// Pass base url to drush command.
$uli = $this->getDriver('drush')->drush('uli', [
"--name '" . $name . "'",
"--browser=0",
"--uri=$domain",
]);
// Trim EOL characters.
$uli = trim($uli);
// Log in.
$this->getSession()->visit($uli);
}
?>
Now I can write my Scenario like so:
@api @javascript
Scenario: Log in as Existing user
Given I am logged in as user "Existing user"
And I am on "/"
Then I should see the link "Log out"
Comments
Thanks for this! Works like a charm.