This is the last in a series of articles that elaborated on a the incremental steps we took to address an issue with our JavaScript causing some last minute scrambling in our development and release processes.  The last article finished with the de-linting our JavaScript, enabling us to have JSLint start failing our build.

The issue with our profile based solution of running JSLint, is that it wouldn’t fail the build as part of our test phase.  To address this issue, we needed to write a plugin that we could tie in with the rest of our test phase plugins during the build.  The easiest way to accomplish this is to write a small Maven plugin using Mojo.  To help me with this task, I enlisted the help of Burke Webster whose Maven Mojo is much better than mine.  Burke also wrote our Maven jstestdriver plugin .  Building on Dominic Mitchell’s jslint4java, we wanted to keep the plugin interface as simple as possible.  Here’s an example of properties for your pom.xml:

<properties>
    <jslint.jar>${basedir}/src/test/resources/jslint4java.jar</jslint.jar>
    <jslint.maven.plugin.version>1.0-SNAPSHOT</jslint.maven.plugin.version>
    <jslint.options>browser,cap,debug,devel,evil,fragment,laxbreak,on</jslint.options>
    <jslint.predef>RALLY</jslint.predef>
    <jslint.source.dir>${basedir}/src/main/webapp/js</jslint.source.dir>
</properties>

These end up getting used in the build section for activating JSLint:

<build>
    <plugins>
        <!-- jslint -->
        <plugin>
            <artifactId>jslint</artifactId>
            <version>${jslint.maven.plugin.version}</version>
            <groupId>com.googlecode.jslintmavenplugin</groupId>
            <executions>
                <execution>
                    <id>run-tests</id
                    <phase>test</phase>
                    <goals>
                        <goal>test</goal>
                    </goals>
                    <configuration>
                        <jar>${jslint.jar}</jar>
                        <options>${jslint.options}</options>
                        <predef>${jslint.predef}</predef>
                        <src>${jslint.source.dir}</src>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

The jar tag allows you to specify where your jslint4java jar is. The src tag allows you to specify the root of your JavaScript (where the plugin will begin to recursively look for JavaScript files on which to run JSLint).  The predef tag allows you to inform JSLint of certain “global” variables that should be predefined so that JSLint will not complain.  This is handy for setting up things like namespaces.  The options tag is where you pass JSLint options to JSLint.  Any of the options available for JSLint are valid.  There is a skipTests tag that you can set to true to skip the next phase of tests.  There is also a verbose tag to have the plugin tell you what it is doing in more detail.

With the JSLint Maven plugin, JSLint can now fail the build.  We also set up some profiles to run JSLint on portions of our JavaScript in different modules and in conjunction with other testing frameworks like jstestdriver.  Deveopers benefit by being able to more easily run JSLint.

For the 8 weeks this has been in place, JSLint has kept numerous problems from reaching our committed code base, and when a error slipped past JSLint, Hudson told us right away of a problem.  We haven’t had any last minute fire drills due to the same JavaScript  issues and we have happier development and operations teams.

This is the second in a series of articles that describe the incremental steps we took to address issues with our JavaScript, causing last minute scrambling in our development and release processes.  When last we left, we had decided to use Dominic Mitchell’s jslint4java wrapper around Douglas Crawford’s JSLint.  I wrote a Maven profile that allowed developers to run JSLint on our JavaScript so we could find the problems early in our development process. We found about 500 complaints and needed work through them before we could let JSLint fail our build.

Since we have multiple scrums working in this code base, we have a many different coding styles. For instance, JSLint has an option called forin which tells JSLint to look for for loop iterations that look like this:

for(var i in someObject) {
    //do something interesting();
}

Some will define someObject as:

someObject = {};

and use it as an associative array.  Others will use a prototyped collection object of some sort.  JSLint wants you to be intentional.  If you use a prototyped object, then you really should only iterate over the properties with something like:

