Buy

Behat Loves Mink (Free Definitions from MinkExtension)

Behat parses scenarios and Mink is really good at browsing the web. If we combine their powers, we could start having steps that look a lot like what we have in search.feature.

11 lines features/search.feature
... lines 1 - 5
Scenario: Search for a word that exists
Given I am on "/"
When I fill in "searchTerm" with "Samsung"
And I press "search_submit"
Then I should see "Samsung Galaxy S II"

For the Background step, we now know we could create a matching definition in FeatureContext and easily use Mink's session object to actually go to that URL. But earlier when we ran this scenario, it worked... so there must already be something tie'ing Behat and Mink together.

Let's see what's happening.

Free Behat Steps

First, in FeatureContext I had you extend MinkContext. Remove that now:

86 lines features/bootstrap/FeatureContext.php
... lines 1 - 12
class FeatureContext implements Context, SnippetAcceptingContext
... lines 14 - 86

When we run Behat, it needs to know all of the step definition language that's available. You can see that list by passing a -dl to the Behat command:

php vendor/bin/behat -dl

This shows the four ls definitions we built. So, Behat opens the FeatureContext class, parses out all of the @Given, @When and @Then annotations, and prints a final list here for our enjoyment.

When we add more step definitions, this list grows. And if we use something that isn't here yet, Behat very politely prints out the function for us in the terminal.

In behat.yml we added this MinkExtension configuration:

12 lines behat.yml
default:
... lines 2 - 6
extensions:
Behat\MinkExtension:
... lines 9 - 12

This library ties Behat and Mink together and gives us two cool things. First, it lets us access the Mink Session object inside of FeatureContext. We'll see that soon.

For the second thing, add a new config called suites: and a key under that called default: with a contexts: key. We'll talk about suites later. Under contexts, pass FeatureContext and Behat\MinkExtension\Context\MinkContext:

12 lines behat.yml
default:
suites:
default:
contexts:
- FeatureContext
- Behat\MinkExtension\Context\MinkContext
... lines 7 - 12

Now, Behat will look inside FeatureContext and MinkContext for those definition annotations.

Let's see what that gives us: run behat with the -dl option again:

php vendor/bin/behat -dl

Boom! Now we see a huge list! These include definitions for all common web actions, like When I go to or When I fill in "field" with "value". This includes the stuff we're using inside of search.feature:

11 lines features/search.feature
... lines 1 - 5
Scenario: Search for a word that exists
Given I am on "/"
When I fill in "searchTerm" with "Samsung"
And I press "search_submit"
Then I should see "Samsung Galaxy S II"

So that's why that scenario already worked.

Let's take a look at where these come from. I'll use shift+shift and search for MinkContext:

487 lines vendor/behat/mink-extension/src/Behat/MinkExtension/Context/MinkContext.php
... lines 1 - 21
class MinkContext extends RawMinkContext implements TranslatableContext
{
/**
... lines 25 - 26
* @Given /^(?:|I )am on (?:|the )homepage$/
* @When /^(?:|I )go to (?:|the )homepage$/
*/
public function iAmOnHomepage()
{
$this->visitPath('/');
}
... lines 34 - 75
/**
... lines 77 - 78
* @When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/
*/
public function pressButton($button)
{
$button = $this->fixStepArgument($button);
$this->getSession()->getPage()->pressButton($button);
}
... lines 86 - 485
}

This looks just like our FeatureContext, but has a bunch of goodies already filled in.

So, why did I use this exact language inside of my scenario originally? Because, I'm lazy, and I knew if I followed the language here, I'd get all this functionality for free. And I'm from the midwest in the US: we love free things.

I'll take off the @javascript line:

11 lines features/search.feature
... lines 1 - 4
Scenario: Search for a word that exists
... lines 7 - 11

Since we don't need JavaScript, and now we should be able to run our search feature. Perfect!

Leave a comment!

  • 2016-02-17 Victor Bocharsky

    Thank you for this issue! Already fixed in 640dfc0 and published.

  • 2016-02-17 weaverryan

    Ah, you're right! Thanks for pointing that out. I created an issue and we should fix it soon :). https://github.com/knpuniversi...

    Thanks!

  • 2016-02-17 Dejan

    Hello, there's a mistake that you are showing the FeatureContext.php file in the script instead of behat.yml when configuring the default suite :)

  • 2015-12-01 weaverryan

    Nice work! RawMinkContext is the real important guy - it extends MinkContext, which just gives you the free definitions.

    Cheers!

  • 2015-12-01 AJ

    ah! never mind ... i needed RawMinkContext! that way i can use $this->getMink()->getSession();

  • 2015-12-01 AJ

    Hi. I removed extends MinkContext and added Behat\MinkExtension\Context\MinkContext but when I ran my script again I get a undefined method FeatureContext::getSession() could you help explain why?