Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

BDD, Behat, Mink and other Wonderful Things

1:59:49

What you'll be learning

This tutorial uses a very old version of Symfony. The fundamentals of Behat are still valid, but integration with Symfony will be different.
// 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
    }
}
// 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
    }
}

Looking for Behat v2.5 of the tutorial? See https://knpuniversity.com/screencast/behat-v25.

Behat is my absolute favorite library to use. First, it let's me think about the behavior of my features first, before I start developing. In this tutorial, we'll do that, and it'll change the way you develop. Second, Behat turns that written behavior into functional tests against your application. Does your feature behave correctly? Just run the automated robots to find out!

Along the way, we'll master Mink - the partner library to Behat - and solve all sorts of common problems, like:

  • Running scenarios in a real browser
  • Properly waiting or JavaScript events
  • Leveraging Behat hooks
  • Multiple contexts
  • Loading Database fixtures and clearing data
  • Bootstrapping your application (specifically Symfony)
  • Using the authenticated user
  • Tagging scenarios
  • How to put BDD into practice
  • Keeping the velociraptors in their pen.

Let's do this!


Your Guides

Ryan Weaver Leanna Pelham

Buy Access

Join the Conversation?

57
Login or Register to join the conversation
Default user avatar
Default user avatar Syed Abouzar Mehdi | posted 4 years ago | edited

there check my yml/composer/feature files http://pastebin.com/LM7uDf4Q
but i am getting errors there.. Can you guide me or tell me what should i write in FeatureContext for my given feature file
FeatureContext::iAmOnHomepage()
Behat\MinkExtension\Context\MinkContext::iAmOnHomepage()
Then I go to "/programs/list"
Step "/^(?:|I )am on (?:|the )homepage$/" is already defined in FeatureContext::iAmOnHomepage()

1 Reply

Hey Syed,

MinkContext already has defined this step, check it here. That's why Behat do not allow you to define it again. You should remove your "FeatureContext::iAmOnHomepage()" method or do not use MinkContext.

Cheers!

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | victor | posted 4 years ago | edited

hey @bocharsky25 m so stuck :/
now i removed "FeatureContext::iAmOnHomepage()" from my FeatureContext but its still showing old message again.

Reply

I think I know the problem, since you already extends MinkContext in your FeatureContext - you can't specify MinkContext in your behat.yml config file. Keep the only FeatureContext there:

default:
suites:
defaults:
contexts:
- FeatureContext

I bet that's the problem.

1 Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | victor | posted 4 years ago

thanks fixed this one

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | posted 4 years ago | edited

there how to do http authentication?
i dont understand how to write in base_URL domain:username:password ? can you tell me the exact scenarior

1 Reply

Hey Syed,

Use next URL pattern:
http://username:password@example.com/

Cheers!

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | victor | posted 4 years ago

another thing what should i do if it asks for http auth twice. first before login and once after login...

Reply

Hm, if you follow the URL like `http://username:password@ex... ` with correct credentials - you won't be asked for http auth at all, you just should be redirected to the domain specified in previous URL (it's `http://example.com/ `). Are you sure your http auth works properly?

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | victor | posted 4 years ago

tried but dont knw whats the issue it does not work :/ it stuck on this http authentication.... thinking to remove the http authentication from my local dev.
Secondly I am just using scenarios to follow my instructions(features) not adding anything in FeatureContext.php so far so good. Because whenever i try to --append-snippets then i start getting thousands of errors :/
Now my question is can i use drop downs/checks/selects via scenarios only ?

Reply

Hey Syed,

It's difficult to say what's the problem here. BTW, if you use basic HTTP auth only locally (or for testing) but traditional login form on prod - that's a bad idea. You should test the same things which you use in production.

Yes, you can! Check MinkContext one more time - it has something like "I check ...", "I uncheck ...", "I select ... from ...", etc. But having problems with ` --append-snippets` is odd. Actually, you don't need to use ` --append-snippets`, just write a new step in any feature (*.feature) and run Behat. Behat generate this step definition (i.e. a new method definition) and show you it in console. Then you can manually copy it and past in the proper feature context.

Cheers!

Reply
Kiuega Avatar

Hello ! this course is now very old, but we are still at Behat version 3. Do you think we can still take this training (from a symfony 5 project, PHP 8 and latest version of Behat 3.8)? The principles remain the same? Thank you !

