Recently we’ve been expanding our suite of “Smoke Tests”.  Smoke Tests is our term for the GUI tests that we’ve written for the purpose of testing common, happy-path actions in the Rally application.  These tests are written in Java using the Selenium API.

During the process of writing these tests, we’ve ran into a few situations where we needed to do seemingly simple actions through the web browser, but we weren’t able to immediately come up with solutions simply by looking at the Selenium API.  I’d like to highlight a few of these below:

1.  Interacting with WebElements in iframes
In one of our Smoke Tests for an editor in the Rally Application, we wanted to enter some text into the the “Description” field in the editor.

Editor

The Description field uses our rich-text editor, and the text box where the Description text can be entered is enclosed inside of an iframe.  The setValue method below shows the code we were trying to use to enter text into this field:

public class RichTextField
{
private String iframeId;
private WebDriver webDriver;

public RichTextField(String iframeId, WebDriver webDriver)
{
this.iframeId = iframeId;
this.webDriver = webDriver;
}

public void setValue(String value)
{
webDriver.findElement(By.cssSelector("#" + iframeId + " body")).sendKeys(value);
}
}

When we tried to access the body element of the iframe with the call to By.cssSelector(…), Selenium was unable to find the body element.  This is because it was inside of the iframe.

Fortunately, after some searching we were able to find the switchTo() method on WebDriver.  This did the trick:

public class RichTextField
{
private String iframeId;
private WebDriver webDriver;

public RichTextField(String iframeId, WebDriver webDriver)
{
this.iframeId = iframeId;
this.webDriver = webDriver;
}

public void setValue(String value)
{
webDriver.switchTo().frame(iframeId).findElement(By.tagName("body")).sendKeys(value);
webDriver.switchTo().defaultContent();
}
}

Notice the webDriver.switchTo().defaultContent() line.  This is necessary so that the WebDriver instance’s context is switched back to the main page instead of being inside of the iframe, which is the result of the first statement in setValue.

2.  Selecting a Value From an Ext.form.ComboBox
In another one of our Smoke Tests, we wanted to click the “Create New User” option from our new auto-suggest text box on the Project-Users grid.  This auto-suggest box is built using ExtJS’ Ext.form.ComboBox object.

AddProjectUserToolbar

Text needs to be entered into the auto-suggest textbox so that the drop-down box containing the “Create New User” option will render.  We thought this could be accomplished using the following code in the sendKeys method (comboTextBox is the WebElement corresponding to the auto-suggest textbox):

public class Combo
{
private WebElement comboTextBox;

public Combo(WebElement comboTextBox)
{
this.comboTextBox = comboTextBox;
}

public void sendKeys(CharSequence text)
{
comboTextBox.sendKeys(text);
}
}

However, we noticed that unless the Firefox window that was running the test was the focused window, the drop-down box (with the link we wanted to click) would never appear regardless of what was typed into the auto-suggest text box.  Wierd, huh?

After much head-shaking, we looked at the expand method in Ext.form.ComboBox:

expand : function(){
if(this.isExpanded() || !this.hasFocus){
return;
}
this.list.alignTo(this.wrap, this.listAlign);
this.list.show();
this.innerList.setOverflow('auto'); // necessary for FF 2.0/Mac
Ext.getDoc().on('mousewheel', this.collapseIf, this);
Ext.getDoc().on('mousedown', this.collapseIf, this);
this.fireEvent('expand', this);
}

We put some alerts in the there, and noticed that hasFocus was false!  This meant that expand() did nothing, and that’s why our auto-suggest box was never expanding!  hasFocus is set to true in the onFocus() method of ComboBox, which is called when the focus event is fired (hence the name ;) ).  So we modified our sendKeys method to attempt to explicitly focus the ComboBox by clicking on it:

public void sendKeys(CharSequence text)
{
comboTextBox.click();
comboTextBox.sendKeys(text);
}

Still no luck!  hasFocus was still false.  After some searching, we stumbled on this article.  This led us to believe that the focus event was never being fired in our Firefox browser.  So we got creative:

public class Combo
{
private WebElement comboTextBox;
private WebDriver webDriver;

public Combo(WebElement comboTextBox, WebDriver webDriver)
{
this.comboTextBox = comboTextBox;
this.webDriver = webDriver;
}

public void sendKeys(CharSequence text)
{
((JavascriptExecutor) webDriver).executeScript("Ext.getCmp('project-user-auto-suggest').onFocus()");
comboTextBox.sendKeys(text);
}
}

This is really awesome because we were able to use the Ext.getCmp method from the ExtJS framework that we use in our application to get our auto-suggest ComboBox (”project-user-auto-suggest” is the id of the component), and then we could make up for the browser’s inability to fire the focus event by simply calling onFocus() ourselves.  This worked like a charm.  So awesome!