Let’s start with a simple Selenium test as follows:
@Test
public void canPlaceHoldOnProductTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
assertTrue(homePage.isDisplayed());
ResultsPage resultsPage = homePage.search(keyword);
assertTrue(resultsPage.isDisplayed());
ProductPage productPage = resultsPage.selectProduct(1);
assertTrue(productPage.isDisplayed());
LoginPage loginPage = productPage.placeHold();
assertTrue(loginPage.isDisplayed());
UserPage userPage = loginPage.loginWith(username, password);
assertTrue(userPage.isDisplayed);
assertTrue(userPage.hasProductHold());
}
The test is very simple as it goes from page to page until it reaches the page under test (UserPage) where is executes an assertion.
The test uses page objects, one for each page involved in the test scenario.
The navigation from one page to the next is clear since the method from each page class that initiates the page change returns a page object that corresponds to the next page:
search() method of HomePage class returns a ResultsPage object
selectProduct() method of ResultsPage class returns a ProductPage object
placeHold() method of ProductPage class returns a LoginPage object
loginWith() method of LoginPage class returns a UserPage object
All the time, it is clear in this test where the user action is executed, in which page.
Before interacting with any of the pages, the test verifies first that the page is displayed.
But the test is fairly long.
Can it be made shorter?
These are the methods from each page class that the test uses:
public class HomePage {
.................
public ResultsPage search(String keyword) {
.....................
return new ResultsPage(driver);
}
}
public class ResultsPage {
.................
public ProductPage selectProduct(int i) {
................
return new ProductPage(driver);
}
}
public class ProductPage {
..................
public LoginPage placeHold() {
................
return new LoginPage(driver);
}
}
public class LoginPage {
.....................
public UserPage loginWith(String username, String password) {
............
return new UserPage(driver);
}
}
One thing that we could do is to move all assertions from the test to the page methods as follows:
public class HomePage {
.................
public ResultsPage search(String keyword) {
.....................
ResultsPage resultsPage = new ResultsPage(driver);
assertTrue(resultsPage.isDisplayed());
return resultsPage;
}
}
public class ResultsPage {
.................
public ProductPage selectProduct(int i) {
................
ProductPage productPage = new ProductPage(driver);
assertTrue(productPage.isDisplayed());
return productPage;
}
}
public class ProductPage {
..................
public LoginPage placeHold() {
................
LoginPage loginPage = new LoginPage(driver);
assertTrue(loginPage.isDisplayed());
return loginPage;
}
}
public class LoginPage {
.....................
public UserPage loginWith(String username, String password) {
............
UserPage userPage = new UserPage(driver);
assertTrue(userPage.isDisplayed());
return userPage;
}
}
With the new page methods, the test does get shorter:
@Test
public void canPlaceHoldOnProductTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
ResultsPage resultsPage = homePage.search(keyword);
ProductPage productPage = resultsPage.selectProduct(1);
LoginPage loginPage = productPage.placeHold();
UserPage userPage = loginPage.loginWith(username, password);
assertTrue(userPage.hasProductHold());
}
All assertions that validate that pages are displayed are gone.
Can we do anything else to shorten the test?
Yes, we can chain the methods.
@Test
public void canPlaceHoldOnProductTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
UserPage userPage = homePage.search(keyword).selectProduct(1)
.placeHold().loginWith(username, password);
assertTrue(userPage.hasProductHold());
}
Wow, what a short test!!!
Amazing, no?
The test may be short but shortness comes with a lot of disadvantages:
all navigation is happening in 1 line of code that executes 4 chained methods; if there is an exception in any of these methods, it will be unclear where the exception happened
the code is hard to understand since, even if it is obvious that search() belongs to HomePage, it is not obvious at all to which page class the other 3 methods belong
the navigation from page to page is not obvious
you may be under the impression that the test has 1 assertion; it has a few more hidden inside of the page classes
This method chaining seems like a good idea.
It is not.
Just because we can do it, it does not mean that we should.
The original test is the optimal one.