Reply

Hey Kiuega

Yeah the main principles are the same, the only difference is in configuration. We are preparing a blog post which will describe base configuration moments :) Keep looking!

Cheers!

2 Reply
Stefan T. Avatar
Stefan T. Avatar Stefan T. | posted 3 years ago

What do you think about codeception?

Reply

Hey Stefan T.!

I don't have a lot of experience, but my impression about codeception is that it's a great tool and well-supported :).

Cheers!

Reply
Default user avatar
Default user avatar Richard Bagshaw | posted 4 years ago

So much yes!! I want this one :) Behat 3!! :)

Reply
Default user avatar
Default user avatar truthrevealer | posted 4 years ago

Should the owners of Behat 2.5 course purchase this one as well to get access to it?

Reply

Hey!

If you own the Behat 2.5 version, shoot us an email/contact message and we'll be happy to give anyone a coupon code to grab the 3.0 version free :).

Cheers!

Reply
Default user avatar

apang7@gmail.com, I am looking for automation on websites. Seems like behat will do the job

Reply

Hey Andrew,

Yeah, Behat with Selenium do the trick. You can even test JS websites with this bundle, just add @javascript above your scenarios.

Cheers!

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | posted 4 years ago | edited

@bocharsky25 hi !! i am facing a new issue from yesterday.. whenever i run any feature file i get following error . It came at once things were fine but now chrome starts and gets closed instantly... any Help?
--------------------
no such session
(Driver info: chromedriver=2.23.409699 (49b0fa931cda1caad0ae15b7d1b68004acd05129),platform=Windows NT 10.0.10240 x86_64) (WARNING: The server did not provide any stacktrace i
nformation)
----

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | Syed Abouzar Mehdi | posted 4 years ago

Seleniumversion is: selenium-server-standalone-3.0.0-beta3.jar

1 Reply

Hey Syed!

Hmm, when this type of thing happens to me (which is rare, but it occasionally happens), I always update the selenium server to the latest version. What happens is that Chrome will receive an update, and it will break something that Selenium relies on. Then, Selenium will release an update to fix the change in Chrome. So, hopefully updating Selenium will fix that. Also, there is a "Chrome Driver" that I believe you also need to have running (you may or may not have this - I'm not 100% sure if it's required), but I would try updating that as well.

Let me know if that helps!

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | weaverryan | posted 4 years ago

ya this is the problem now how to overcome it. my selenium and chromes are latest but still having issues.. I dont know how to fix these.. Firefox having same issues as well.. what other browser I can use ? and how ..
thanks for the help

Reply

Hmm, I'm not sure - it's definitely some issue then with Selenium and possibly your system. I did find an issue that has the same error - it seems very hard to reproduce: https://bugs.chromium.org/p.... Some of the suggestions include making sure you have enough memory (only really relevant if you're doing something in Docker or similar, as the person was) and also a "--disable-impl-side-painting" flag. You can see how to set flags for Chrome here: https://edmondscommerce.git... (look for chromeOptions, then args). I don't do this very often, so I'm not sure if it'll help - just trying to throw it out there!

For other browsers, it depends on your system, but you can check out the plugins here: http://www.seleniumhq.org/d...

Sorry I can't help more - usually the solution is upgrading... but sometimes Selenium might need a bit more help.

Cheers!

Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | weaverryan | posted 4 years ago | edited

@weaverryan fixed it finally with Latest Chrome driver https://chromedriver.storag...
meanwhile i was working on some FeatureContext working with Ajaxcalls.. Thanks Again =) cheers

Reply

Awesome! Great news - glad it all got finally fixed. I think things are a little weird right now with the v 3 of the Selenium Server being released - things seem to be a bit more "broken" than normal.

Reply
Default user avatar

I would just add as a reference for others looking for a quick solution running chrome-driver:
When running the selenium server, specify it to be run with the chrome driver:

java \
-Dwebdriver.chrome.driver="chromedriver" \
-jar selenium-server-standalone-3.0.1.jar

(at the same root of chromedriver and be careful of the selenium server version)

Reply

Thanks for sharing this!

Cheers!

Reply
Default user avatar
Default user avatar Abuzar Mehdi | posted 4 years ago | edited

@weaverryan i am facing few issues .
when i run the bin/behat my firefox browser opens with welcome page and nothing happens.
"about:blank&utm_content=firstrun" <-= in firefox address bar kindly tell me how to fix this one

