A possible solution to the code duplication from the previous post, where all static page methods use a driver parameter, is to create the driver as a static variable in the test class:
public class WebTests {
public static WebDriver driver;
private static final String KEYWORD = "java";
@BeforeMethod
public void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@AfterMethod
public void tearDown() {
driver.quit();
}
@Test
public void canNavigateToOtherPagesTest() {
HomePage.open();
Verify.verify(HomePage.isDisplayed());
HomePage.searchBy(KEYWORD);
Verify.verify(ResultsPage.isDisplayed());
Verify.verify(ResultsPage.getResultsFound().contains("1 to 10"));
ResultsPage.goToPage(2);
Assert.assertTrue(ResultsPage.urlContains(2));
ResultsPage.goToPage(3);
Assert.assertTrue(ResultsPage.urlContains(3));
}
}
No more driver parameter for all static page methods!
How did this happen?
This is all possible because the driver variable is declared as static in the WebTests class:
public static WebDriver driver;
Because of this, in any page method, the driver can be accessed with WebTests.driver.
This is the HomePage class updated to use the static driver variable:
public class HomePage {
private static final String HOME_PAGE_URL = "https://www.vpl.ca/";
private static final By SEARCH_BOX_ID = By.id("edit-keyword");
private static final By SEARCH_BUTTON_ID = By.id("edit-submit");
public static void open() {
WebTests.driver.get(HOME_PAGE_URL);
}
public static boolean isDisplayed() {
return getUrl().equalsIgnoreCase(HOME_PAGE_URL);
}
public static String getUrl() {
return WebTests.driver.getCurrentUrl();
}
public static void searchBy(String keyword) {
typeKeyword(keyword);
clickSearchButton();
}
public static void typeKeyword(String keyword) {
WebElement searchBox = WebTests.driver.findElement(SEARCH_BOX_ID);
searchBox.sendKeys(keyword);
}
public static void clickSearchButton() {
WebElement searchButton = WebTests.driver.findElement(SEARCH_BUTTON_ID);
searchButton.click();
}
}
And this is ResultsPage class updated in the same way:
public class ResultsPage {
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 String pageXpath =
"//li[contains(@class, 'page-number')]/a[@data-page = '%s']";
public static String getUrl() {
return WebTests.driver.getCurrentUrl();
}
public static boolean isDisplayed() {
return getUrl().startsWith(RESULTS_PAGE_URL);
}
public static String getResultsFound() {
WebElement label = WebTests.driver.findElement(RESULTS_FOUND_XPATH);
return label.getText();
}
public static void goToPage(int n) throws InterruptedException {
scrollToBottom();
By xpath = getPageXpath(n);
Thread.sleep(2000);
WebElement page = WebTests.driver.findElement(xpath);
page.click();
}
private static By getPageXpath(int n) {
String locator = String.format(pageXpath, n);
return By.xpath(locator);
}
public static void scrollToBottom() {
((JavascriptExecutor) WebTests.driver).executeScript(
"window.scrollTo(0, document.body.scrollHeight)");
}
public static boolean urlContains(int pageNumber) {
return WebTests.driver.getCurrentUrl().contains("page=" + pageNumber);
}
}
Any method that needs the driver accesses it from the WebTests class with WebTests.driver.
This is good, right?
Nope, it is not good at all.
What is wrong with having a static driver in the test class?
Since the driver is static, this variable is going to be shared by all tests.
This will create problems when you run your tests, not sequentially but in parallel.
Also, using a static driver goes against one of the Selenium group’s good practices:
Although mentioned in several places, it is worth mentioning again. We must ensure that the tests are isolated from one another.
Also,
Create a new WebDriver instance per test. This helps ensure test isolation and makes parallelization simpler.
Using a static driver makes tests dependent and it will complicate parallelization a lot.
What should you do then?
No static driver.
See the end of the previous post for how your code should look like.