Testing your Sylius application with Behat

Testing your Sylius application with Behat

Introduction

Have you extended your Sylius webshop with custom resources and now want to test them? In this blog post, I’ll walk you through the steps to set up a basic Behat suite for testing your Sylius resources.

Prerequisites

For the purposes of this tutorial, I’m going to assume that you already have a Sylius application that is operational, complete with custom resources and grids. We will use a custom Brand resource as our example for testing.

Behat Components

Behat is a BDD (Behavior Driven Development) framework that enables the writing of human-readable stories to describe the behavior of your application.

Our suite will utilize the following key components:

  • Scenarios: Scenarios in Behat are crafted using the Gherkin language, offering a format that’s understandable by humans. They outline your application’s behavior in plain language.

  • Contexts: Contexts in Behat are classes that house the definitions for your scenarios’ steps. They serve to convert our stories into executable code.

  • Pages: Pages in Behat are classes that model the pages within your application, containing methods to interact with various page elements.

A suite may incorporate multiple contexts and pages to accommodate the complexity of your application and the complexity of tests required.

Creating our scenario

For our scenario, i wanted to pick something that would not be too complex, but still provide a good example.

Our scenario will check if the user can add a brand in the admin interface.

We’ll define our feature in the features/admin/brands.feature file.

@managing_brands
Feature: Managing brands
    In order to configure my store
    As a store owner
    I want to be able to manage brands

    Background:
        Given the store is available in "English (United States)"
        And I am logged in as an administrator

    @ui
    Scenario: Adding a new brand
        When I want to create a new brand
        And I specify its name as "Nike"
        And I add it
        Then I should be notified that it has been successfully created
        And the brand "nike" should appear in the registry

Lets break this down a bit.

  • Feature: The feature describes the overall goal of the scenarios. In this case, we want to manage brands.

  • Background: The background sets the stage for the scenarios. Here we make sure we have a store available with the English (United States) locale, and we are logged in as an administrator.

  • Scenario: The scenario describes the steps we want to execute. In this case, we want to create a new brand with the name “Nike”. It’s important to note that we can add multiple scenarios to a feature, each describing a different aspect of the feature.

To structure our code, we’ll place our custom code in the src/Behat folder. This folder will contain the Behat contexts, pages, and resources.

Setting up our Page

With the scenario in place, we can start setting up our page.

! Remember, the page is a class that models the pages within your application
It contains methods that interact with the page elements.
<?php

namespace App\Behat\Page\Admin\Brand;

use Sylius\Behat\Page\Admin\Crud\CreatePage as BaseCreatePage;

final class CreatePage extends BaseCreatePage
{
    public function nameIt(string $name): void
    {
        $this->getDocument()->fillField('app_brand_name', $name);
    }

    public function add()
    {
        $this->getDocument()->pressButton('Create');
    }
}

So, what have we done here?

  • We created a new class CreatePage that extends the BaseCreatePage class.
  • We added two methods, nameIt and add.
  • The nameIt method fills in the name field for the brand.
  • The add method presses the create button.

Finally, we need to register our page. We can do this by adding the following configuration:

# config/services_test.yaml

services:
    App\Behat\Page\Admin\Brand\CreatePage:
        parent: sylius.behat.page.admin.crud.create
        public: false
        arguments:
            - "app_admin_brand.brand_create" # This is the route of the page

Creating our context

With the page ready to use, we can create our context.

! Remember, the context is a class that contains the step definitions for your scenarios.
It translates our readable stories into executable code.
<?php

namespace App\Behat\Context\Admin;

use Behat\Behat\Context\Context;

class BrandContext implements Context
{

}

We’ll leave our context empty for now, as Behat can help us a bit with the step definitions.

Setting up our testing suite

To setup our suite, we’ll create the following file

