Symfony2 Keep Your Project Guided with Behat and Mink

This is a summary of how to start with a project on BehatBundle with Mink.

// deps
// autoload.php
'Behat\Mink' => __DIR__.'/../vendor/behat/mink/src',
'Behat\MinkBundle' => __DIR__.'/../vendor/bundles',
'Behat\SahiClient' => __DIR__.'/../vendor/behat/sahi/src',
'Behat\BehatBundle' => __DIR__.'/../vendor/bundles',
'Behat\Behat'       => __DIR__.'/../vendor/behat/Behat/src',
'Behat\Gherkin'     => __DIR__.'/../vendor/behat/Gherkin/src',
'Buzz'             => __DIR__.'/../vendor/buzz/lib',
// AppKernel.php
$bundles[] = new Behat\MinkBundle\MinkBundle();
$bundles[] = new Behat\BehatBundle\BehatBundle();
// config_test.yml
    base_url:   http://h.local/web/app_dev.php
        host:     x.local
    show_cmd:   google-chrome %%s
    #default_session: sahi
    default_session: symfony
behat: ~

Notice how we escape the % sign on the show_cmd above.
Notice also that we want to explicitly set the default_session if it is different than symfony only. Or in the case when we want to avoid typing a specific driver session for every scenario:

  Scenario: ....

Or for the default case:

  Scenario: ....

Now we will generate the structure for starting with Behat:

php app/console --env=test behat --init src/Acme/MyDemoBundle
php app/console --env=test behat --init @MyDemoBundle

Both statements above are equivalent, one using the path and the other using the logical name.

# php app/console --env=test behat @MyDemoBundle
No scenarios
No steps

Now if you issue the command below you will get the following response:

# php app/console behat @MyDemoBundle --definitions
Given /^(?:|I )am on "(?P<page>[^"]+)"$/                                                     - Opens specified page.
 When /^(?:|I )go to "(?P<page>[^"]+)"$/                                                     - Opens specified page.
 When /^(?:|I )reload the page$/                                                             - Reloads current page.
 When /^(?:|I )move backward one page$/                                                      - Moves backward one page in history.
 When /^(?:|I )move forward one page$/                                                       - Moves forward one page in history
 When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/                                           - Presses button with specified id|name|title|alt|value.
 When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/                                            - Clicks link with specified id|title|alt|text.
 When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/          - Fills in form field with specified id|name|label|value.
 When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/           - Fills in form field with specified id|name|label|value.
 When /^(?:|I )fill in the following:$/                                                      - Fills in form fields with provided table.
 When /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/         - Selects option in select field with specified id|name|label|value.
 When /^(?:|I )check "(?P<option>(?:[^"]|\\")*)"$/                                           - Checks checkbox with specified id|name|label|value.
 When /^(?:|I )uncheck "(?P<option>(?:[^"]|\\")*)"$/                                         - Unchecks checkbox with specified id|name|label|value.
 When /^(?:|I )attach the file "(?P<path>[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/             - Attaches file to field with specified id|name|label|value.
 Then /^(?:|I )should be on "(?P<page>[^"]+)"$/                                              - Checks, that current page PATH is equal to specified.
 Then /^the url should match "(?P<pattern>(?:[^"]|\\")*)"$/                                  - Checks, that current page PATH matches regular expression.
 Then /^the response status code should be (?P<code>\d+)$/

Now in order to make an entry point we issue the command to generate the structure of the Features:

php app/console --env=test behat @MyDemoBundle --init

This will create the structure for us and we can add feature files such as:

// open feature1.feature
# Features/pickup.feature
Feature: DemoSpecification1
  In order to fill a form
  As a website user
  I need to be able to persist an entity
#  @mink:sahi
  Scenario: Persisting a new entity
    Given I am on "/persist/"
    And Given I am authenticated
    And I press "completeButton"
    #Then I should see "successfully persisted"
    Then show last response

This code above will get me the structure of the function i need to implement on FeatureContext.php where the steps definitions are defined:

       * @Given /^Given I am authenticated$/
    public function givenIAmAuthenticated()
        $page = $this->getSession()->getPage();
        $username_field = $page->findField('username');
        $password_field = $page->findField('password');
        $button_submit = $page->findButton('');

Now if we rerun the command:

// php app/console --env=test behat @MyDemoBundle
 successful log here
1 scenario (1 passed)
3 steps (3 passed)

This will be a friend:

The idea is now that specifications done as features will lead development and direct it in a much efficient way. Getting the job done will be provided by how many of this specifications are implemented and how many of them are covered.

Notice also that if you are using sahi, and you can’t get it to work it is because one reason: You don’t have it installed. Ye sahi needs to be downloaded from here.

For me it was this command after I downloaded it to get it installed:

java -jar  ~/Desktop/install_sahi_v35_20110719.jar

And also before running your tests issue:

~/sahi/userdata/bin$ ./

Provided you have installed sahi at your home directory.

Now happy coding! and dont’ forget to help me help you more with the link on the sidebar.

I was having problems with this error when using sahi:
500 page for too many parameters
Warning: session_start(): The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9

But they were resolved by an issue on github.

And in addition I was able to sort out the assets issue hard coding a line like this for feeding the assets:

<link rel="stylesheet" href="http://mydomain.local/web/css/style.css" />

Now we run the same command:

php app/console behat --env=test @MyDemoBundle/MyDemo.feature:13 --no-paths

This is for the bundle MyDemoBundle and for MyDemo feature file and the scenario starting at line 13. There are tags and other niceties which you can look up on the documentation.

Thanks Stof for helping me getting through the rough unknown places.

6 thoughts on “Symfony2 Keep Your Project Guided with Behat and Mink

  1. Have you got any further with the session_start() issue? I’ve found this isn’t confined to just the testing side of things via Sahi, but is replicated in my browser during normal development as well. It seems to have only surfaced in the past week or so, so I don’t know if it’s a core SF2 problem or not…

  2. Rich I believe you are right, it is made worse with the sahi testing
    i have seen it off and on on regular development, however whenever i refresh the browser it is gone. But true sahi testing made it worse completely not able even to work when refreshing.

    Any hints or history on you getting this? I am trying to draw a solution too.

  3. Hi,

    I follow your tutorial, and i have this error message:
    ServiceNotFoundException: The service “behat.mink” has a dependency on a non-existent service “test.client”.

    Could you help me to fix that ?

Leave a Reply

Your email address will not be published. Required fields are marked *