for (var i in someObject) {
    if(someObject.hasOwnProperty(i) {
        // now do something interesting;
    }
}

Another big area dealt with just relatively benign things like mixing tabs and spaces on lines.  What we found was the some folks use Eclipse and some use IntelliJ.   We were able to configure Eclipse to match what IntelliJ does with white space for JavaScript, and this cleared up 100 or so complaints.

Another big set of issues involved if statements that were simply checking for the existence of something versus evaluating whether the value was null or undefined. They were written like:

if(something != null) {
    // do something
}

JSLint wants you to write this as:

if(something !== null) {
    // do something
}

or

if(!something) {
    // do something
}

It turns out that sometimes we really do want to check for exactly null or exactly undefined (true and false as well). But at other times we are really just checking for the existence of something and you do not care if the value is null or undefined, for this specific purpose.

The last major grouping of complaints centered around in line if statements like:

if(something) blah();

JSLint does not like this for readability reasons.  It can be hard to figure out the intent of something like:

if (something)
    blah();
    blah2();

Were blah() and blah2() meant to be in the same if block, or were they really suppose to be different?  It is hard to tell.  In any case JSLint does not like it.

JSLint also found about five actual errors that would affect the operation of the javascript in some browsers.

Once everything was cleaned up, it was time to include JSLint as part of our build process. This is described in the next article.

Recently we had some issues with our JavaScript which were discovered late in the release cycle.  This caused some scrambling in our development and operations teams at the last minute.  In both cases, the culprit was an extra comma which causes IE* to have conniptions, while FireFox, Chrome, and Safari seem to be immune.  This is the first in a series of three articles that describe the incremental steps we took to address this issue. This first article describes what we did to assess the situation.  The second article describes the steps we took to de-lint our JavaScript.  The third article describes a Maven module we wrote to allow developers to run JSLint on their JavaScript changes, pre-commit, and also allowed our Hudson jobs to fail the build should JSLint find a problem.

To eliminate the fire drills and get feedback earlier (at the build phase), we implemented Douglas Crawford’s JSLint to check all of our JavaScript as part of the build process.  We have several sub modules within our code base; each submodule with its own JavaScript.  We wanted developers to run mvn tests before committing changes and to have our Hudson jobs fail if JSLint found any problems.

To try to get a handle on how big an issue we could be looking at, I created a maven profile to run Dominic Mitchell’s jslint4java as an ant task within our pom.xml:

<!-- run the jslint4java on javascript test, mvn -P jslint-all test -->
<profile>
    <id>jslint-all</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.4.2</version>
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.3</version>
                <dependencies>
                    <dependency>
                        <groupId>com.googlecode.jslint4java</groupId>
                        <artifactId>jslint4java-ant</artifactId>
                        <version>1.3.3</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>run-tests</id>
                        <phase>test</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <ant antfile="${basedir}/jslint-submodule1.xml">
                                    <property name="root" location="${basedir}" />
                                    <target name="jslint" />
                                </ant>
                                <ant antfile="${basedir}/jslint-submodule2.xml">
                                    <property name="root" location="${basedir}" />
                                    <target name="jslint" />
                                </ant>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

I also had to create an ant build file to be able to set the options for jslint.   Our initial one looks like this:

<project xmlns:jsl="antlib:com.googlecode.jslint4java">
    <target name="jslint">
        <jsl:jslint haltOnFailure="false" options="browser,cap,debug,devel,evil,fragment,laxbreak,on">
            <formatter type="plain" />
            <formatter type="xml" destfile="${root}/jslint-submodule1-out.xml" />
            <fileset dir="${root}/src/main/slm.war/js/rally" includes="**/*.js" />
        </jsl:jslint>
    </target>
</project>

After running this against our code base, we had about 500 JSLint complaints.  Once the expletives stopped and the tears dried up, I began categorizing what the issues were.  In the next article I will go over what some of the common issues were, and what fixes and decisions we made regarding the different coding styles in our JavaScript.

One problem that you may have encountered when attempting to write a test for an abstract class is that, well, you can’t instantiate it.  So how do you test it?

I was wondering the same thing a few weeks ago.  I had the following abstract class (simplified for readability and understanding):

public abstract class MyAbstractClass {

 protected String getDefaultOrder() {
 return getDefaultFetch().split(",")[0];
 }

 protected abstract String getDefaultFetch();
}

I wanted to write a simple test that would verify that getDefaultOrder() would perform as expected and return the first word in the comma-delimited string returned by getDefaultFetch().

Luckily, I stumbled upon Mockito’s thenCallRealMethod() method. This made the test easy to write:

public void defaultOrderShouldBeFirstWordInDefaultFetch() {
 MyAbstractClass abstractClass = mock(MyAbstractClass.class);

 when(abstractClass.getDefaultFetch()).thenReturn(
 "Rank,FormattedID,Name,PlanEstimate,Priority,Owner,ClosedDate,CreationDate"
 );

 when(abstractClass.getDefaultOrder()).thenCallRealMethod();

 assertEquals(abstractClass.getDefaultOrder(), "Rank");
 }

As you can see, we’re telling Mockito that when the getDefaultOrder() method gets called on the mock object “abstractClass”, Mockito should execute the real getDefaultOrder() defined in our MyAbstractClass class. This is contrary to Mockito’s default behavior of simply returning the default value for the return type of the method called on the mock object (in this case, for getDefaultOrder()’s return type of String, Mockito would return null).

So there you go: an easy way to test methods in abstract classes!

When testing interactions with mocks, some common code patterns can be difficult to test.

We recently encountered a case in a controller where we were talking to a wrapper for a third party service. Our wrapper would new-up a data transfer object based on the parameters provided by the controller and pass that query object to the third party.

Controller code:

    public ModelAndView doSomethingUseful(
            @RequestParam("name") String name,
            @RequestParam("order") String order)
    {
        Iterable<MyModel> queryResult
                = serviceWrapper.queryByName(name, order);

        return new ModelAndView("myView", "myModels", queryResult);
    }

Service wrapper code:

    public Iterable<MyModel> queryByName(String name, String order) {
        ThirdPartyDTO dto = new ThirdPartyDTO();
        dto.setParameter("name", name);
        dto.setOrder(order);
        dto.setFilter("type", MyModel.class.getName());
        return service.query(dto);
    }

While the code in both classes is fairly concise and easy to read, it is difficult to verify that the correct query logic was applied to the DTO. Because the DTO is constructed in the method call on the wrapper and never returned, it’s hard to write a test for that method. We could construct the DTO in the controller and make the service easy to test, but that would have just moved the problem. We could have introduced a factory to return new instances of the DTO then mocked that to return mocks and verify that the correct methods were called, but mocks returning mocks is a code smell.

What we settled on was introducing an intermediate class:

public class DTOBuilder {
    private Class aClass;
    private String order;
    private String name;

    public DTOBuilder(Class aClass) {
        this.aClass = aClass;
    }

    public DTOBuilder withName(String name) {
        this.name = name;
        return this;
    }

    public DTOBuilder orderBy(String order) {
        this.order = order;
        return this;
    }

    public ThirdPartyDTO buildDTO() {
        ThirdPartyDTO dto = new ThirdPartyDTO();
        dto.setParameter("name", this.name);
        dto.setOrder(this.order);
        dto.setFilter("type", this.aClass.getName());
        return dto;
    }
}

Now we can write tests verifying that when buildDTO is called, the correct values are set on the resulting DTO. It’s a simple test to write, and it doesn’t involve any mocks. Additionally, our service wrapper code is simplified…

public class ServiceWrapper {
    private ThirdPartyService service;

    public ServiceWrapper(ThirdPartyService service) {
        this.service = service;
    }

    public Iterable<MyModel> query(DTOBuilder builder) {
        return service.query(builder.buildDTO());
    }
}

.. and we can now write a test for our service wrapper pretty easily:

    public void queryShouldPassDTOFromBuilderToThirdPartyService() {
        DTOBuilder builder = mock(DTOBuilder.class);
        ThirdPartyService service = mock(ThirdPartyService.class);

        ThirdPartyDTO dto = new ThirdPartyDTO();
        Iterable<MyModel> expected = new ArrayList<MyModel>();

        when(builder.buildDTO()).thenReturn(dto);
        when(service.query(dto)).thenReturn(expected);

        ServiceWrapper wrapper = new ServiceWrapper(service);
        Iterable<MyModel> actual = wrapper.query(builder);

        assertEquals(actual, expected);
    }

To this point however, we’ve actually made our controller harder to test. While the code from the controller is clean and reads very well, it’s no longer easy to test:

    public ModelAndView doSomethingUseful(
            @RequestParam("name") String name,
            @RequestParam("order") String order)
    {
        DTOBuilder DTOBuilder = new DTOBuilder(MyModel.class)
                .withName(name)
                .orderBy(order);

        Iterable<MyModel> queryResult = serviceWrapper.query(DTOBuilder);

        return new ModelAndView("myView", "myModels", queryResult);
    }

A nice feature of IntelliJ and an understanding of mockito can help us out here. The when method in mockito relies on object equality to determine whether an expectation has been met. By overriding equality in our builder class, we can write our controller test like this:

    public void doSomethingUsefulShouldBuildExpressionAndDelegateToService(){
        ServiceWrapper serviceWrapper = mock(ServiceWrapper.class);
        Iterable<MyModel> models = new ArrayList<MyModel>();

        DTOBuilder builder = new DTOBuilder(MyModel.class)
                .withName("foo")
                .orderBy("bar");

        when(serviceWrapper.query(builder)).thenReturn(models);

        HypotheticalController hypotheticalController = new HypotheticalController(serviceWrapper);
        ModelAndView result = hypotheticalController.doSomethingUseful("foo", "bar");

        assertEquals(result.getModel().get("myModels"), models);
    }

Notice that this test verifies that the correct logic was applied to the DTO without over-relying on mocking and without using verify. It reads well and clearly communicates the intent of the production code.

Where does IntelliJ come into the equation? Writing the equality logic for the builder would be tedious and error prone to do by hand. Luckily, IntelliJ knows how to do it for us. Pressing Command+N brings up the code generation window (that’s on the mac – check the IntelliJ documentation for the shortcut on your platform). Choosing “equals() and hashCode()” from the resulting menu gives us this:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    DTOBuilder that = (DTOBuilder) o;

    if (aClass != null ? !aClass.equals(that.aClass) : that.aClass != null) return false;
    if (name != null ? !name.equals(that.name) : that.name != null) return false;
    if (order != null ? !order.equals(that.order) : that.order != null) return false;

    return true;
}

