Behat like a boss: meta-steps

Dec 15, 2011 − Previously, in "Behat like a boss", we learned how to write custom steps. One thing that bothered me when I first discovered Behat and started writing custom steps was that I had to know an existing step's method name (e.g. visit) in order to reuse it in my steps. Actually, you don't have to, there is a very simple way to use an existing step, and even create a step that runs multiple steps at the same time.

{abstract}

Say you implemented some kind of authentication form in your application, and
you want to write a scenario that requires you to be logged in. You could
write the following:

Feature: View users list
    In order to manage my users
    As an Administrator
    I need to be able to list my users

Scenario: View users list
    Given I am on "/"
    When I go to "/login"
    And I fill in the following:
        | Login | Administrator |
        | Password | supadupaadminpasswd |
    And press "Login"
    And follow "Users list"
    Then I should see "List of users"

It works, but it’s a bit tedious. And what about code reuse? You certainly
don’t want to have to worry about filling in the login form on every scenario
where you need to be authenticated! That would be insane! And actually, if you
read part 1 of this series, you already know that we can write a custom step
for authenticating:

Scenario: View users list
    Given I am logged in as Administrator
    And I am on "/"

With its basic implementation:

class FeatureContext
{
    /**
     * @Given /^(?:|I )am logged in as Administrator$/
     */
    public function iAmLoggedInAsAdministrator()
    {
        $this->visit('/login');
        $this->fillField('Login', 'Administrator')
        $this->fillField('Password', 'supadupaadminpasswd');
        $this->pressButton('Login');
    }
}

It works, but it’s far from being optimal because you have to know a bit more
of the internals that you’d really need to know if you knew the internals a
bit more. Wait, what? Well, if you knew about meta-steps, you wouldn’t need to
know about Mink’s step implementations :-)

A meta-step, put shortly, is a step that executes several steps at a time.
Concretly, a meta-step is your average step, except that it returns an array of
steps. A quick example:

use BehatBehatContextStep;

class FeatureContext
{
    /**
     * @Given /^(?:|I )am logged in as Administrator$/
     */
    public function iAmLoggedInAsAdministrator()
    {
        return array(
            new StepWhen('I am on "/login"'),
            new StepWhen('I fill in "Login" with "Administrator"'),
            new StepWhen('I fill in "Password" with "supadupaadminpasswd"'),
            new StepWhen('I press "Login"'),
        );
    }
}

Tada! Now you can leverage your knowledge of existing steps without having to
know their actual calling methods.

And that’s it for today! Next time you will learn how to automatically run steps
before each scenario, which can come handy when you’d like to have a clean
database to play with ;-)

Everzet.

  • 2018-06-22 OskarStark

    It is not working anymore :(

    https://github.com/KnpLabs/...

    But this should be deprecated soon, too

  • 2018-06-22 OskarStark

    The classes changed a bit.

    One Example here: https://gist.github.com/cys...

    My Code:
    use Behat\Behat\Definition\Call as Step;

    /**
    * @When /^the Column-Switcher should be working with field "([^"]*)"$/
    */
    public function theColumnSwitcherShouldBeWorkingWithField($field)
    {
    return [
    new Step\Given("I should see the Column-Switcher"),
    new Step\Then("I should not see \"$field\" list column"),
    new Step\When("I click the Column-Switcher"),
    new Step\Then("I select \"$field\" on Colum-Switcher"),
    new Step\Then("I click the Column-Switcher"),
    new Step\Then("I should see \"$field\" list column"),
    ];
    }

    Maybe it could help someone else :-)