Customizing step definition generation with Codeception and Steppify.
Not just WordPress
While in the example below I’m using WordPress specific modules from the wp-browser package the steppify command will work with any Codeception module.
Recap
In my previous post I’ve set out to write and run a Gherkin scenario using the Codeception steppify
command to generate Gherkin step definitions from existing Codeception modules.
The starting modules are WPBrowser
and WPDb
from the wp-browser module library and the feature I was able to run is the one below:
Feature: home
In order to read the latest posts
As a visitor
I need to see the latest posts on the homepage
Scenario: the home page will show the latest published posts in descending order
Given I have post in database
| post_type | post_title | post_status |
| post | Post 1 | publish |
| post | Post 2 | publish |
| post | Post 3 | publish |
| post | Post 4 | private |
| post | Post 5 | draft |
| post | Post 6 | publish |
When I am on page "/"
Then I see number of elements ".post" and expected 4
Using the steppify
command I was able to successfully run the feature and its only scenario with an AcceptanceTester
class merely using the two traits generated by the command:
<?php
use _generated\WPBrowserGherkinSteps;
use _generated\WPDbGherkinSteps;
class AcceptanceTester extends \Codeception\Actor
{
use _generated\AcceptanceTesterActions;
use WPBrowserGherkinSteps;
use WPDbGherkinSteps;
}
Customizing the step definition expression
In the home.feature
file above there are two expressions that, while working at different degrees, could use some tweaking.
I’d like the step in charge of populating the database with posts to read like:
Given I have posts in database
| post_type | post_title | post_status |
| post | Post 1 | publish |
| ... | ... | ... |
and just add an “s” to “post” for clarity.
The steppify
command will inherit step definition doc lines from module methods but modifying WPDb::havePostInDatabase
method signature to add the line defining the step expression is not an option here as I’m using the two modules as dependencies and those changes will be overridden on each composer update
.
To handle this case the steppify
command allows defining a configuration file to control the step definition generation; the file can be called in any way and has to be in Yaml format, I’ve called mine tests/_support/steppify.config.yml
and added the first configuration option:
modules:
WPDb:
methods:
havePostInDatabase:
generates: [given]
step: I have posts in database
With this file I’m telling the steppify
command:
- I want to control the step definition generated from the
WPDb::havePostInDatabase
method - the method should generate an expression that reads
I have posts in database
- the method should only generate a
@Given
definition as it makes little sense to have the step in any place but the scenarion set up phase
All it takes to apply the new rules is running the steppify
command again specifying that I want to use the configuration file:
codecept g:steppify WPDb --steps-config tests/_support/steppify.config.yml
[caption id=“attachment_3183” align=“aligncenter” width=“1153”] Generating WPDb module steps with `steppify` command and configuration file[/caption]
Looking up the regenerated step definition trait in tests/_support/_generated/WPDbGherkinSteps.php
file I can see the method signature and doc block has been correctly generated:
/**
* [!] Method is generated from steppify task. Documentation taken from corresponding module.
*
* @Given I have posts in database
*
* @see \Codeception\Module\WPDb::havePostInDatabase()
*/
public function step_havePostInDatabase(\Behat\Gherkin\Node\TableNode $data) {
$args = steppify_convertTableNodesToArrays(func_get_args(), $iterations);
if(!empty($iterations)) {
$returnValues = [];
foreach($iterations as $iteration){
$returnValues[] = $this->getScenario()->runStep(new \Codeception\Step\Action('havePostInDatabase', $iteration));
}
return $returnValues;
}
return $this->getScenario()->runStep(new \Codeception\Step\Action('havePostInDatabase', $args));
}
Another modification I’d like to make is to have the last step, currently reading Then I see number of elements ".post" and expected 4
, read instead Then I see ".post" 4 times
.
Once again to the configuration file adding, this time, a configuration for the WPBrowser
module (this specific method is inherited from the PHPBrowser
module though):
modules:
WPDb:
methods:
havePostInDatabase:
generates: [given]
step: I have posts in database
WPBrowser:
methods:
seeNumberOfElements:
generates: [then]
step: "I see :selector :expected times"
To note here:
- I’m telling the command it should onlye generate a
@Then
step definition for the method - I’m using parameter placeholders in the step definition (see Behat documentation here)
- the names of the two parameters match those used by the
PHPBrowser::seeNumberOfElements
method:public function seeNumberOfElements($selector, $expected);
- the order of the parameters is maintained;
I see :number :selector elements
would not work
Time to regenerate WPBrowser
step definitions again:
codecept g:steppify WPBrowser --steps-config tests/_support/steppify.config.yml
[caption id=“attachment_3184” align=“aligncenter” width=“1153”] Generating WPBrowser module steps with `steppify` command and configuration file[/caption]
Update the feature to use the new step definitions:
Feature: home
In order to read the latest posts
As a visitor
I need to see the latest posts on the homepage
Scenario: the home page will show the latest published posts in descending order
Given I have posts in database
| post_type | post_title | post_status |
| post | Post 1 | publish |
| post | Post 2 | publish |
| post | Post 3 | publish |
| post | Post 4 | private |
| post | Post 5 | draft |
| post | Post 6 | publish |
When I am on page "/"
Then I see ".post" 4 times
And run the acceptance
suite again:
codecept run acceptance -vvv
[caption id=“attachment_3185” align=“aligncenter” width=“1153”] Running acceptance tests with new step definitions[/caption]
On GitHub
The steppify
command is available on GitHub.