Drupal Selenium tests API

This article is followup of the previous two Selenium testing in Drupal and Run Selenium tests in Drupal on Debian headless. I strongly recommend to read these two articles (at least watch demo videos) before reading more technical explanation below.

Now is the time to explain how to write tests using Selenium in simpletest.

setUp

In order to write selenium test we need to extend DrupalSeleniumWebTestCase class. This class on setUp starts new Firefox session. We can manipulate to connection with Firefox using driver property of the class.

So after we have established connection to Firefox we can do all our magic.

DrupalSeleniumWebTestCase

Some of methods of DrupalSeleniumWebTestCase
drupalGet -- open specified url in browser.
drupalPost -- submits the form on specified page (analog of DrupalWebTestCase drupalPost)
verboseScreenshot -- take a screenshot of whole page
drupalLogin -- log in user. Browser will go to /user page and submit all username and password specified in $user object. Works similar way to DrupalWebTestCase implementation.
drupalLogout -- log out current user
Implemented asserts:
assertTitle -- assert titles of the page
assertLink -- assert existance of the link by its label
assertTextHelper -- helper for assertText and assertNoText so you can use these two asserts

SeleniumWebdriver

Other methods are accessible via methods of SeleniumWebdriver (instance of this class is in $this->driver property).
I think most important methods for us are:
waitForElements($locator) -- this method checks every second whether element specified by $locator can be found on the page. This is needed for example when we test some javascript that adds new element to the page and we need to wait till script finished its work. More about locators below.
getElement($locator) -- find element on the page and return object of SeleniumWebElement class that represents this element. Afterwards we can do actions on this element. More details below.
getAllElements($locator) -- find all elements on the page that can be found with specified locator

Locators

These are strings that can be used to find elements on the page. Selenium has following types of locators:
css -- find element by its CSS selector
id -- find element by its identifier. Example $this->getElement('id=edit-submit')
name -- find form element by its name attribute. Example $this->getElement('name=pass')
class -- find element by its class. Example $this->getElement('class=form-item')
link -- find link by its label. Example $this->getElement('link=Log out')
partial link text -- find link by its partial label. Example $this->getElement('partial link text=out')
xpath -- find element by its xpath. Example $this->getElement('xpath=//*[@id="header"]')
tag name -- find element by its tag name. Example $this->getElement('tag name=input')

Most interesting for us of course is css selector. It allows us to use selectors that we use in jquery. Selenium uses sizzle library for that. So we can use expressions like:

css=div.region-header div.social-links a

This is really great feature. Selenium announced that we can use full CSS 3 selectors but I haven't managed to use selectors with values like:

css=a[href*=logout]

Well, maybe I am missing something or maybe current Selenium only implements CSS 2 selectors. More information about selectors http://saucelabs.com/blog/index.php/2011/01/why-jquery-in-selenium-css-l...


SeleniumWebElement

Coming back to SeleniumWebElement class object that we get after call $this->getElement. We can do tons with it. Like:
click -- click on element
clear -- clear the value (workable example textfield in the form)
getAttributeValue -- get the value of the specified attribute
getText -- get text of the element (for example lable of the link)
getValue -- get value of the element
sendKeys -- send keys to element (like fill textfield)
dragAndDrop -- drag and drop element

Example of the code:

$this->driver->getElement('css=#edit-name')->sendKeys($user->name);
$this->driver->getElement('css=#edit-pass')->sendKeys($user->pass_raw);
$this->driver->getElement('css=#edit-submit')->submit();

Of course more methods and how they work you can look in the code.

I hope you have enjoyed possibilities of Selenium framework and find writing tests quite simple. I think we will need to implement more methods "like" in DrupalWebTestCase to DrupalSeleniumWebTestCase in order to make developers already familiar with methods names.

I am sure names of the methods and code will change after more people review. I will try to keep this document updated on changes.

Happy testing!

Comments

I posted on g.d.o and twitter about your fantastic work. I tried it out today and was able to make it run just fine. Needs more API support, of course. I encourage you to put this information on the project page, and to keep building examples. How about a set of examples for the AJAX example in Examples project?