Navigation in automation tests scenarios implemented in Gherkin language with PageObject pattern

May 30 2017

There are two approaches for implementation automated test scenarios: implement steps in code or using BDD. First leverages test frameworks such as JUnit, xUnit, Mocha, etc., where tests are implemented in one function. This function will consist of test initialization, action and assertion. Usually you use PageObject pattern to abstract your page specifics from test implementation details. You create, modify and destroy PageObjects in the same function:

@Test
public void testIsActionDone() {
    MainPage page = new MainPage(driver);
    page.action();
    assertTrue(page.isActionDone);
}

So, you can use PageObjects to navigate between pages as well, the way it is described in Martin Fowler’s article. Briefly, each page will return next page if navigation performed

@Test
public void testIsSubActionDone() {
    SubPage page = (new MainPage(driver)).navigateToSubPage();
    page.action();
    assertTrue(page.isActionDone);
}

Another approach for implementation automated test scenarios is to use one of the frameworks based on Gherkin language such as Cucumber, SpecFlow and implement tests using BDD. It means, that test scenario is described as a set of steps, each step is implemented as a separate function in the code

Scenario: Check that action is done
    When I am on the main page
    And I perform action
    Then Action is performed

Where the steps are

public class Steps {
    MainPage page;

    @When("^I am on the main page")
    public void whenOnTheMainPage() {
        page = new MainPage(driver);
        page.openPage();
    }

    @And("^I perform action")
    public void whenPerformAction() {
        page.action();
    }

    @Then("^Action is performed")
    public void verifyActionDone() {
        assertTrue(page.isActionDone);
    }
}

Usually steps are defined in different files, which makes it hard using navigation approach described above. Each step definition in the scenario should be self contained and do not share state between each other. So, to implement navigation and be able to use different PageObjects in steps we will implement helper function which is going to check if given PageObject represents current page and create it automatically.

public class BasePage {
    public static <T extends AbstractPage> T onPage(Class<T> cl) {
        T page = PageFactory.initElements(DriverManager.getDriver(), cl);
        if (page.isOnPage()) {
            return page;
        }
        return null;
    }
}

The only requirement for this function to work is: each PageObject should implement method isOnPage, which returns true if PageObject represents current page, otherwise false. Now PageObject organizes navigation to the next page if needed and waits till the page is loaded? but instead of returning new PageObject we use onPage function. Thus, implementation for testIsSubActionDone scenario using BDD will be

Scenario: Check that action is done
    When I am on the main page
    And I go to the sub page
    And I perform action
    Then Action is performed
public class MainSteps {
    @When("^I am on the main page")
    public void whenOnTheMainPage() {
        page = new MainPage(driver);
        page.openPage();
    }

    @And("^I go to the sub page")
    public void whenGoToTheSubPage() {
        onPage(MainPage.class).action();
    }
}

public class SubSteps {
    @And("^I perform action")
    public void whenPerformAction() {
        onPage(SubPage.class).action();
    }

    @Then("^Action is performed")
    public void verifyActionDone() {
        assertTrue(onPage(SubPage.class).isActionDone);
    }
}

As a result, we learnt how to leverage onPage method to organize navigation between pages in automated test scenarios, which are implemented using Cucumber, SpecFlow or another framework based on Gherkin language and use PageObjects to abstract from page implementation details.