The next test script verifies that it is possible to go through multiple pages of results:
@Test
public void canNavigateToOtherPagesTest2() {
HomePage homePage = new HomePage(driver);
homePage.open();
Verify.verify(homePage.isDisplayed(), "home page is not displayed!");
ResultsPage resultsPage = homePage.searchBy(KEYWORD);
Verify.verify(resultsPage.isDisplayed(), "results page is not displayed!");
Verify.verify(resultsPage.getResultsFound().contains("1 to 10"),
"results found label does not include 1 to 10!");
resultsPage.goToPage2();
Assert.assertTrue(resultsPage.getUrl().contains("page=2"));
resultsPage.goToPage3();
Assert.assertTrue(resultsPage.getUrl().contains("page=3"));
resultsPage.goToPage4();
Assert.assertTrue(resultsPage.getUrl().contains("page=4"));
}
The part that we should pay attention to is related to going to page 2, page 3 and page 4 of results.
The goToPage2(), goToPage3(), goToPage4() methods are implemented in the ResultsPage class:
public class ResultsPage {
private WebDriver driver;
private static final String RESULTS_PAGE_URL =
"https://vpl.bibliocommons.com";
private static final By RESULTS_FOUND_XPATH =
By.xpath("(//span[@data-key = 'pagination-text'])[1]");
private static final By PAGE_2_XPATH =
By.xpath("//li[contains(@class, 'page-number')]/a[@data-page = '2']");
private static final By PAGE_3_XPATH =
By.xpath("//li[contains(@class, 'page-number')]/a[@data-page = '3']");
private static final By PAGE_4_XPATH =
By.xpath("//li[contains(@class, 'page-number')]/a[@data-page = '4']");
public ResultsPage(WebDriver driver) {
this.driver = driver;
}
public String getUrl() {
return driver.getCurrentUrl();
}
public boolean isDisplayed() {
return getUrl().startsWith(RESULTS_PAGE_URL);
}
public String getResultsFound() {
WebElement label = driver.findElement(RESULTS_FOUND_XPATH);
return label.getText();
}
public void goToPage2() {
WebElement page = driver.findElement(PAGE_2_XPATH);
page.click();
}
public void goToPage3() {
WebElement page = driver.findElement(PAGE_3_XPATH);
page.click();
}
public void goToPage4() {
WebElement page = driver.findElement(PAGE_4_XPATH);
page.click();
}
}
goToPage2(), goToPage3(), goToPage4() methods are obviously identical.
But the page element locators are also identical, their only difference being the page number:
private static final By PAGE_2_XPATH =
By.xpath("//li[contains(@class, 'page-number')]/a[@data-page = '2']");
private static final By PAGE_3_XPATH =
By.xpath("//li[contains(@class, 'page-number')]/a[@data-page = '3']");
private static final By PAGE_4_XPATH =
By.xpath("//li[contains(@class, 'page-number')]/a[@data-page = '4']");
If we need to expand the test or create other tests that need to interact with more pages (5, 6, 7, 8), then we need to create more locators and more methods.
Which is inefficient.
How do we fix this?
First, we create a locator pattern by replacing the page number with a String placeholder:
private String pageXpath =
"//li[contains(@class, 'page-number')]/a[@data-page = '%s']";
Then, we create a private method that gets as parameter the page number. It replaces the placeholder in the locator pattern with the page number. It finally creates the locator for the page:
private By getPageXpath(int n) {
String locator = String.format(pageXpath, n);
return By.xpath(locator);
}
Since we have the ability to build the locator dynamically, we can create a public method that can click any page. This method gets the page number as parameter as well:
public void goToPage(int n) {
By xpath = getPageXpath(n);
WebElement page = driver.findElement(xpath);
page.click();
}
We can remove the duplicated locators and the duplicated methods from the ResultsPage class:
public class ResultsPage {
private WebDriver driver;
private static final String RESULTS_PAGE_URL =
"https://vpl.bibliocommons.com";
private static final By RESULTS_FOUND_XPATH =
By.xpath("(//span[@data-key = 'pagination-text'])[1]");
private String pageXpath =
"//li[contains(@class, 'page-number')]/a[@data-page = '%s']";
public ResultsPage(WebDriver driver) {
this.driver = driver;
}
public String getUrl() {
return driver.getCurrentUrl();
}
public boolean isDisplayed() {
return getUrl().startsWith(RESULTS_PAGE_URL);
}
public String getResultsFound() {
WebElement label = driver.findElement(RESULTS_FOUND_XPATH);
return label.getText();
}
public void goToPage(int n) {
By xpath = getPageXpath(n);
WebElement page = driver.findElement(xpath);
page.click();
}
private By getPageXpath(int n) {
String locator = String.format(pageXpath, n);
return By.xpath(locator);
}
}
The test script does not change much:
@Test
public void canNavigateToOtherPagesTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Verify.verify(homePage.isDisplayed(), "home page is not displayed!");
ResultsPage resultsPage = homePage.searchBy(KEYWORD);
Verify.verify(resultsPage.isDisplayed(), "results page is not displayed!");
Verify.verify(resultsPage.getResultsFound().contains("1 to 10"),
"results found label does not include 1 to 10!");
resultsPage.goToPage(2);
Assert.assertTrue(resultsPage.getUrl().contains("page=2"));
resultsPage.goToPage(3);
Assert.assertTrue(resultsPage.getUrl().contains("page=3"));
resultsPage.goToPage(4);
Assert.assertTrue(resultsPage.getUrl().contains("page=4"));
}
The changes in the ResultsPage are significant:
we removed all duplicated page locators
we use a single locator for any page
we removed the duplicated methods for going to a specific page
we use a single method that can go to any page
the class is simpler and shorter