“There’s nothing in the world more powerful than a good story”, said the king of wit and wisdom, Tyrion Lannister.

The power of stories and good communication empowers a collaborative and efficient software delivery. Evolving out of agile methodologies, Behavior Driven Development (BDD) technologies leverage this power to the fullest to automate the testing process. Behat is one such BDD technology that enables automated testing using “ubiquitous language”. Let’s learn more about Behat, Mink, Gherkin and how to implement it in Drupal.

behat drupal

What is Behat?

Behat is an open source PHP framework that is used to automate testing by leveraging Behavior Driven Development (BDD). A BDD approach ensures quality software delivery by focusing on continuous communication and simple text stories. With BDD the tester builds test cases in human-readable language. Because of this, it is easy to get the entire team on the same page as everyone, right from the product owner to the developer, can understand and get continuous feedback about the current scenario. 

What is Gherkin?

The language used by the Behat tool is Gherkin, which is a business readable and domain-specific language. Gherkin also serves as a living documentation and reports can be generated to document each test run. This simple whitespace-based language uses simple language words as keywords. Indentations (using space/tab) and line endings define the structure for the test case. Although writing and understanding the language is easy, the end result should focus on enabling better collaboration, efficiency, automation and traceability. Test cases should be written intuitively, focus on important elements, avoid checking duplicate records and use good grammar.

What is Mink?

Mink is an open source browser controller that simulates a test scenario with the web application. Once the test cases are written, it needs to be executed and emulate user actions. With Mink, you can use the same test scenario and run it on various browser emulators like Goutte, Selenium, Chrome, Zombie, and more. While installing the Behat Drupal extension, you will see a dependency on Mink so make sure you have it installed as well.

Installation and implementation of Behat in Drupal

The official way to install Behat in your Drupal project is through Composer. Not only can it install Behat for you, but it will also be able to easily update you to the latest version later when one comes out.

•    Inside the project folder, run the command: 

$ composer require behat/behat

•    Or inside your composer.json file, add the require statement

    "require": {
                "behat/behat": "^3.0.0",
     “phpunit/phpunit”: “^5.0.0”
     }

•    Next, run composer install command in the terminal.
•    When it is done, you will also notice a new directory bin/ with a Behat file in it. This is the Behat executable and you will use it to run your tests and get debug information.
•    Next, create a file named behat.yml inside the root folder of the project. When Behat runs, it looks for a behat.yml file, which it uses for its configuration.

default:
  suites:
    default:
      contexts:
        - Drupal\DrupalExtension\Context\DrupalContext
  extensions:
    Behat\MinkExtension:
      goutte: ~
      base_url: http://example.org/  # Replace with your site's URL
    Drupal\DrupalExtension:
      blackbox: ~

To initialize the project, run the command: 

vendor/bin/behat –init

This creates a features/ folder and a bootstrap/FeatureContext.php default context file inside the features/ folder.

Writing Stories and Running tests with Behat

Our goal is to describe the stories in the most effective way. The stories are written in a human-readable language, Gherkin, with the extension .feature under the features/ directory.

Let’s imagine that you need to test whether you can add content to the Basic page content type in your site successfully or not. To do that, you must have access to the page to fill the fields and save it as an administrator. 

So, let’s write our first story:

Feature: Check basic page CT
 In order to create a page
 As an admin
 I want to access /node/add/page
 So that I can create a page

Scenario: Basic Page CT
 Given I am logged in as a user with the "administrator" role
 When I go to "/node/add/page"
 And I enter "Basic page title" for "edit-title-0-value"
 When I press "edit-submit"
 Then I should see "Basic page Basic page title has been created"

This file can be named basic_page.feature. Each feature can have many scenarios, which describe the specific behavior of the feature. Each scenario will have sections: 
•    Given - details the starting state of the system
•    When - includes the action the user takes
•    Then - describes what the user sees after taking action
•    And - to maintain the connectivity in the scenario. 
There is not much difference between Then, And, and But. These words are made available to make your scenarios natural and readable.

All feature files can be run by vendor/bin/behat. If you want to run a specific feature file, run vendor/bin/behat features/basic_page.feature. There is also a way to run a single scenario by just adding a line number where the scenario is defined: vendor/bin/behat features/basic_page.feature:11.

There are commands like vendor/bin/behat -dl which provides you all the statement syntax that is used in scenarios and vendor/bin/behat -di provides the syntax along with the examples.

How to write Feature files

Behat runs curl requests against URLs on your website, which makes the testing process quite fast, but also makes Behat lose the ability to test features that require Javascript. So, to test features we only need to do add @javascript tag before every scenario that requires Javascript, like this:

Feature: Check basic page CT
 In order to create a page
 As an admin
 I want to access /node/add/page
 So that I can create a page

@api @javascript
Scenario: Basic Page CT
 Given I am logged in as a user with the "administrator" role
 When I go to "/node/add/page"
 And I enter "Basic page title" for "edit-title-0-value"
 And I fill in wysiwyg on field "edit-body-0-value" with "Basic page content"
 When I press "edit-submit"
 Then I should see "Basic page Basic page title has been created"


To test this, run vendor/bin/behat. This will show you the undefined steps in the scenarios because the scenarios must map to a function.

behat


You can either copy-paste the code snippet to the context file FeatureContext.php or run vendor/bin/behat --dry-run --append-snippets

Then you can write the definitions for the functions in FeatureContext.php as shown:

<?php

use Behat\Mink\Exception\ExpectationException;
use Drupal\DrupalExtension\Context\RawDrupalContext;

/**
 * Defines application features from the specific context.
 */
class FeatureContext extends RawDrupalContext {

  /**
   * The mink context.
   *
   * @var Drupal\DrupalExtension\Context\MinkContext
   */
  protected $minkContext;

  /**
   * Initializes context.
   *
   * Every scenario gets its own context instance.
   * You can also pass arbitrary arguments to the
   * context constructor through behat.yml.
   */
  public function __construct() {
  }

  /**
   * Fill in wysiwyg on field.
   *
   * @Then I fill in wysiwyg on field :locator with :value
   */
  public function iFillInWysiwygOnFieldWith($locator, $value) {
    $el = $this->getSession()->getPage()->findField($locator);
    if (empty($el)) {
      throw new ExpectationException('Could not find WYSIWYG with locator: ' . $locator, $this->getSession());
    }
    $fieldId = $el->getAttribute('id');
    if (empty($fieldId)) {
      throw new Exception('Could not find an id for field with locator: ' . $locator);
    }
    $this->getSession()
      ->executeScript("CKEDITOR.instances[\"$fieldId\"].setData(\"$value\");");
  }

}

Now, run the command vendor/bin/behat and all the scenarios that are written must pass. The defined JS function will map the scenario statement “And I fill in wysiwyg on-field "edit-body-0-value" with "Basic page content".

Contact us

LET'S DISCUSS YOUR IDEAS. 
WE'D LOVE TO HEAR FROM YOU.

CONTACT US SUBMIT RFP