Last updated September 18, 2012.

This page is limited in scope to decisions and conventions that affect Drupal.org specifically.

Writing Features and Scenarios

BDD Features use the Gherkin syntax, and the Behat documentation for Writing Features gives a thorough explanation. Below you'll find documentation about styles and conventions specific to Drupal.org

Feature Files

Each individual feature has its own file which contains the Feature block and one or more scenarios. Feature files are stored in the doobie/features and are named [FeatureName].feature and split into one of 5 major areas:

  • Project
  • Git
  • Solr
  • Theme
  • DrupalOrg
  • Feature Block

    The feature block should be written in the following format:

    Feature: [A terse description of the feature]

      In order to [realize a named business value]
      As [an explicit system actor]
      I want to [gain some beneficial outcome which furthers the goal]

    Explicit system actors

    • any user (anonymous + authenticated)
    • any Drupal.org user (authenticated)
    • git user (has agreed to terms of service)
    • git vetted user (has agreed to terms of service AND is allowed to create full projects)
    • Git administrator
    • drupal.org issue queue squad
    • Packaging whitelist maintainer
    • security team
    • site maintainer
    • testing administrator
    • user administrator
    • project committer (has Write to VCS)
    • project editor (has Edit project)
    • project maintainer admin (has Administer maintainers)
    • project release admin (has Administer releases)
    • project issue maintainer (has Maintain issues)

    Scenarios

    The Behat documentation provides a detailed explanation of scenario writing. Many common scenario steps are already supported. This means wherever you use the language patterns below, you will not have to write any supporting code.

    You can see the current list once you've set up for the Drupal.org BDD project with:
    bin/behat -dl

    Given /^(?:that I|I) am (?:on|at) the homepage$/
    When /^I clone the repo$/
    Then /^I should have a local copy of "([^"]*)"$/
    Then /^I should see the project$/
    When /^I search for "([^"]*)"$/
    When /^I search sitewide for "([^"]*)"$/
    Given /^I am logged in as "([^"]*)" with the password "([^"]*)"$/
    Given /^I am logged in as "([^"]*)"$/
    Given /^I execute the commands$/
    When /^I create a "([^"]*)"$/
    Then /^I (?:|should )see the project title$/
    Given /^I am on the Version control tab$/
    When /^I initialize the repository$/
    Given /^I should not see the following <texts>$/
    Given /^I should see the following <texts>$/
    Given /^I should see the following <links>$/
    Given /^I should not see the following <links>$/
    When /^I select "([^"]*)" from field "([^"]*)"$/
    Given /^I enter "([^"]*)" for field "([^"]*)"$/
    When /^I click on page "([^"]*)"$/
    When /^I click the table heading "([^"]*)"$/
    Then /^I should see "([^"]*)" sorted in "([^"]*)" order$/
    When /^I click on the feed icon$/
    Then /^I should see the (?:issue|text )(?:|"([^"]*)") in the feed$/
    Given /^I should see at least "([^"]*)" feed item(?:|s)$/
    Given /^I fill in "([^"]*)" with random text$/
    Then /^I should see the random "([^"]*)" text$/
    When /^I see "([^"]*)"$/
    Given /^I should see at least "([^"]*)" record(?:|s)$/
    When /^I press "([^"]*)" to filter$/
    When /^I press search to filter$/
    Then /^I wait for the suggestion box to appear$/
    Given /^(?:|I )wait (?:|for )"([^"]*)" second(?:|s)$/
    When /^I click on a case study image$/
    Given /^I should see the link "(?P<link>[^"]*)" at the "(?P<position>[^"]*)" in the "(?P<region>[^"]*)"(?:| region)$/
    Then /^I should see "(?P<count>\d+)" links in the "(?P<region>[^"]*)"(?:| region)$/
    When /^I select the following <fields> with <values>$/
    When /^I select "([^"]*)" from Project Type on Create Project page$/
    Given /^I should see "([^"]*)" under "([^"]*)"$/
    Given /^I should not see "([^"]*)" under "([^"]*)"$/
    Given /^I select "([^"]*)" from the suggestion "([^"]*)"$/
    Given /^I download the "([^"]*)" file "([^"]*)"$/
    Then /^the md5 hash should match "(?P<md5hash>[^"]*)"$/
    Then /^I should see the following <subcategories> under "([^"]*)"$/
    Then /^I should not see the following <subcategories> under "([^"]*)"$/
    Then /^I expand the category "([^"]*)"$/
    Then /^I collapse the category "([^"]*)"$/
    Then /^(?:I|I should) see at least "(?P<count>\d+)" link(?:|s) under the "(?P<tab>[^"]*)" tab$/
    When /^I select <option> from "([^"]*)" results will contain <text>$/
    When /^I click on "([^"]*)" of a commit$/
    Given /^I should see at least "([^"]*)" file(?:|s) in the list$/
    Given /^I should see at least "([^"]*)" "([^"]*)" symbol(?:|s)$/
    Given /^I should see the commit message$/
    Given /^I press "(?P<button>[^"]*)" in the "(?P<region>[^"]*)" region$/
    When /^I follow a post$/
    When /^I follow "([^"]*)" for a post$/
    Given /^all the checkboxes are selected$/
    Then /^none the checkboxes are selected$/
    When /^I check "([^"]*)" checkboxes to "([^"]*)"$/
    Given /^I should see at least "([^"]*)" committer(?:|s)$/
    Given /^I should see at least "([^"]*)" commit(?:|s)$/
    Given /^I click the edit link for the sandbox project$/
    Given /^I should see that the project short name is readonly$/
    Given /^I should see project name in the first part of the heading$/
    Then /^the "([^"]*)" field should be "([^"]*)"$/
    Then /^I should see at least "([^"]*)" email (?:address|addresses)$/
    Then /^I should see at least "([^"]*)" confirmed email (?:address|addresses)$/
    Then /^I should not see "([^"]*)" in the dropdown "([^"]*)"$/
    When /^I click the Sandbox project link$/
    Given /^I click the Full project link$/
    Given /^I upload the following "([^"]*)" <files>$/
    Given /^I check the project is created$/
    Given /^I should see that the Sandbox checkbox is "([^"]*)"$/
    Given /^the field "([^"]*)" should be outlined in red$/
    Given /^I should see at least "([^"]*)" (?:reply|replies) for the post$/
    Given /^I should see at least "([^"]*)" new (?:reply|replies) for the post$/
    Given /^I should see updated for the post$/
    Given /^I should not see updated for the post$/
    Then /^I should see the following <tabs>$/
    Then /^the page status should be "([^"]*)"$/
    Then /^I should see that the tab "([^"]*)" is highlighted$/
    Given /^I should see the following <blocks> in the right sidebar$/
    Given /^the background color of the status should be "([^"]*)"$/
    Given /^I should see the copyright statement in the right sidebar$/
    Given /^"([^"]*)" should not contain an input element$/
    Given /^I should see the following <slides>$/
    Given /^I should see the following <blocks> in the "([^"]*)" column$/
    Then /^I should see the below <blocks> in column "([^"]*)"$/
    Then /^I should see the following <blocklinks> in small boxes$/
    Given /^I should see at least "([^"]*)" record(?:|s) in "([^"]*)" table$/
    Then /^I should see the following <links> in column "([^"]*)" in "([^"]*)" table$/
    Given /^I click "([^"]*)" from "([^"]*)" table$/
    Given /^I should see "([^"]*)" page$/
    Given /^I fill in "([^"]*)" with Project Name$/
    Given /^I select Project Name from "([^"]*)"$/
    Then /^I should see at least "([^"]*)" blocks$/
    Then /^I should see at least "([^"]*)" blocks in column "([^"]*)"$/
    Then /^I should see at least "([^"]*)" items in block "([^"]*)"$/
    Then /^I should see the item "([^"]*)" in the block "([^"]*)"$/
    Then /^I drag the block "([^"]*)" onto "([^"]*)"$/
    Then /^I drag the block "([^"]*)" onto column "([^"]*)"$/
    Then /^I should not see the below <blocks> in column "([^"]*)"$/
    Then /^I should see the block "([^"]*)" in column "([^"]*)" just "([^"]*)" the block "([^"]*)"$/
    Then /^I change the setting "([^"]*)" to "([^"]*)" for the block "([^"]*)" and save$/
    Then /^I close the block "([^"]*)" from dashboard$/
    Then /^I close the block$/
    Then /^I should not see the block$/
    When /^I click the link "([^"]*)" to add$/
    Then /^I should see the block "([^"]*)" in column "([^"]*)"$/
    Given /^I should see the following <icons> on the block "([^"]*)"$/
    Then /^I should see the submitted user "([^"]*)"$/
    Given /^I should see the advertisment in the right sidebar$/
    Given /^I create a book page$/
    When /^I follow a random book page$/
    When /^I am on the Maintainers tab$/
    When /^I follow "([^"]*)" for the maintainer "([^"]*)"$/
    When /^I assign the following <permissions> to the maintainer "([^"]*)"$/
    When /^I assign "([^"]*)" to the maintainer "([^"]*)"$/
    When /^I unassign the following <permissions> from the maintainer "([^"]*)"$/
    When /^I unassign "([^"]*)" from the maintainer "([^"]*)"$/
    Given /^I am on the project page$/
    When /^I create a full project$/
    Then /^I create a new issue$/
    Given /^I follow an issue of the project$/
    Then /^I should be able to push (?:a|one more) commit to the repository$/
    Then /^I should see "([^"]*)" in the dropdown "([^"]*)"$/
    When /^I follow "([^"]*)" for version "([^"]*)"$/
    When /^I download the "([^"]*)" file for version "([^"]*)"$/
    Then /^the downloaded file name should be "([^"]*)"$/
    Given /^(?:that I|I) created a sandbox project$/
    When /^I promote the project$/
    Then /^I should have a local copy of (?:the|([^"]*)") project$/
    Then /^I should not be able to clone the sandbox repo$/
    Then /^I should see the <users> with the following <permissions>$/
    Given /^I should see the <users> without the following <permissions>$/
    Then /^I (?:|should )see the issue title$/
    Given /^I add (?:a|one more) comment to the issue$/
    Given /^(?:that I|I) am at "([^"]*)"$/
    When /^I visit "([^"]*)"$/
    When /^I click "([^"]*)"$/
    Given /^for "([^"]*)" I enter "([^"]*)"$/
    Given /^I enter "([^"]*)" for "([^"]*)"$/
    When /^I press the "([^"]*)" button$/
    Then /^I should see the link "([^"]*)"$/
    Then /^I should not see the link "([^"]*)"$/
    Then /^I (?:|should )see the heading "([^"]*)"$/
    Then /^(?:I|I should) see the text "([^"]*)"$/
    Then /^I should not see the text "([^"]*)"$/
    Then /^I should get a "([^"]*)" HTTP response$/
    Then /^I should not get a "([^"]*)" HTTP response$/
    Given /^I check the box "([^"]*)"$/
    Given /^I uncheck the box "([^"]*)"$/
    When /^I select the radio button "([^"]*)" with the id "([^"]*)"$/
    Given /^I am an anonymous user$/
    Given /^I am logged in as a user with the "([^"]*)" role$/
    Given /^(?:|I )am on homepage$/
    When /^(?:|I )go to homepage$/
    Given /^(?:|I )am on "(?P<page>[^"]+)"$/
    When /^(?:|I )go to "(?P<page>[^"]+)"$/
    When /^(?:|I )reload the page$/
    When /^(?:|I )move backward one page$/
    When /^(?:|I )move forward one page$/
    When /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/
    When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/
    When /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:[^"]|")*)"$/
    When /^(?:|I )fill in "(?P<value>(?:[^"]|")*)" for "(?P<field>(?:[^"]|")*)"$/
    When /^(?:|I )fill in the following:$/
    When /^(?:|I )select "(?P<option>(?:[^"]|")*)" from "(?P<select>(?:[^"]|")*)"$/
    When /^(?:|I )additionally select "(?P<option>(?:[^"]|")*)" from "(?P<select>(?:[^"]|")*)"$/
    When /^(?:|I )check "(?P<option>(?:[^"]|")*)"$/
    When /^(?:|I )uncheck "(?P<option>(?:[^"]|")*)"$/
    When /^(?:|I )attach the file "(?P[^"]*)" to "(?P<field>(?:[^"]|")*)"$/
    Then /^(?:|I )should be on "(?P<page>[^"]+)"$/
    Then /^the (?i)url(?-i) should match (?P<pattern>"([^"]|")*")$/
    Then /^the response status code should be (?P<code>\d+)$/
    Then /^the response status code should not be (?P<code>\d+)$/
    Then /^(?:|I )should see "(?P<text>(?:[^"]|")*)"$/
    Then /^(?:|I )should not see "(?P<text>(?:[^"]|")*)"$/
    Then /^(?:|I )should see text matching (?P<pattern>"(?:[^"]|")*")$/
    Then /^(?:|I )should not see text matching (?P<pattern>"(?:[^"]|")*")$/
    Then /^the response should contain "(?P<text>(?:[^"]|")*)"$/
    Then /^the response should not contain "(?P<text>(?:[^"]|")*)"$/
    Then /^(?:|I )should see "(?P<text>(?:[^"]|")*)" in the "(?P<element>[^"]*)" element$/
    Then /^(?:|I )should not see "(?P<text>(?:[^"]|")*)" in the "(?P<element>[^"]*)" element$/
    Then /^the "(?P<element>[^"]*)" element should contain "(?P<value>(?:[^"]|")*)"$/
    Then /^(?:|I )should see an? "(?P<element>[^"]*)" element$/
    Then /^(?:|I )should not see an? "(?P<element>[^"]*)" element$/
    Then /^the "(?P<field>(?:[^"]|")*)" field should contain "(?P<value>(?:[^"]|")*)"$/
    Then /^the "(?P<field>(?:[^"]|")*)" field should not contain "(?P<value>(?:[^"]|")*)"$/
    Then /^the "(?P<checkbox>(?:[^"]|")*)" checkbox should be checked$/
    Then /^the "(?P<checkbox>(?:[^"]|")*)" checkbox should not be checked$/
    Then /^(?:|I )should see (?P<num>\d+) "(?P<element>[^"]*)" elements?$/
    Then /^print last response$/
    Then /^show last response$/