There are many incorrect ways of writing Selenium tests.
1. This is the worst:
@Test
public void searchReturnsResultsTest() {
driver.get(URL);
Assert.assertTrue(driver.getCurrentUrl().contains(URL));
WebDriver searchBox = driver.findElement(searchBoxId);
searchBox.click();
searchBox.clear();
searchBox.sendKeys(KEYWORD);
WebDriver searchButton = driver.findElement(searchButtonId);
searchButton.click();
Assert.assertTrue(driver.getCurrentUrl().contains(RESULTS_PAGE_URL));
WebElement paginationInfoLabel = driver.findElement(paginationInfoId);
String paginationInfo = paginationInfoLabel.getText();
Assert.assertTrue(paginationInfo.contains("1 to 10 results"));
}
Why is this not good?
the test will need to be changed significantly every time there is a change in the site.
this is not object oriented code.
this code is hard to read, understand and maintain.
the test class contains all element locators
there is no way of re-using code between test classes
the test uses Selenium methods and objects; this is a bad practice as per Simon Stewart
2. Which leads us to
@Test
public void searchReturnsResultsTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Assert.assertTrue(homePage.getUrl().contains(URL));
homePage.searchBox.click();
homePage.searchBox.clear();
homePage.searchBox.sendKeys(KEYWORD);
homePage.searchButton.click();
ResultsPage resultsPage = new ResultsPage(driver);
Assert.assertTrue(resultsPage.getUrl().contains(RESULTS_PAGE_URL));
String paginationInfo = resultsPage.paginationInfoLabel.getText();
Assert.assertTrue(paginationInfo.contains("1 to 10 results"));
}
This test uses 2 page classes, HomePage and ResultsPage.
HomePage.java is below:
public class HomePage {
private static final String URL = "https://www.abc.com";
private WebDriver driver;
@FindBy(id = "searchBoxId")
public WebElement searchBox;
@FindBy(id = "searchButtonId")
public WebElement searchButton;
public HomePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void open() {
driver.get(URL);
}
public String getUrl() {
return driver.getCurrentUrl();
}
....................
}
This approach is also not good because
no page class fields should be public; only page methods should be public and not all of them
the test focuses on interacting with elements of the page instead of emulating user actions
when there are changes in the pages of the site, both the page classes and the test methods will need to be modified.
3. Another incorrect approach is
@Test
public void searchReturnsResultsTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Assert.assertTrue(homePage.getUrl().contains(URL));
homePage.clickSearchBox();
homePage.clearSearchBox();
homePage.sendKeysSearchBox(KEYWORD);
homePage.clickSearchButton();
ResultsPage resultsPage = new ResultsPage(driver);
Assert.assertTrue(resultsPage.getUrl().contains(RESULTS_PAGE_URL));
String paginationInfo = resultsPage.getTextPaginationInfoLabel();
Assert.assertTrue(paginationInfo.contains("1 to 10 results"));
}
public class HomePage {
private static final String URL = "httpds://www.abc.com";
private WebDriver driver;
private By searchBoxId = By.id("searchBoxId");
private By searchButtonId = By.id("searchButtonId");
public HomePage(WebDriver driver) {
this.driver = driver;
}
public void open() {
driver.get(URL);
}
public String getUrl() {
return driver.getCurrentUrl();
}
public void clickSearchBox() {
searchBox().click();
}
public void clearSearchBox() {
searchBox().clear();
}
public void sendKeysSearchBox(String keyword) {
searchBox().sendKeys(keyword);
}
public void clickSearchButton() {
searchButton().click();
}
private WebElement searchBox() {
return driver.findElement(searchBoxId);
}
private WebElemewnt searchButton() {
return driver.findElement(searchButtonId);
}
....................
}
The page classes are not using Page Factory any longer. They also do not have public WebElement fields.
But they are full of methods that implement possible actions on each element of the page. This is a problem.
The other problem is that the test is still focused on interacting with the elements of the site instead of emulating the user actions.
And, when there are changes in the pages of the site, both the page classes and the test methods will need to be modified.
Finally, about the correct approach.
It does not have the test interacting with the elements of each page. Instead, the test emulates the user actions:
@Test
public void searchReturnsResultsTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
Assert.assertTrue(homePage.isDisplayed());
homePage.searchFor(KEYWORD);
ResultsPage resultsPage = new ResultsPage(driver);
Assert.assertTrue(resultsPage.isDisplayed());
Assert.assertTrue(resultsPage.getPaginationInfo()
.contains("1 to 10 results"));
}
public class HomePage {
private static final String URL = "https://www.abc.com";
private WebDriver driver;
private By searchBoxId = By.id("searchBoxId");
private By searchButtonId = By.id("searchButtonId");
public HomePage(WebDriver driver) {
this.driver = driver;
}
public void open() {
driver.get(URL);
}
public boolean isDisplayed() {
return driver.getCurrentUrl().equals(URL);
}
public void searchFor(String keyword) {
WebElement searchBox = driver.findElement(searchBoxId);
searchBox.click();
searchBox.clear();
searchBox.sendKeys(keyword);
WebElement searchButton = driver.findElement(searchButtonId);
searchButton.click();
}
....................
}
Thanks for reading.