Hi folks,

One of the major benefits of the Apache Isis framework (and more generally
the naked objects pattern) is that as a developer you get a user interface
"for free".  So given that the responsibility for rendering your domain
objects moves into the framwork, it's a little embarrassing that the
framework itself doesn't have any end-2-end browser (ie Selenium) tests to
check that the rendering is correct.  I'd really like to address that.

But it would also be useful, I think, for the framework to make it easy for
projects to write their own end-to-end tests.  Even though using
integration tests and unit tests should be the standard way of verifying
that the business functionality of the application works as expected,
having as a minimum some browser based tests for smoke tests could be
worthwhile in many cases, especially as more and more of us are moving to
continuous deployment and tighter release schedules.

Another use case is BDD, where the output of the BDD tests acting as
"living documentation" to describe the behaviour of the system.  Being able
to hook up a BDD framework to an end-to-end testing framework that can take
screenshots of the "journey" through the application would make that living
documentation that much more compelling.

On the other hand, end-to-end tests are notoriously labour intensive to
develop, and can be expensive to maintain.  Any support that the framework
provides should substantially address these issues.

With that in mind, I've started to do some exploration, using the
kitchensink app [1].  What's emerging is the following architecture:

- a set of page objects that could in principle be code-generated from
Isis' own metamodel
- tests that then use these page objects

If the Wicket viewer is changed, then the code generation would also be
updated; the tests would not change.  And, because the page objects are
code generated, they would be quite standardised and so hopefully easy to
use.

These page objects I see as being code-generated by the isis-maven-plugin,
probably using freemarker templates.  These would then be compiled into
bytecode using a subsequent maven compiler plugin later on in the build
pipeline.  Finally, the tests would compile against these page objects.  In
this way, the end-to-end tests would therefore belong in the same repo as
the application under test.

In terms of how this might look, in the kitchensink I've been using the
(groovy) geb and spock libraries.

For example, given BusRulesObject [2] domain service:

public class BusRulesObjects {
    ...
    public List<BusRulesObject> listAllBusRulesObject() { ... }
    public BusRulesObject findBusRulesObject(final String name) {  ... }
    ...
}

then the listAll could be tested using [3]:

@Stepwise
class S_040_BusRulesObject_ListAllBusRulesObject extends
GebReportingSpecWithApprovals {

    void "Business Rules Object > List All Bus Rules Object"() {
        given:
        def page = at LoggedInPage

        when:
        page.busRulesObjects.menu.jquery.mouseover()
        page.busRulesObjects.listAllBusRulesObject.menuItem.click()

        then:
        at BusRulesObject_StandaloneCollectionPage
    }

    void "Check 1st Row"() {
        when:
        def page = at BusRulesObject_StandaloneCollectionPage

        then:
        page.tablePanel.columns.name(0) =~ /Foo/
        page.tablePanel.columns.enableActions(0) == false
    }

    void "Navigate to 1st Entity"() {
        given:
        def page = at BusRulesObject_StandaloneCollectionPage

        when:
        page.tablePanel.columns.objectTitle(0).click()

        then:
        def nextPage = at BusRulesObject_EntityPage
        nextPage.objectTitle =~ /Foo/
    }
}

and the finder could be tested using [4]:

@Stepwise
class S_050_BusRulesObjects_FindBusRulesObject extends
GebReportingSpecWithApprovals {

    void "Business Rules Object > Find Bus Rules Object"() {
        given:
        def page = at LoggedInPage

        when:
        page.busRulesObjects.menu.jquery.mouseover()
        page.busRulesObjects.findBusRulesObject.menuItem.click()

        then:
        page.busRulesObjects.findBusRulesObject.prompt.displayed

        when: "Missing name"

page.busRulesObjects.findBusRulesObject.prompt.parameters.name.input = ""
        page.busRulesObjects.findBusRulesObject.prompt.ok.click()

        then:

page.busRulesObjects.findBusRulesObject.prompt.parameters.name.feedback.text()
=~ /'Name' is required./
        report "name is required"

        when: "Enter all details"

page.busRulesObjects.findBusRulesObject.prompt.parameters.name.input = "Foo"
        page.busRulesObjects.findBusRulesObject.prompt.ok.click()

        then:
        at EntityPage
    }
}

Each of these would result in a number of geb "module"s [5], these are the
classes that would be code generated.

All in all it's going to be quite a bit of effort to develop out these page
object generation, though my hunch is that this will be worthwhile in the
end.  Not only will the current community benefit, it would also be a
rather unique selling point for the framework.

So, *if anyone is interested in helping out, please reply on this thread*.
You'll need to have some familiarity (or willing to learn) with
Selenium/geb and CSS, but you don't need to understand the internals of the
framework to assist.

Many thanks
Dan


[1] https://github.com/isisaddons/isis-app-kitchensink  (maint-1.16.1
branch)
[2]
https://github.com/isisaddons/isis-app-kitchensink/blob/maint-1.16.1/dom/src/main/java/org/isisaddons/app/kitchensink/dom/busrules/BusRulesObjects.java
[3]
https://github.com/isisaddons/isis-app-kitchensink/blob/maint-1.16.1/tests-e2e/src/test/groovy/org/isisaddons/app/kitchensink/e2etests/specs/S_040_BusRulesObject_ListAllBusRulesObject.groovy
[4]
https://github.com/isisaddons/isis-app-kitchensink/blob/maint-1.16.1/tests-e2e/src/test/groovy/org/isisaddons/app/kitchensink/e2etests/specs/S_050_BusRulesObjects_FindBusRulesObject.groovy
[5]
https://github.com/isisaddons/isis-app-kitchensink/blob/maint-1.16.1/tests-e2e/src/test/groovy/org/isisaddons/app/kitchensink/e2etests/modules/busrules/BusRulesObjects/BusRulesObjects.groovy

Reply via email to