Reply

Hey Abuzar,

I had the same issue, that's why I switched to the Google Chrome as a default browser for Behat tests. I suppose it's due to some BC breaks in new version of FireFox.

1 Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | victor | posted 4 years ago

i tried alot to play with google but gets enough issues in it . Dont know how to make it possible to run tests via google.

Reply

You should specify browser_name in behat.yml configuration for Mink extension, that's it:


default:
extensions:
Behat\MinkExtension\Extension:
browser_name: chrome
Reply
Default user avatar
Default user avatar Syed Abouzar Mehdi | victor | posted 4 years ago

ya thanks Victor
i am now starting with this one
$this->driver = new \Behat\Mink\Driver\Selenium2Driver('chrome');
$this->session = new \Behat\Mink\Session($this->driver);
$this->session->start();
and in behat.yml i am using same as you said../
now when chrome opens one tab has -> Data; and then other one opens with Data; and later on browses my given URL... :D
sorry just learning :$

Reply

Yep, I've had the same issues at times. What happens is that a browser releases a new version, and this breaks some backwards-compatibility in Selenium. Sometimes, a new version of Selenium has already fixed the issue, but sometimes that hasn't happened yet. In those cases, exactly like Victor said, I'll switch back and forth between Firefox or Chrome to get one that works. This doesn't happen very often, but it definitely happens :).

Cheers!

Reply
Default user avatar
Default user avatar Andrew Pang | posted 4 years ago

I am using wiki/main page to do a search and following your examples in the tutorial gave me this error:
Scenario: Search for a word that exists # features/search.feature:7
Given I am on "/wiki/MainPage" # FeatureContext::visit()
Could not open connection: Curl error thrown for http POST to http://localhost:4444/wd/hub/session with params: {"desiredCapabilities":{"tags":["apang2-08","PHP 7.0.17"],"browser":"firefox","ignoreZoomSetting":false,"name":"Behat feature suite","browserName":"firefox"}}

Failed to connect to localhost port 4444: Connection refused (Behat\Mink\Exception\DriverException)

Reply

Hey Andrew,

I suppose your scenario has \@javascript tag and Behat trying to run it on Selenium server. But this error means that you do not start Selenium server yet. Take a look at: https://knpuniversity.com/s... - which explain how to run Selenium server.

Cheers!

Reply
Default user avatar
Default user avatar Jon Robinson | posted 4 years ago

Hi, thanks for this... you guys have the best Behat/Mink tutorials.

Question though... when using @javascript in my feature file... Firefox loads and runs the tests successfully, which is great, using Firefox version: 47.0. However, I've recently updated to latest Firefox (53.0). Every time I run my tests now, Firefox loads, but the url from Given I go to "http://whateversite.com" is not entered and obviously nothing happens and eventially the test timeouts with error: Could not open connection: Failed to connect to binary FirefoxBinary(/Applications/Firefox.app/Contents/MacOS/... on port 7055; process output follows: "

Any ideas why? I am using latest selenium-server-standalone-3.4.0

Thanks in advance,
Jon

Reply

Hey Jon,

Hm, weird error, I don't have many ideas. Try to check any new updates for Selenium server and FireFox. Also, could you try to restart your Mac and try to run tests again? If it doesn't work, try to start selenium server with sudo, maybe you have permissions issue. Btw, what version of Behat do you have? Could you try to upgrade it too?

Cheers!

Reply
Default user avatar
Default user avatar Martin Bittner | posted 4 years ago

So Behat is to do integration testing, to make sure everything fits and works together.
Do you still use phpunit to test your model?
Would you mind explaining your overall testing strategy / organization. What are all the components (phpunit, behat, alice, etc) you use and how do you use them.
Thanks

Reply

Yo @disqus_EwCSvPkx4r!

Great question :). Let me give you a quick run-down of what we do here at KnpUniversity:

1) Obviously, we use Behat. This is probably our main tool, because ultimately we're concerned most about the *behavior* of the features we're building. If the feature has any decent complexity, we'll cover it with a Behat scenario (and often, when we build a new big feature, we'll add the features/scenarios first)

2) When we're building a feature, we might find out that a specific function is quite complex. We *could* write several Behat scenarios to cover the different input/output of that function, but it would be easier if we tested the function (unit) directly. In this case, we'll use PhpUnit (we don't [yet] use PhpSpec, but that's also a great tool for this).