@Override
public int hashCode() {
    int result = aClass != null ? aClass.hashCode() : 0;
    result = 31 * result + (order != null ? order.hashCode() : 0);
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
}

At Rally, we’ve stayed committed for the last 7 years to never telling the business that the product has to halt active development to pay down technical debt. For us, the “big rewrite in the sky” has always been off the table. Instead, we prefer to incrementally refactor and improve the existing elements of the codebase, gradually getting it to where we want it to be without ever halting feature development completely.

This has never been an easy task. The truth is, the codebase is quite old by engineering standards, many parts of it written before standards emerged in the industry. Our entire persistence layer, for example, was created by hand well before libraries such as Hibernate existed (or at least, before they became standard practice). This means that there are many, many areas of the code that we’d like to attack and improve.

One thing we’ve started doing is holding lunchtime “refactotums,” where we take a look at some code and try to improve it. Of course, with such a large codebase, and so many areas of the code that have not been touched since they were first written, we’ve often wondered how to most effectively spend our refactotum time. This led us to wonder “what are the areas of the code where a refactoring would have the greatest impact?”

We started keeping track of our codebase using Sonar which was extremely helpful in keeping track of metrics at a class level, but it didn’t give us quite enough information. For example, if Class A has a complexity score of 500 and Class B has a complexity score of 200 (higher is worse), you’d think that spending some time cleaning up Class A would be the most effective thing to do. But what if Class B is used by 50 times as many other classes as Class A? Or what if Class B, complicated as it is, has never been modified in the history of the project? It would be nice to clean this class up, but it might be a better use of time to focus on Class A

