Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Building a Login Scenario

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

Open up authentication.feature, because, you can't do much until you login. Let's add a scenario:

... lines 1 - 5
Scenario: Logging in
... lines 7 - 13

We remember from running behat -dl:

./vendor/bin/behat -dl

That we have a lot of built in language already. Let's save some effort and describe the login process using these:

... lines 1 - 6
Given I am on "/"
... lines 8 - 13

We want to start on the homepage. PhpStorm tries to help by auto-completing this step, but when I hit tab, it prints it with extra stuff. When you use the -dl option, the "Given I am on" ends with a bunch of crazy regex. Anytime you see regex like this, it's just forming a wildcard: something where you can pass any value, surrounded by quotes.

Oh, and one other thing: even though each line starts with Given, When and Then in the definition list, that first word doesn't matter. We could actually say:

Then I am on "/"

It doesn't sound right in English, but technically, it would still run.

Alright! Given I am on "/". Next, I will click "Login". The built-in definition for that is "I follow". There's no built-in definition for "I click" but we'll add one later since that's how most people actually talk.

But for now let's add:

... lines 1 - 7
When I follow "Login"
... lines 9 - 13

Remember, these all use the named selector, so we're using "Login" because that's the text of the link.

On the login page, we need to fill in these two fields. Again, because of the named selector, we'll target these by the labels "Username" and "Password". There are a few definitions for fields, byt the one I like is "When I fill in field with value". So:

... lines 1 - 8
And I fill in "Username" with "admin"
And I fill in "Password" with "adminpass"
... lines 11 - 13

Yes I know, that isn't the right password - this won't work yet. It's cool though.

Finally, press the login button with:

... lines 1 - 10
And I press "Login"
... lines 12 - 13

Notice that you follow a link but you press a button. Then we need to find something to assert - some sign that this worked. Login on the browser. Hmm, nothing says "Congratulations, you're in!"... but our login button did change to "Logout". Let's look for that with:

... lines 1 - 11
Then I should see "Logout"

Good work team. Let's run this!

./vendor/bin/behat features/web/authentication.feature

Debugging Failed Scenarios

It runs... and fails:

The text "Logout" was not found anywhere in the text of the current page.

I happen to know this is because the password is wrong. But let's pretend that we didn't know that, and we're staring at this message wondering what the heck is going on.

Debugging tip number 1: right before the failing step, use a step definition called:

... lines 1 - 11
Then print last response
... lines 13 - 14

Now run this again. It still fails, but first it prints out the entire page's code. Yes, this is ugly - I have another debugging tip later. There are two important things: first, we're still on the login page for some reason. And second, if you scan down, you'll see the error message: "invalid credentials".


You can also see the failed page by using Then show last response:

... lines 1 - 5
Scenario: Logging in
... lines 7 - 10
And I press "Login"
Then show last response
... lines 13 - 14

You'll just need to configure the show_cmd in behat.yml. On OSX, I use show %s, but using firefox %s is common on other systems:

19 lines behat.yml
... lines 2 - 12
... lines 15 - 17
show_cmd: 'open %s'

You can even set the show_auto setting to true to automatically open a browser on failures.

Let's remove our debug line and update this to the correct password which is "admin". And now let's rerun it:

./vendor/bin/behat features/web/authentication.feature

It's alive!

But we have a big problem: We're assuming that there will always be an admin user in the database with password admin. What if there isn't? What if the intern deleted that or your dropped your database locally? Ah! Everything would start failing.

We can do better.

Leave a comment!

Login or Register to join the conversation
Soltan Avatar

Which method can be used to find an element by xpath? How should be the sequence of script?

Thank you


Hey Soltan!

I typically recommend to find things by CSS element instead of xpath... because xpath is hard :). But, you CAN find via xpath with:

$element = $this->getPage()->find('xpath', 'THEXPATH');

You can also use findAll() in the same way. See: http://mink.behat.org/en/latest/guides/traversing-pages.html#xpath-selector


Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses a very old version of Symfony. The fundamentals of Behat are still valid, but integration with Symfony will be different.

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=5.4.0, <7.3.0",
        "symfony/symfony": "^2.7", // v2.7.4
        "twig/twig": "^1.22", // v1.22.1
        "sensio/framework-extra-bundle": "^3.0", // v3.0.16
        "doctrine/doctrine-bundle": "^1.5", // v1.5.1
        "doctrine/orm": "^2.5", // v2.5.1
        "doctrine/doctrine-fixtures-bundle": "^2.2", // v2.2.1
        "behat/symfony2-extension": "^2.0" // v2.0.0
    "require-dev": {
        "behat/mink-extension": "^2.0", // v2.0.1
        "behat/mink-goutte-driver": "^1.1", // v1.1.0
        "behat/mink-selenium2-driver": "^1.2", // v1.2.0
        "phpunit/phpunit": "^4.8" // 4.8.18