We have 3 tests for checking that filtering results (by books, comic books and ebooks) works. Each test goes through the following steps:
execute a keyword search
verify that there are results on the results page
verify that the specific filter is not checked by default
checks the filter
verify that the filter is checked
unchecks the filter
verify that the filter is unchecked again
public class WebTest_PageObjectClasses {
private WebDriver driver;
private static final String HOME_PAGE_URL = "https://www.vpl.ca/";
private static final String RESULTS_PAGE_URL =
"https://vpl.bibliocommons.com";
private static final String KEYWORD = "java";
private static final By SEARCH_BOX_ID = By.id("edit-search");
private static final By SEARCH_BUTTON_ID = By.id("edit-submit");
private static final By RESULTS_FOUND_XPATH =
By.xpath("(//span[@data-key = 'pagination-text'])[1]");
private static final By BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-BK']");
private static final By COMIC_BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-COMIC_BK']");
private static final By E_BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-EBOOK']");
@BeforeMethod
public void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@AfterMethod
public void tearDown() {
driver.quit();
}
@Test
public void canFilterByBooksTest() {
driver.get(HOME_PAGE_URL);
Verify.verify(driver.getCurrentUrl().equalsIgnoreCase(HOME_PAGE_URL));
WebElement searchBox = driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(KEYWORD);
WebElement searchButton = driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
Verify.verify(driver.getCurrentUrl().startsWith(RESULTS_PAGE_URL),
"results page url does not start with " + RESULTS_PAGE_URL);
WebElement resultsFoundLabel = driver.findElement(RESULTS_FOUND_XPATH);
Verify.verify(resultsFoundLabel.getText().contains("1 to 10"),
"results found label does not include 1 to 10!");
WebElement bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "false");
bookFilter.click();
bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "true");
bookFilter.click();
bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "false");
}
@Test
public void canFilterByComicBooksTest() {
driver.get(HOME_PAGE_URL);
Verify.verify(driver.getCurrentUrl().equalsIgnoreCase(HOME_PAGE_URL));
WebElement searchBox = driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(KEYWORD);
WebElement searchButton = driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
Verify.verify(driver.getCurrentUrl().startsWith(RESULTS_PAGE_URL),
"results page url does not start with " + RESULTS_PAGE_URL);
WebElement resultsFoundLabel = driver.findElement(RESULTS_FOUND_XPATH);
Verify.verify(resultsFoundLabel.getText().contains("1 to 10"),
"results found label does not include 1 to 10!");
WebElement comicBookFilter = driver.findElement(COMIC_BOOK_FILTER_XPATH);
Assert.assertEquals(comicBookFilter.getAttribute("aria-checked"),
"false");
comicBookFilter.click();
comicBookFilter = driver.findElement(COMIC_BOOK_FILTER_XPATH);
Assert.assertEquals(comicBookFilter.getAttribute("aria-checked"),
"true");
comicBookFilter.click();
comicBookFilter = driver.findElement(COMIC_BOOK_FILTER_XPATH);
Assert.assertEquals(comicBookFilter.getAttribute("aria-checked"),
"false");
}
@Test
public void canFilterByEBooksTest() {
driver.get(HOME_PAGE_URL);
Verify.verify(driver.getCurrentUrl().equalsIgnoreCase(HOME_PAGE_URL));
WebElement searchBox = driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(KEYWORD);
WebElement searchButton = driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
Verify.verify(driver.getCurrentUrl().startsWith(RESULTS_PAGE_URL),
"results page url does not start with " + RESULTS_PAGE_URL);
WebElement resultsFoundLabel = driver.findElement(RESULTS_FOUND_XPATH);
Verify.verify(resultsFoundLabel.getText().contains("1 to 10"),
"results found label does not include 1 to 10!");
WebElement eBookFilter = driver.findElement(E_BOOK_FILTER_XPATH);
Assert.assertEquals(eBookFilter.getAttribute("aria-checked"), "false");
eBookFilter.click();
eBookFilter = driver.findElement(E_BOOK_FILTER_XPATH);
Assert.assertEquals(eBookFilter.getAttribute("aria-checked"), "true");
eBookFilter.click();
eBookFilter = driver.findElement(E_BOOK_FILTER_XPATH);
Assert.assertEquals(eBookFilter.getAttribute("aria-checked"), "false");
}
}
The tests are pretty much duplicated. The only thing that is different in them is the locator of the filter that is being used in the test.
Code duplication is never good so we should get rid of it.
We will do this in a few simple steps.
figure out what actions are executed in each test
break down the test so it is clear what happens in the home page and what happens in the results page
determine the variables and locators used for each page used by the test
create a class for HomePage; move all code that interacts with home page and all variables related to home page to the HomePage class
create a class for ResultsPage; move all code that interacts with results page and all variables related results page to the ResultsPage class
use home page and results page objects in the test
Step 1 - figure out what actions are executed in each test
See below all actions that are done inside of each test.
I added comments for each action, describing what it does:
@Test
public void canFilterByBooksTest() {
//ACTION: open page
driver.get(HOME_PAGE_URL);
//ACTION: get current url
//ACTION: is the url correct
//VERIFICATION: verify if the current url is correct
Verify.verify(driver.getCurrentUrl().equalsIgnoreCase(HOME_PAGE_URL));
//ACTION: type keyword in search box
WebElement searchBox = driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(KEYWORD);
//ACTION: click search button
WebElement searchButton = driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
//ACTION: get current url
//ACTION: is the url correct
//VERIFICATION: verify if the url is correct
Verify.verify(driver.getCurrentUrl().startsWith(RESULTS_PAGE_URL),
"results page url does not start with " + RESULTS_PAGE_URL);
//ACTION: get results found label
//VERIFICATION: verify if it contains "1 to 10"
WebElement resultsFoundLabel = driver.findElement(RESULTS_FOUND_XPATH);
Verify.verify(resultsFoundLabel.getText().contains("1 to 10"),
"results found label does not include 1 to 10!");
//ACTION: get aria-checked attribute of the book filter
//VERIFICATION: verify that the attribute value is equal to false
WebElement bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "false");
//ACTION: click the book filter element
bookFilter.click();
//ACTION: get aria-checked attribute of the book filter
//VERIFICATION: verify that the attribute value is equal to true
bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "true");
//ACTION: click the book filter element
bookFilter.click();
//ACTION: get aria-checked attribute of the book filter
//VERIFICATION: verify that the attribute value is equal to true
bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "false");
}
Step 2 - break down the test code by page
The first part of the test is about the home page:
test loads the home page
test verifies that the home page url is correct
types a keyword in the search box
clicks the search button
The remaining part of the test is about the results page:
@Test
public void canFilterByBooksTest() {
//HOME PAGE
driver.get(HOME_PAGE_URL);
Verify.verify(driver.getCurrentUrl().equalsIgnoreCase(HOME_PAGE_URL));
WebElement searchBox = driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(KEYWORD);
WebElement searchButton = driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
//RESULTS PAGE
Verify.verify(driver.getCurrentUrl().startsWith(RESULTS_PAGE_URL),
"results page url does not start with " + RESULTS_PAGE_URL);
WebElement resultsFoundLabel = driver.findElement(RESULTS_FOUND_XPATH);
Verify.verify(resultsFoundLabel.getText().contains("1 to 10"),
"results found label does not include 1 to 10!");
WebElement bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "false");
bookFilter.click();
bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "true");
bookFilter.click();
bookFilter = driver.findElement(BOOK_FILTER_XPATH);
Assert.assertEquals(bookFilter.getAttribute("aria-checked"), "false");
}
Step 3 - break down the variables and locators by page
//TEST variables
private WebDriver driver;
private static final String KEYWORD = "java";
//HOME PAGE variables
private static final String HOME_PAGE_URL = "https://www.vpl.ca/";
private static final By SEARCH_BOX_ID = By.id("edit-search");
private static final By SEARCH_BUTTON_ID = By.id("edit-submit");
//RESULTS PAGE variables
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 BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-BK']");
private static final By COMIC_BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-COMIC_BK']");
private static final By E_BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-EBOOK']");
Step 4 - create a class for home page
Create a HomePage class for all test interactions with the home page of the site.
Move to it all variables (url and locators) related to the home page.
Create methods in the new class for all actions that happen in home page.
public class HomePage {
private WebDriver driver;
private static final String HOME_PAGE_URL = "https://www.vpl.ca/";
private static final String KEYWORD = "java";
private static final By SEARCH_BOX_ID = By.id("edit-search");
private static final By SEARCH_BUTTON_ID = By.id("edit-submit");
public HomePage(WebDriver driver) {
this.driver = driver;
}
public void open() {
driver.get(HOME_PAGE_URL);
}
public boolean isDisplayed() {
return getUrl().equalsIgnoreCase(HOME_PAGE_URL);
}
public String getUrl() {
return driver.getCurrentUrl();
}
public void typeKeywordInSearchBox(String keyword) {
WebElement searchBox = driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(keyword);
}
public void clickSearchButton() {
WebElement searchButton = driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
}
}
Step 5 - create a class for results page
Create a ResultsPage class for all test interactions with the results page of the site.
Move to it all variables (url and locators) related to the results page.
Create methods in the new class for all actions that happen in results page.
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 BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-BK']");
private static final By COMIC_BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-COMIC_BK']");
private static final By E_BOOK_FILTER_XPATH =
By.xpath("//button[@aria-labelledby='label_FORMAT-BOOKS-EBOOK']");
public ResultsPage(WebDriver driver) {
this.driver = driver;
}
public String getUrl() {
return driver.getCurrentUrl();
}
public boolean isDisplayed() {
return getUrl().startsWith(RESULTS_PAGE_URL);
}
public String getResultsFoundValue() {
WebElement label = driver.findElement(RESULTS_FOUND_XPATH);
return label.getText();
}
public String getBookFilterEnabledAttribute() {
WebElement filter = driver.findElement(BOOK_FILTER_XPATH);
return filter.getAttribute("aria-checked");
}
public void clickBookFilter() {
WebElement filter = driver.findElement(BOOK_FILTER_XPATH);
filter.click();
}
public String getComicBookFilterEnabledAttribute() {
WebElement filter = driver.findElement(COMIC_BOOK_FILTER_XPATH);
return filter.getAttribute("aria-checked");
}
public void clickComicBookFilter() {
WebElement filter = driver.findElement(COMIC_BOOK_FILTER_XPATH);
filter.click();
}
public String getEBookFilterEnabledAttribute() {
WebElement filter = driver.findElement(E_BOOK_FILTER_XPATH);
return filter.getAttribute("aria-checked");
}
public void clickEBookFilter() {
WebElement filter = driver.findElement(E_BOOK_FILTER_XPATH);
filter.click();
}
}
Step 6 - use home page and results page objects in the test
@Test
public void canFilterByBooksTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Verify.verify(homePage.isDisplayed(), "home page is not displayed!");
homePage.typeKeywordInSearchBox(KEYWORD);
homePage.clickSearchButton();
ResultsPage resultsPage = new ResultsPage(driver);
Verify.verify(resultsPage.isDisplayed(), "results page is not displayed!");
Verify.verify(resultsPage.getResultsFoundValue().contains("1 to 10"),
"results found label does not include 1 to 10!");
Assert.assertEquals(resultsPage.getBookFilterEnabledAttribute(), "false");
resultsPage.clickBookFilter();
Assert.assertEquals(resultsPage.getBookFilterEnabledAttribute(), "true");
resultsPage.clickBookFilter();
Assert.assertEquals(resultsPage.getBookFilterEnabledAttribute(), "false");
}
@Test
public void canFilterByComicBooksTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Verify.verify(homePage.isDisplayed(), "home page is not displayed!");
homePage.typeKeywordInSearchBox(KEYWORD);
homePage.clickSearchButton();
ResultsPage resultsPage = new ResultsPage(driver);
Verify.verify(resultsPage.isDisplayed(), "results page is not displayed!");
Verify.verify(resultsPage.getResultsFoundValue().contains("1 to 10"),
"results found label does not include 1 to 10!");
Assert.assertEquals(resultsPage.getComicBookFilterEnabledAttribute(),
"false");
resultsPage.clickComicBookFilter();
Assert.assertEquals(resultsPage.getComicBookFilterEnabledAttribute(),
"true");
resultsPage.clickBookFilter();
Assert.assertEquals(resultsPage.getComicBookFilterEnabledAttribute(),
"true");
}
@Test
public void canFilterByEBooksTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Verify.verify(homePage.isDisplayed(), "home page is not displayed!");
homePage.typeKeywordInSearchBox(KEYWORD);
homePage.clickSearchButton();
ResultsPage resultsPage = new ResultsPage(driver);
Verify.verify(resultsPage.isDisplayed(), "results page is not displayed!");
Verify.verify(resultsPage.getResultsFoundValue().contains("1 to 10"),
"results found label does not include 1 to 10!");
Assert.assertEquals(resultsPage.getEBookFilterEnabledAttribute(), "false");
resultsPage.clickEBookFilter();
Assert.assertEquals(resultsPage.getEBookFilterEnabledAttribute(), "true");
resultsPage.clickEBookFilter();
Assert.assertEquals(resultsPage.getEBookFilterEnabledAttribute(), "false");
}
There are several improvements when using page objects in the test:
the tests are shorter
the tests rely only on page object methods; it does not matter how the page methods are implemented; all complex code is moved to the page classes which makes the tests simpler
the code duplication is removed
it is clear what code executes on home page and what code on results page
there are no Selenium objects and methods in the tests with the exception of the driver