So our idea was to combine two metrics: the class complexity (based on McCabe Cyclomatic Complexity) and the number of times a file has been modified in the codebase. The idea here was, every time a file has to be modified, it has to be read. A complex file is harder to read, making the engineer more likely to misunderstand or make a mistake while editing the file.

Luckily, git makes it quite easy to count the number of modifications to files in the codebase:

(more…)

We have recently started to write our browser based tests with Selenium 2.0. and the WebDriver api. We like the direct control over the browser versus the JavaScript execution of Selenium 1.0.

I also stumbled across Sauce Labs and its Sauce OnDemand product. I really would like to not maintain a huge grid of different browsers and operating systems, having them available “in the cloud” seems like a much better option. It also aligns better with the companies efforts to be more green. Unfortunately, Sauce OnDemand is a Selenium 1.0 version of Selenium Remote Control. Bummer. I took some time and at got a very basic example working using WebDriver and Sauce OnDemand.

Here is a simple TestNG test that verifies the title of google.

package com.rallydev.acceptance;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.CommandExecutor;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.net.URL;

import static org.testng.Assert.assertEquals;

@Test
public class SauceLabsTest {

    private WebDriver driver;

    @BeforeMethod
    protected void setUp() throws Exception {

        String browserString = new SauceLabsBrowser("sauceusername", "sauce-api-key-goes-here", "Windows 2003", "firefox", "3.", "WebDriver example").toJson();

        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setBrowserName(browserString);
        CommandExecutor executor = new RallySeleneseCommandExecutor(new URL("http://saucelabs.com:4444/"), new URL("http://www.google.com/"), capabilities);
        driver = new RemoteWebDriver(executor, capabilities);

    }

