Generating Gherkin step definitions from Codeception modules 02

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 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
Generating WPDb module steps with `steppify` command and configuration file
Generating WPDb module steps with `steppify` command and configuration file

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
Generating WPBrowser module steps with `steppify` command and configuration file
Generating WPBrowser module steps with `steppify` command and configuration file

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
Running acceptance tests with new step definitions
Running acceptance tests with new step definitions

On GitHub

The steppify command is available on GitHub.

I appreciate your input