If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
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
.
... 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.
First, in FeatureContext
I had you extend MinkContext
. Remove that now:
... 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:
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:
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
:
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:
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
:
... 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
:
... 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:
... 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!
ah! never mind ... i needed RawMinkContext! that way i can use $this->getMink()->getSession();
Nice work! RawMinkContext is the real important guy - it extends MinkContext, which just gives you the free definitions.
Cheers!
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 :)
Ah, you're right! Thanks for pointing that out. I created an issue and we should fix it soon :). https://github.com/knpunive...
Thanks!
// 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
}
}
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?