    @AfterMethod
    protected void tearDown() throws Exception {
        driver.quit();

    }

    public void sauceLabsWorks() throws Exception {
        driver.get("http://www.google.com/");
        assertEquals("Google", driver.getTitle());
    }
}

I had to extend the SeleneseCommandExecutor so the JSON browser name that Sauce wants doesn’t blow up. Here is the code for the what I called the RallySeleneseCommandExecutor:

package com.rallydev.acceptance;

import com.thoughtworks.selenium.HttpCommandProcessor;
import org.openqa.selenium.SeleneseCommandExecutor;
import org.openqa.selenium.remote.Capabilities;

import java.net.URL;

public class RallySeleneseCommandExecutor extends SeleneseCommandExecutor {
    public RallySeleneseCommandExecutor(URL seleniumServer, URL remoteAddress, Capabilities capabilities) {
        super(
                new HttpCommandProcessor(
                        seleniumServer.getHost(),
                        seleniumServer.getPort(),
                        capabilities.getBrowserName(),
                        remoteAddress.toString()
                )
        );
    }
}

The only other thing I did to make life easier was to create the SauceLabsBrowser class. All it does it put all the arguments into map and then convert the map to JSON. I can only handle string concatenation for so long :)

package com.rallydev.acceptance;

import net.sf.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

public class SauceLabsBrowser {

    private Map<String, String> sauceParams;

    public SauceLabsBrowser(String username, String accessKey, String os, String browser, String browserVersion, String jobName) {
        this.sauceParams = new HashMap<String, String>();

        this.sauceParams.put("username", username);
        this.sauceParams.put("access-key", accessKey);
        this.sauceParams.put("os", os);
        this.sauceParams.put("browser", browser);
        this.sauceParams.put("browser-version", browserVersion);
        this.sauceParams.put("job-name", jobName);
    }

