Revise GEB Functional Tests in Grails

At work, i have been doing enough functional tests to begun note some important aspects that can help boost productativity

Accessing Page Content in Helper Method

In my fellow developer’s code, i noticed in Page objects a lot of¬†repetitive¬†setters for each page content defined. Here is example:

class RentalUnitEditPage extends Page {
...
    static content = {
        nameInput(wait: true) { $("input#name") }
        review(wait: true) { $("select", id: "review.id") }
        someGroupSelect(wait: true) { $("select#someGroup\\.id") }
        paymentMethodSelect(wait: true) { $('select#paymentMethodType') }
        companyTypeSelect(wait: true) { $('select#companyType') }
        groupSizeSelect(wait: true) { $('select#classification') }
...
}

    void setName(String newName) {
        nameInput.value(newName)
    }

    void setSomeGroup(String group) {
        someGroupSelect.value(group)
    }

    void setReview(String rev) {
        review.value(rev)
    }

    void setPaymentMethod(PaymentMethodType paymentMethod) {
        paymentMethodSelect.value(paymentMethod.id)
    }
...
}

As you see, there is setter for each input variable and we need setter because in the test we update fields to validate it updated correctly, however. With so many setters, we certainly are not following DRY(Don’t Repeat Yourself) principle. To do so, instead of the many setters for each field, lets have general setter as follows:

class RentalUnitEditPage extends Page {
...
    void setField(String fieldName, String fieldValue){
        browser.page."$fieldName".value(fieldValue)
    }
...
}

So, this way we can remove the many setters only having one – the general one described above

Upload file widget Module Example

In the ‘Book of GEB‘, it encourages to use Modules for reusing functionality. Here is an example of module for uploading files widget:


class LoadFileModule extends Module {
    String buttonName
    String inputId
    String inputUrl

    static content = {
        fileUploadField(wait: true) { $("input#${inputId}") }
        loadButton(wait: true) { $("input", name: buttonName) }
    }

    void clickLoad(Class toPage){
        fileUploadField.value(inputUrl)
        loadButton.click(toPage)
    }
}

So, for page objects that has the upload file widget, you don’t have to recreate functionality to upload file in test. You could just include the LoadFileModule module and use it as follows:

class SomeLoadPage extends Page {
...
    static content = {
        ...
        loadFile(wait: true) { inId, inUrl, bName -> module  LoadFileModule, inputId: inId, inputUrl: inUrl, buttonName: bName}
    }

    AfterLoadStatusPage loadSomeFile(String filePath) {
        loadFile("fileInputFieldId", filePath, "uploadFileButtonName").clickLoad(AfterLoadStatusPage)
        ...
    }
}

As you can see, first we load the module LoadFileModule(highlighted line) and pass three parameters – inId that is fileInputFieldId, inUrl that is file path and bName that is the button name. Then, in your test to load file all you need is call this method while giving file path.

Leave a Reply

Your email address will not be published. Required fields are marked *