Marcin Erdmann

Groovy, Grails, Geb...

Resizing browser window in Geb tests

It sometimes proves useful to be able to resize browser window in your Geb tests. Up to not so long ago WebDriver (which is used by Geb to drive browsers) did not provide such a functionality and you had to resort to different hacks that never worked in all of the browsers, but thankfully nowadays it is pretty straightforward.

To make sure that the browser window is maximised before any tests are executed we can add the following to the driver closure in GebConfig.groovy:

driver = {
    def driverInstance = new FirefoxDriver()
    driverInstance.manage().window().maximize()
    driverInstance
}

One of the possible usages of browser window resizing can be testing responsive sites. So for example if we want to write a specification that performs some tests on the site laid out as for an iPhone 4 and then maximise the site when done we could use the following:

class IPhone4Spec extends GebSpec {

    void setupSpec() {
        driver.manage().window().size = new Dimension(640, 960)
    }

    void cleanupSpec() {
        driver.manage().window().maximize()
    }

    (...)

}

As a side note, it seems like you can also modify the position of the browser window using the WebDriver.Window class instance which can be retrieved using driver.manage().window() but I can't think of how that could be useful.

Mocking browser timers in Geb tests

Functional tests are usually slow enough and you want to avoid any unnecessary waiting in them. But what should you do if the site you're testing is using animated elements? By simply putting waitFor {} blocks to wait for the animation to finish you're just wasting precious time.

But there is a simple solution - you can easily mock browser timers using sinon.js. Let's see how we can use it in Geb tests to make them faster when testing an example Grails application that contains a carousel.

Assuming that we're using Resources plugin, we'll first need to define a resource module that contains sinon.js and a simple Javascript file that will trigger timer mocking:

modules = {
    fakeTimer {
        resource '/js/test/sinon.js'
        resource '/js/test/fakeTimer.js'
    }
}

In fakeTimer.js file we need to assign the mocked timer to a global variable so that we can then reference it from Geb tests:

var fakeTimer = sinon.useFakeTimers();

The next step is to add the fakeTimer resource module to the head of the tested page. It is important to load it before any other Javascript so that any code that's using timers will not schedule any callbacks before the timers are mocked. We also want to make sure that the timers are mocked only in test environment:

<html>
    <head>
        <g:if env="test"><r:require module="fakeTimer"/></g:if>
        ...
    </head>
    ...
</html>

And finally we can write our test:

class TimeeMockingSpec extends GebSpec {
    void tick(milis) {
        js.exec "fakeTimer.tick($milis)"
    }

    void 'fake time in browser'() {
        when:
        to HomePage

        then:
        activeSlide == 1

        when:
        tick(2100)

        then:
        activeSlide == 2
    }
}

In tick() we are using Geb's js object that allows us to work with Javascript in the browser to call a method on the global object holding the mocked timer. Then it's just a matter of using the tick() method to control the time in the browser in functional tests.

Setting system properties for JUnit run configurations in Intellij using Gradle

There is one particular Gradle feature that I couldn't live without - IDE project generation. Firstly it means that there are no more IDE specific files in your repository. Secondly it is a perfect tool to easily and quickly generate IDE project configuration files in a repeatable and customisable manner.

There are currently two IDE plugins that gradle ships with Eclipse plugin and IDEA plugin. In this post I will describe how to use the latter to customise the generated project configuration files for IntelliJ.

There are three types of Intellij project configuration files - project files (.ipr), module files (.iml) and workspace files (.iws). While Gradle provides a DSL for modyfing those files (at least for project and module files) quite often you will have to revert to using withXml {} hook to do non-standard stuff. It means dealing with those large XML configuration files and understanding their syntax which is not the nicest of tasks but it's worth it.

My use case came from preparing for my "Test driving Gaelyk applications" talk from GGX and Greach. I noticed that when running the tests the console output contained way more logging than I would be happy with. The logging came from the appengine-testing module which is used by Gaelyk Spock Helpers I was showcasing. I needed to change configuration of java.utils.logging to limit the amount of logging produced.

One of the ways of specifying where java.utils.logging config file is located is to use java.util.logging.config.file system property. I knew that I wanted it to be specified for all JUnit run configurations in IntelliJ so I had a look at the .iws file to learn how the default JUnit run configuration part looks like:

<project version="4">
    ...
    <component name="RunManager">
        ...
        <configuration default="true" type="JUnit" factoryName="JUnit">
            ...
            <option name="VM_PARAMETERS" value="" />
            ...
        </configuration>
        ...
    </component>
    ...
</project>

After finding it I knew that I have to modify the VM_PARAMETERS option and that can be done using the idea.workspace.iws.withXml {} hook by simply adding the following to my build.gradle:

idea.workspace.iws.withXml { provider ->
    def node = provider.asNode()
    def runManager = node.component.find { it.'@name' == 'RunManager' }
    def defaultJUnitConf = runManager.configuration.find { it.'@default' == 'true' && it.'@type' == 'JUnit' }
    def vmParametersOption = defaultJUnitConf.option.find { it.'@name' == 'VM_PARAMETERS' }
    vmParametersOption.'@value' = '-Djava.util.logging.config.file=logging.properties'
}

Then all that I needed to to is regenerate the idea files of my project by running gradle idea and reloading the project in the IDE. From then on all the newly created JUnit run configurations had the system property set.

There are other situations where you might want to modify IDE project configuration files. For example to tell IntelliJ that the code is versioned using git so that you don't have to manually do it after you check it out for the first time on a new machine and generete config files for it you would add the following:

idea.project.ipr.withXml { provider ->
    def node = provider.asNode()
    node.component.find { it.'@name' == 'VcsDirectoryMappings' }?.mapping[0].'@vcs' = 'Git'
}

The possibilities here are endless. For example Geb project configures code style settings as well as adds a licence header to all newly created files.

Specifying git revisions using a commit message

Sometimes when I want to rebase some commits in git I cannot be bothered to copy and paste commit hash or calculate how many commits behind HEAD the commit I want to rebase onto is to be able to use the HEAD~N notation.

Recently I've learned from gitrevisions manual that you can also specify a git revision using the :/<text> notation where <text> is a regular expression applied against commit messages. Unfortunately it doesn't work with git rebase complaining that it expects a single revision. But you can always use git rev-parse to resolve a git commit hash:

git rebase -i $(git rev-parse ":/some commit message")

Test driving Gaelyk applications talk from GGX and Greach

The slides from my 'Test driving Gaelyk applications' I gave at Groovy and Grails eXchange 2012 and Greach 2013 are available here.

The example application is available at github.

If you missed it you can still see the recording of the talk from GGX.