Drupal BDD -- Looking for the presence of a form on a page with Behat

I am working on a project where I am writing some custom Behat steps, as the steps that come pre-defined with Behat, Mink and the Drupal Extension are simply not adequate for user friendly scenario steps. The step I just wrote and tested, which is fairly simple but makes writing scenarios for this particular project much easier, allows you to look for the presence of a form within a region of a page using its HTML ID or HTML name, and is outlined here.

The project I am working on is a Drupal Application where authenticated users will see different forms presented on a particular page depending on the "roles" that the authenticated user has been granted at the time the page is visited.

Background

In this particular project, the form on the page changes based on the user role. Each form has a distinct ID associated with it, so I wanted to be able to test for the presence of a "form" element in the "content" region with a particular css ID based on the role of the authenticated user.

The Drupal Extension provides us with the capability of defining a "region" on a page based on a CSS selector, and putting that definition in our behat.yml file. Awesome!

(FYI -- By the way, by installing the Drupal Extension for Behat, you can leverage this on non-Drupal sites as well. The Drupal Community Rocks!)

However, when I started looking at the predefined steps, there was no ability to look for a "form" tag within a region. So, I started looking at the underlying classes that make up the DrupalContext.

DrupalContext extends the MinkContext from the Mink Extension, which brings with it, among other things, access to Mink's Named Selector class. This is where the definitions for accessing certain HTML elements has been defined. On the list of "named" elements are: fieldset, field, link, button, content, select, checkbox, radio, file, optgroup, option, and table. Mink's TraversableElement class provides a number of convenience wrapper functions for finding and accessing any of the "named" elements, which the DrupalContext uses for defining the steps for looking for these elements within a "region". Alas, no "form" element exists.

However, we do get the ability also search generically for any element that is present using "xpath". So, I leveraged this capability to write a custom step that searches for a form element, by its ID or name attribute, within a defined "region" on a page. The DrupalContext provides a convenience method that returns the HTML present on a page with a defined "region", called "getRegion(). You simply pass in your "region" definition, and you get back a traversable object containing all of the HTML within that region, which you can then search through using the "find" method from Mink's Element class.

Step Definition Code

The step definition is as follows:


  /**
   * @Then /^I should see the "([^"]*)" form in the "([^"]*)" region$/
   */
  public function iShouldSeeTheFormInTheRegion($form_id, $region) {
    $regionObj = $this->getRegion($region);
    $selectElement = $regionObj->find('xpath','//form[@id = "'. $form_id .'" or @name = "' . $form_id . '"]');
    
    if (empty($selectElement)) {
      throw new \Exception(sprintf("No form '%s' is present in the '%s' region", $form_id, $region));
    }
  }

This provides me with a step that can be used as follows, in my Scenario description:

  Then I should see the "user-login" form in the "content" region

Works Beautifully! Hope you find this useful.