BDD, Behat, Mink and other Wonderful Things

Buy Access

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

Questions? Conversation?

  • 2017-06-13 Victor Bocharsky

    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!

  • 2017-06-12 Jon Robinson

    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

  • 2017-04-26 Victor Bocharsky

    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!

  • 2017-04-25 Andrew Pang

    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)

  • 2017-04-14 Victor Bocharsky

    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!

  • 2017-04-13 Andrew Pang

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

  • 2017-04-11 weaverryan

    Yo Martin Bittner!

    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!

  • 2017-04-07 Martin Bittner

    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

  • 2017-02-13 Victor Bocharsky

    Thanks for sharing this!

    Cheers!

  • 2017-02-11 fydh

    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)

  • 2016-11-07 weaverryan

    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.

  • 2016-11-07 Syed Abouzar Mehdi

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

  • 2016-10-26 weaverryan

    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!

  • 2016-10-26 Syed Abouzar Mehdi

    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

  • 2016-10-25 weaverryan

    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!

  • 2016-10-25 Syed Abouzar Mehdi

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

  • 2016-10-25 Syed Abouzar Mehdi

    Victor Bocharsky 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)
    ----

  • 2016-10-03 Victor Bocharsky

    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!

  • 2016-09-30 Syed Abouzar Mehdi

    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 ?

  • 2016-09-29 Victor Bocharsky

    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?

  • 2016-09-29 Syed Abouzar Mehdi

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

  • 2016-09-28 Victor Bocharsky

    Hey Syed,

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

    Cheers!

  • 2016-09-28 Syed Abouzar Mehdi

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

  • 2016-09-22 Syed Abouzar Mehdi

    thanks fixed this one

  • 2016-09-22 Victor Bocharsky

    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.

  • 2016-09-21 Syed Abouzar Mehdi

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

  • 2016-09-21 Victor Bocharsky

    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!

  • 2016-09-21 Victor Bocharsky

    You're welcome!

    BTW, one more useful command which helped me a lot when I had discovered it: $ behat -dl and $ behat -di - which print all available step definitions. I think it might be useful for you too.

    Cheers!

  • 2016-09-21 Syed Abouzar Mehdi

    Victor Bocharsky 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()

  • 2016-09-20 Syed Abouzar Mehdi

    Victor Bocharsky thanks man , I got it what you said. let me try to extend my FeatureContext with Mink and try to run it. will hit you in a while if i get stuck in something :D

  • 2016-09-20 Victor Bocharsky

    Hey Syed,

    I can help you with your questions:
    1. The --init command tells Behat to provide you with things missing to start testing your feature. In your case - it’s probably a FeatureContext class under the features/bootstrap/FeatureContext.php file. That's it. If you already have this files - nothing will happen if you run this command again. Run $ behat --append-snippets if you want Behat to add missing steps to the main context itself or $ behat --append-to=APPEND-TO to append missing steps to the specified context file. Check more information about available commands with $ behat --help.
    2. Actually, it happens due to your *empty* FeatureContext extends default feature context which already has some pre-defined steps. Probably you extend MinkContext, but it depends on your actions. So for example, open MinkContext in your code editor and you will see this pre-defined steps there.

    Cheers!

  • 2016-09-19 Syed Abouzar Mehdi

    weaverryan i have few questions things are confusing as
    1: Once i have created feature file and feature.context can I edit my feature file and run --init again! to recreate featurecontext with my modified Feature file? ( as I tried it but nothing happens)
    2: Another thing sometimes when i do new installation. i just write the feature file and everything works fine without writing a single word to FeatureContext. how this works actually? what my scenario was to visit a website and login there and then go to another sub page from given link! and it worked perfectly without writing a single code in FeatureContext!

  • 2016-09-15 weaverryan

    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!

  • 2016-09-14 Miya

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

  • 2016-09-12 weaverryan

    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!

  • 2016-09-09 Syed Abouzar Mehdi

    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 :$

  • 2016-09-07 Victor Bocharsky

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


    default:
    extensions:
    Behat\MinkExtension\Extension:
    browser_name: chrome
  • 2016-09-07 Syed Abouzar Mehdi

    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.

  • 2016-09-07 Victor Bocharsky

    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.

  • 2016-09-06 Abuzar Mehdi

    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

  • 2016-07-18 Diego Aguiar

    Hey Ryan!
    Thanks for your answer

    I ended doing your solution A ;]

  • 2016-07-15 weaverryan

    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!

  • 2016-07-15 Diego Aguiar

    Hello Victor

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

  • 2016-07-14 Victor Bocharsky

    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!

  • 2016-07-13 Diego Aguiar

    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

  • 2016-03-22 Dan Costinel

    I still experience an error when testing. Do you know why my test fails? http://imgur.com/Ts6E3w1

  • 2016-03-22 Dan Costinel

    Nevermind guys. I've missplaced the security. Instead of putting it in app/config/security.yml, I've placed it in app/config/config.yml... Sorry!

  • 2016-03-22 Dan Costinel

    Hello guys. I copied all the "finish" files into a fresh Symfony 2.7.10 project. I changed few things in your files, in order to make the project work, and I finally did it. Now I'm stuck at login, as I can't login with the provided credentials (user=admin, pass=admin). I've re-created the db with the link inside my app ( /_db/rebuild ) - nothing, I've deleted entirely my db, and I've re-created it with doctrine:database:create, and doctrine:schema:update --force, but still nothing. I get the same error message when I try to login: Invalid credentials. I tried to generate, online, the bcrypt hash for the string "admin" using http://bcrypthashgenerator...., and replacing the password field value within user table, but without any good result. Any ideas on how to solve it, maybe without re-creating all from the start? Thank you!!

  • 2016-01-19 weaverryan

    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!

  • 2016-01-19 Bartek

    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?

  • 2015-10-13 weaverryan

    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!

  • 2015-10-13 truthrevealer

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

  • 2015-10-13 Richard Bagshaw

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