groovygeb

Is there a way in Geb to automatically assign the right Module to all Elements in a Form


We use Geb to run our Frontend Tests and we have some quite complex pages in our application.

Some of the pages have forms with a lot of different buttons, checkboxes and some multiselects.

I love the feature of geb/groovy that i just have to define the form in the Page Object and then can access all its elements in it.

static content = {
    form { $("#form")}
}

But for them to be clickable and to query if they are readonly and more they need to be at least of type FormElement which does not happen with the above method. So I have to mention all these FormElements separately:

static content = {
    form { $("#form")}
    button1 { $("#button1").module(FormElement)}
    button2 { $("#button2").module(FormElement)}
    checkbox{ $("#checkbox").module(Checkbox)}
    ...
}

All those buttons, checkboxes... are already in the form variable, but cannot be clicked or checked if they are selected and so on. It's also not possible to apply the the module afterwards like this:

def "test something"() {
    when:
        form.button1.module(FormElement).click() //error
    then:
        ...
}

Is there no way to automatically assign each input, checkbox, radiobutton, button,... the correct Module based on their type without the need of doing it by hand?

If someone could also point me in the right direction to understand how this "form { $("#form")}" works, that i can access all sub elements by its name by just suppying the form, that would be nice!


Solution

  • For your example of creating a module based on a form control you need to obtain a navigator for the control and not it's value. It's done by calling a method named the same as the control you're trying to access (it's explained in this section of The Book of Geb):

    form.button1().module(FormElement).click()
    

    If you want to automatically create modules based on the element type then you could create a Module for the form and override method missing:

    class FormModule extends Module {
    
        Object methodMissing(String name, Object args) {
            def result = super.methodMissing(name, args)
            if (result instanceof Navigator && result.tag() == "input") {
                switch (result.@type) {
                    case "checkbox":
                        result = result.module(Checkbox)
                        break
                    default:
                        result = result.module(FormElement)
                }
            }
            result
        }
    
    }
    

    then you would use it like:

    static content = {
        form { $("#form").module(FormModule) }
    }
    
    form.button1().click()