3) But wait! Sometimes when you're unit testing that complex function, you realize that if you mock all the dependencies, all the complexity is gone! For example, if a function makes a complex database query and then uses that output to call 4 other services... then once you've mocked all of that out... there is really no "meat" left in your test. In this cases, it's better to do an integration test: a PhpUnit test where you boot the container and actually use your *real* service (and so also, your real database connection). This is a *great* way to test big "units" of your code. Of course, those tests are slower and you need to worry about setting up your database - i.e. making sure that specific tables have specific records in them to support your test. Btw, I don't typically load my fixtures in tests (the same is true for Behat tests) - usually I just make sure that whatever tables I'm concerned with have specific data in it.

So, Behat & PhpUnit, but I use PhpUnit for both unit tests, and less pure (but super pragmatic) integration tests.

Cheers!

3 Reply
Default user avatar

Hey I have a question. Do you know how to setup the database in order to run these scenarios?

Reply

Hi Miya!

Definitely :). We *usually* include detailed install instructions in the README in the download, but it looks like we forgot to add those this time! Shame on us! I've just updated the README file with details - you can see it here: https://github.com/knpunive.... I'm deploying that to the code download right now.

If that doesn't answer all of your questions, please let me know!

Cheers!

Reply

Hey there!
I found this tutorial really good, I really appreciate your effort doing it.
Also a I have a question :]

How do you press a button tag using symfony-extension driver ?
I'm getting this error over and over(I'm going crazy) - Behat\Symfony2Extension\Driver\KernelDriver supports clicking on links and submit or reset buttons only. But "button" provided

My step is - When I press "Actions" from MinkExtension class, method pressButton($button)
And my html is like this:
<button data-toggle="dropdown" type="button" class="btn btn-default dropdown-toggle">
Actions
</button>

Thanks in advance

Reply

Hey Diego,

In your case I simply replace a button `<button type="button">` tag with a link `<a href="javascript:void(0);">` tag. If you use Twitter Bootstrap - this link will exactly look like a button. But I'm wondering about other solutions here too )

Cheers!

Reply

Hello Victor

I just can't imagine why symfony's driver don't support clicking on button tags, but well ... thanks for your reply ;]

Reply

Hey guys!

You're doing the right thing - but you need to use a JavaScript-based driver if you want to do this. The reason is that a button (except for a submit and reset button) has *no* functionality outside of JavaScript. What I mean is: if I click a "submit" button, it submits a form. But if I click your button (in an environment that has no JavaScript), nothing will happen: this button has no native functionality. The Symfony2Extension is basically trying to warn you about this.

So, solutions:

A) Don't click this button :). If you're clicking it simply so that a drop-down can open and you can click a link/button that's *inside* of that drop-down, you can simply skip clicking this first button and click/press the "hidden" link/button directly. Of course, you can't do this in a "real browser" (because the link/button is hidden), but you can with the Symfony2Exension - because it's simply parsing the HTML and can click/press any button you want.

B) Use a JavaScript-based driver (like Selenium).

Both are good solutions - (A) feels like cheating, but I don't think it is - I'm not worried about testing that the drop-down works, so it's cool to skip it if you want.

Cheers!

2 Reply

Hey Ryan!
Thanks for your answer

I ended doing your solution A ;]

Reply
Default user avatar

Hi, How can I switch from one window to another. For example, my scenario is as follows -

Scenario Outline: User login with Facebook
When I press "siginFacebook"
And I switch to the new tab
And I fill in "<email>" for "email"
And I fill in "<password>" for "pass"
And Click the "u_0_2" select by "id"

In this stage, as facebook login works, so popup window close automatically and it generates an error -
"Window not found. The browser window may have been closed."

Do you know how to come back to my original window after a successful facebook login?

Reply

Hi Bartek!

Yes, I have done this stuff before with a client (at least with iframes, but I think also with windows) - some of the details are fuzzy, but we were totally able to pull it off. As you probably already know, the key methods are on the Session: https://github.com/minkphp/.... I would use getWindowName() and getWindowNames() (https://github.com/minkphp/... to debug and figure out what all the window names are being called during the process.

I know that's vague, but I hope it helps! Cheers!

Reply
Cat in space

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