# src/Behat/Resources/suites.yaml
default:
    suites:
        managing_brands:
            contexts:
                - sylius.behat.context.hook.doctrine_orm
                - sylius.behat.context.hook.session
                - sylius.behat.context.setup.admin_security
                - sylius.behat.context.transform.locale
                - sylius.behat.context.setup.locale

                - App\Behat\Context\Admin\BrandContext
            
                filters:
                    tags: "@managing_brands&&@ui"

As you can see, we attached multiple contexts to our suite. These are some of the default contexts provided by Sylius, and our custom BrandContext. The default contexts provide us with some basic functionality, like setting up the shop, and the security context.

Sylius comes with a default Behat config, which we can extend to add our custom suites. For that, we’ll create a new behat.yml file based on the default configuration.

cp behat.yml.dist behat.yml

Then, we’ll adjust the behat.yml file to include our custom suite.

# behat.yml
imports:
    - ...
    - "src/Behat/Resources/suites.yaml"

Configuring our custom context

Lets go back to our custom context. Remember, we still need to define our steps!

Luckily, behat can help us with those steps! Lets run the followig command, and see what behat tells us.

$ php vendor/bin/behat features/admin/brands.feature --append-snippets --snippets-type=turnip

Magic! It notices we have some missing steps, and ask us to choose a context to generate the snippets.

 >> suite has undefined steps. Please choose the context to generate snippets:

  [0] None
  [1] Sylius\Behat\Context\Hook\DoctrineORMContext
  [2] Sylius\Behat\Context\Hook\SessionContext
  [3] Sylius\Behat\Context\Setup\AdminSecurityContext
  [4] Sylius\Behat\Context\Transform\LocaleContext
  [5] Sylius\Behat\Context\Setup\LocaleContext
  [6] App\Behat\Context\BrandContext
 > 6

u src/Behat/Context/Admin/BrandContext.php - `i want to create a new brand` definition added
u src/Behat/Context/Admin/BrandContext.php - `i specify its name as "Nike"` definition added
u src/Behat/Context/Admin/BrandContext.php - `i add it` definition added
u src/Behat/Context/Admin/BrandContext.php - `i should be notified that it has been successfully created` definition added
u src/Behat/Context/Admin/BrandContext.php - `the brand "Nike" should appear in the registry` definition added

If we go and have a look in our context, we can see the added steps.

# ...
    /**
     * @When I want to create a new brand
     */
    public function iWantToCreateANewBrand()
    {
        throw new PendingException();
    }
# ...

We can now start implementing the steps in our context.

Below, we’ve added the functions for two scenario’s. You can see the complete example implementation here.

    /**
     * @When I want to create a new brand
     */
    public function iWantToCreateANewBrand()
    {
        $this->createPage->open();
    }

    /**
     * @When I specify its name as :name
     */
    public function iSpecifyItsNameAs(string $name)
    {
        $this->createPage->nameIt($name);
    }

Running our tests

With everything in place, we can now run our tests.

$ php vendor/bin/behat features/admin/brands.feature

@manading_brands
Feature: Managing brands
    In order to configure my store
    As a store owner
    I want to be able to manage brands

    Background:
        Given the store is available in "English (United States)"
        And I am logged in as an administrator

    @ui
    Scenario: Adding a new brand
        When I want to create a new brand
        And I specify its name as "Nike"
        And I add it
        Then I should be notified that it has been successfully created
        And the brand "nike" should appear in the registry

1 scenario (1 passed)
8 steps (8 passed)

Wohoo, we have a passing suite!

Conclusion

In this post, we’ve set up a basic Behat suite to test our custom Sylius resources. We’ve created a scenario, a page, and a context to test the creation of a brand in the admin interface.

Behat is a powerful tool that can help you test your application in a human-readable way. By writing scenarios in the Gherkin language, you can describe the behaviour of your application in plain text, making it easier to understand and maintain.

I hope this post has given you a good starting point to test your Sylius resources with Behat. Feel free to reach out to me on Twitter if you have any questions or feedback.

Happy testing!

Sources