Behat like a boss: meta-steps

Published on

Dec 14, 2011

how2tips

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.

Written by

KNP Labs
KNP Labs

Comments