A pluggable field-handling system for the Behat Drupal Extension
Write more complete Behat test scenarios for both Drupal 7 and Drupal 8.
On of the main goal of BDD (Behaviour Driven Development) is to be able to describe a system's behavior using a single notation, in order to be directly accessible by product owners and developers and testable using automatic conversion tools.
In the PHP world, Behat is the tool of choice. Behat allows to write test scenarios using Gherkin step definitions and it generates the corresponding PHP code to actually run and test the defined scenarios.
Thanks to the excellent Behat Drupal Extension Drupal developers have been able to enjoy the benefits of Behavioral Driven Development for quite some time.
Essentially the project provides an integration between Drupal and Behat allowing the usage of Drupal-specific Gherkin step definitions. For example, writing a scenario that tests node authorship would look like:
Scenario: Create nodes with specific authorship<br> Given users:<br> | name | mail | status |<br> | Joe User | joe@example.com | 1 |<br> And "article" content:<br> | title | author | body |<br> | Article by Joe | Joe User | PLACEHOLDER BODY |<br> When I am logged in as a user with the "administrator" role<br> And I am on the homepage<br> And I follow "Article by Joe"<br> Then I should see the link "Joe User"
Dealing with complex content types
The Gherkin scenario above is pretty straightforward and it gets the job done for simple cases. In a real-life situation, though, it's very common to have content types with a high number of fields, often of different types and, possibly, referencing other entities.
The following scenario might be a much more common situation for a Drupal developer:
Scenario: Reference site pages from within a "Post" node<br> Given "page" content:<br> | title |<br> | Page one |<br> | Page two |<br> | Page three |<br> When I am viewing a "post" content:<br> | title | Post title |<br> | body | PLACEHOLDER BODY |<br> | field_post_reference | Page one, Page two |<br> Then I should see "Page one"<br> And I should see "Page two"
While it is always possible to implement project specific step-definition, as show on this Gist dealing with field collections and entity references, having to do that for every specific content type might be an unnecessary burden.
Introducing field-handling for the Behat Drupal Extension
Nuvole recently contributed a field-handling system that would allow the scenario above to be ran out of the box, without having to implement any custom step definition, working both in Drupal 7 and Drupal 8. The idea behind it is to allow a Drupal developer to work with fields when writing Behat test scenarios, regardless of the entity type or of any field-specific implementation.
The code is currently available on the master branches of both the Behat Drupal Extension and the Drupal Driver projects, if you want to try it out follow the instructions at "Stand-alone installation" and make sure to grab the right code by specifying the right package versions in your composer.json
file:
{<br> "require": {<br> "drupal/drupal-extension": "3.0.*@dev",<br> "drupal/drupal-driver": "1.1.*@dev"<br>}
The field-handling system provides an integration with several highly-used field types, like:
Date fields
Date field values can be included in a test scenario by using the following notation:
- Single date field value can be expressed as
2015-02-08 17:45:00
- Start and end date are separated by a dash
-
, for ex.2015-02-08 17:45:00 - 2015-02-08 19:45:00
. - Multiple date field values are separated by a comma
,
For example, the following Gherkin notation will create a node with 3 date fields:
When I am viewing a "post" content:<br> | title | Post title |<br> | field_date1 | 2015-02-08 17:45:00 |<br> | field_date2 | 2015-02-08 17:45:00, 2015-02-09 17:45:00 |<br> | field_date3 | 2015-02-08 17:45:00 - 2015-02-08 19:45:00 |
Entity reference fields
Entity reference field values can be expressed by simply specifying the referenced entity's label field (e.g. the node's title or the term's name). Such an approach wants to keep up with BDD's promise: i.e. describing the system behavior by abstracting, as much as possible, any internal implementation.
For example, to reference to a content item with title "Page one" we can simply write:
When I am viewing a "post" content:<br> | title | Post title |<br> | field_reference | Page one |
Or, in case of multiple fields, titles will be separated by a comma:
When I am viewing a "post" content:<br> | title | Post title |<br> | field_reference | Page one, Page two |
Link fields
A Link field in Drupal offers quite a wide range of options, such as an optional link title or internal/external URLs. We can use the following notation to work with links in our test scenarios:
When I am viewing a "post" content:<br> | title | Post title |<br> | field_link1 | http://nuvole.org |<br> | field_link2 | Link 1 - http://nuvole.org |<br> | field_link3 | Link 1 - http://nuvole.org, Link 2 - http://example.com |
As you can see we use always the same pattern: a dash -
to separate parts of the same field value and a comma ,
to separate multiple field values.
Text fields with "Select" widget
We can also refer to a select list value by simply referring to its label, so to have much more readable test scenarios. For example, given the following allowed values for a select field:
option1|Single room<br>option2|Twin room<br>option3|Double room
In our test scenario, we can simply write:
When I am viewing a "post" content:<br> | title | Post title |<br> | field_room | Single room, Double room |
Working with other entity types
Field-handling works with other entity types too, such as users and taxonomy terms. We can easily have a scenario that would create a bunch of users with their relative fields by writing:
Given users:<br> | name | mail | language | field_name | field_surname | field_country |<br> | antonio | antonio@example.com | it | Antonio | De Marco | Belgium |<br> | andrea | andrea@example.com | it | Andrea | Pescetti | Italy |<br> | fabian | fabian@example.com | de | Fabian | Bircher | Czech Republic |
Contributing to the project
At the moment field-handling is still a work in progress and, while it does support both Drupal 7 and Drupal 8, it covers only a limited set of field types, such as:
- Simple text fields
- Date fields
- Entity reference fields
- Link fields
- List text fields
- Taxonomy term reference fields
If you want to contribute to the project by providing additional field type handlers you will need to implement this very simple, core-agnostic, interface:
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #007700">namespace </span><span style="color: #0000BB">Drupal</span><span style="color: #007700">\</span><span style="color: #0000BB">Driver</span><span style="color: #007700">\</span><span style="color: #0000BB">Fields</span><span style="color: #007700">;<br><br></span><span style="color: #FF8000">/**<br> * Interface FieldHandlerInterface<br> * @package Drupal\Driver\Fields<br> */<br></span><span style="color: #007700">interface </span><span style="color: #0000BB">FieldHandlerInterface </span><span style="color: #007700">{<br><br> </span><span style="color: #FF8000">/**<br> * Expand raw field values in a format compatible with entity_save().<br> *<br> * @param $values<br> * Raw field values array.<br> * @return array<br> * Expanded field values array.<br> */<br> </span><span style="color: #007700">public function </span><span style="color: #0000BB">expand</span><span style="color: #007700">(</span><span style="color: #0000BB">$values</span><span style="color: #007700">);<br>}<br></span><span style="color: #0000BB">?></span></span>
If you need some inspiration check the current handlers implementation by inspecting classes namespaced as \Drupal\Driver\Fields\Drupal7
and \Drupal\Driver\Fields\Drupal8
.
Tags: Drupal PlanetTest Driven DevelopmentBehat