    public String toJson() {
        JSONObject jsonObject = new net.sf.json.JSONObject();
        jsonObject.putAll(sauceParams);
        return jsonObject.toString();
    }
}

There is still a decent amount of work to do. I found there a bunch of WebDriver commands that aren’t yet implemented in the SeleneseCommandExecutor. I hope to fix that and get a patch send to the Selenium people soon. Hope this at least gets people started.

Ben Whaley of AppliedTrust and I recently spent a few months putting together a security model for Rally. We analyzed each module of our Java-based stack, detailing and capturing security considerations along the way. We relied on OWASP as a standardized framework for guiding our process. The goal of the project was to conveniently describe the Rally approach to security at the application layer. Additionally, this model has proven essential for newer members of our development team.
Many companies, particularly SaaS companies, can benefit by having a published security model. Since we had never seen anything quite like this, and because we believe in the open exchange of information, we decided to share the model with the public. Ben and I presented a talk entitled “Effectively marketing security as a win for both the business and the customer” at Front Range OWASP Conference 2010 where we presented the model detailing Rally’s approach to securing our SaaS product. Feel free to take a look at our slides.
We can now arm our sales team with a straightforward (even pretty) picture that represents exactly how we handle security throughout the application. This should assist us with answering questions in those difficult RFP documents from our more security-conscious customers. Also, I truly believe that having our security approach out there for the whole world to see shows a certain level of confidence. It’s clear that we’re not just doing a “security by obscurity” approach.
The development team at Rally has been growing during the last year and it can be difficult to train developers, especially from a security standpoint. The security model serves dual purpose from a training perspective. We now have a current architecture diagram that visually depicts security at each layer of the stack.
Our hope is that other companies can use this model as an example. There was no existing reference point when we started this project, so we chose to share ours.  The software development industry generally, and next-generation web platforms specifically, can only benefit from being more security-aware as increasingly sensitive data is made available via the web.

Ben Whaley of AppliedTrust and I recently spent a few months putting together a security model for Rally. We analyzed each module of our Java-based stack, detailing and capturing security considerations along the way. We relied on OWASP as a standardized framework for guiding our process. The goal of the project was to conveniently describe the Rally approach to security at the application layer. Additionally, this model has proven essential for newer members of our development team.

Many companies, particularly SaaS companies, can benefit by having a published security model. Since we had never seen anything quite like this, and because we believe in the open exchange of information, we decided to share the model with the public. Ben and I presented a talk entitled “Effectively marketing security as a win for both the business and the customer” at Front Range OWASP Conference 2010 where we presented the model detailing Rally’s approach to securing our SaaS product. Feel free to take a look at our slides.

We can now arm our sales team with a straightforward (even pretty) picture that represents exactly how we handle security throughout the application. This should assist us with answering questions in those difficult RFP documents from our more security-conscious customers. Also, I truly believe that having our security approach out there for the whole world to see shows a certain level of confidence. It’s clear that we’re not just doing a “security by obscurity” approach.

The development team at Rally has been growing during the last year and it can be difficult to train developers, especially from a security standpoint. The security model serves dual purpose from a training perspective. We now have a current architecture diagram that visually depicts security at each layer of the stack.

Our hope is that other companies can use this model as an example. There was no existing reference point when we started this project, so we chose to share ours.  The software development industry generally, and next-generation web platforms specifically, can only benefit from being more security-aware as increasingly sensitive data is made available via the web.

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!

The other day I needed to cache some data that should expire. Thanks to Google Collections this was incredibly easy.

The entries in this map will expire in 1 hour. Super easy and pretty clean too. Thanks Google.

ConcurrentMap<String, String> cache = new MapMaker().expiration(1, TimeUnit.HOURS).makeMap();

Next Page »