WebDriverWrapper is a Selenium Webdriver Wrapper helps to build robust & adaptive test automation project in a fast pace. It contains:
- WebDriverWrapper: A Webdriver Factory lets you easily create webdrivers with different capabilities.
- Operation: A high-level abstraction of basic webdriver methods makes you manipulate and interact with DOM elements in a convenient and robust way.
- BasePage: Adopt the concept of Page-Object to implement your automation project, and it has Operation object as a member variable, so dealing with DOM elements in this Page-Object is a piece of cake.
- Utility Tools: Some tools you could find it helpful when you're writing your automation project. Like dealing with String, Number, Files and so on.
To get a Git project into your build:
Take Gradle for example. Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.deersheep330:WebDriverWrapper:-SNAPSHOT'
}
- Get WebDriverWrapper instance
WebDriverWrapper is a singleton.
WebDriverWrapper wrapper = WebDriverWrapper.getInstance();
- Get Chrome driver runs on your local machine
WebDriverWrapper has built-in Chrome driver.
WebDriver driver = wrapper.getWebDriver("Chrome");
- Get Chrome Mobile Emulation driver runs on your local machine
WebDriverWrapper has built-in ChromeMobileEmulation driver.
WebDriver driver = wrapper.getWebDriver("ChromeMobileEmulation");
- Get IE driver runs on your local machine
WebDriverWrapper has built-in IE driver.
WebDriver driver = wrapper.getWebDriver("IE");
- Get a customized driver runs on your local machine
If you'd like to create your own customized driver, you can implement the WebDriverSettingAbility interface, and override the getCapabilities() method to setup the capabilities (options) you want, and override the getName() method to specify a name to this customized driver so you can create this driver by this name later.
wrapper.addWebDriverSetting(new WebDriverSettingAbility() {
@Override
public Capabilities getCapabilities() {
SafariOptions options = new SafariOptions();
options.setCapability("your_custom_setting", yourCustomSetting);
return options;
}
@Override
public String getName() {
return "CustomSafari";
}
});
WebDriver driver = wrapper.getWebDriver("CustomSafari");
- Get a (remote) driver runs on a remote node
The { node-name: node-address } mappings should be added into WebDriverWrapper so it can create the remote driver for you.
wrapper.addRemoteNode("remote-safari-on-mac", "http://192.168.30.40:4040/wd/hub");
wrapper.addRemoteNode("remote-chrome-on-win", "http://50.60.70.80:4040/wd/hub");
WebDriver remoteSafariDriver = wrapper.getWebDriver("CustomSafari", "remote-safari-on-mac");
WebDriver remoteChromeDriver = wrapper.getWebDriver("Chrome", "remote-chrome-on-win");
- Get a driver using BrowserMob to intercept http requests and running on your local machine
For more details about BrowserMob, please visit its github. Currently, WebDriverWrapper only create BrowserMob driver running on a local machine, if you know how to setup BrowserMob so it can run on a remote node, please kindly let me know :)
WebDriver driver = wrapper.getHttpRequestsInterceptionChromeDriver();
- Create a new Operation object
You can explicitly create an Operation object, but actually it's not necessary. If you let your page object extend BasePage, it already has Operation member variable built-in.
Explicitly create a new Operation:
Operation op = new Operation(driver);
Or just extends BasePage:
public abstract class BasePage {
protected Operation op;
public BasePage(WebDriver driver) {
this.op = new Operation(driver);
}
}
public class MainPage extends BasePage {
// ......
}
- Use methods provided by Operation
To use methods provided by Operation, you should wrap the DOM elements you'd like to interact with into an Element object. Element class has only 2 fields: the identifier (name) and the Xpath of this DOM element.
public class Element {
...
public Element(String name, String xpath) {
this.name = name;
this.xpath = xpath;
}
...
}
It could be convenient to store all the Elements you will use into a HashMap.
Map<String, Element> elements = new HashMap<>();
elements.put(elementName, new Element(elementName, elementXpath)));
Also, BasePage has built-in map to store Elements and provide methods to easily set/access Elements in this map.
public abstract class BasePage {
...
protected Map<String, Element> elements = new HashMap<>();
protected void addElement(String name, String xpath) {
elements.put(name, new Element(name, xpath));
}
protected Element getElement(String name) { return elements.get(name); }
...
}
Examples below assume your page objects extend BasePage so you can use the Operation object and Element-related methods provided by it.
- Click an element
Click an element. If the element isn't clickable because it's not present, it would retry several times. If the element still not present so not clickable, an exception would be thrown.
op.click(getElement("MyButton"));
- Click an element and wait for another element
Click an element and expect another element to be displayed, if the expected element isn't present, it would retry several times. If the expected element still not present, an exception would be thrown.
op.clickAndWait(getElement("MyButton"), getElement("TriggeredElement"));
- Click an element with offset and wait for another element
Click an element with offset and expect another element to be displayed, if the expected element isn't present, it would retry several times. If the expected element still not present, an exception would be thrown. It could be useful if you're dealing with SVG elements.
op.clickWithOffsetAndWait(getElement("MySvgElement"), 10, 30, getElement("TriggeredSvgElement"));
- Hover an element and wait for another element
Hover an element and expect another element to be displayed, if the expected element isn't present, it would retry several times. If the expected element still not present, an exception would be thrown.
op.hoverAndWait(getElement("MyText"), getElement("TriggeredTooltip"));
- Hover an element with offset and wait for another element
Hover an element with offset and expect another element to be displayed, if the expected element isn't present, it would retry several times. If the expected element still not present, an exception would be thrown. It could be useful if you're dealing with SVG elements.
op.hoverWithOffsetAndWait(getElement("MySvgElement"), 10, 30, getElement("TriggeredSvgElement"));
- Test if an element is present or not
Test if an element is present or not for a certain timeout. Which means if the target element not found, it would retry several times before return.
boolean found = op.tryToFind(getElement("GDPRModal"));
Test of an element is present or not. This method would return immediately.
boolean found = op.isExist(getElement("GDPRModal"));
- Wait for an element
Wait for an element being present, if it's not present, an exception would be thrown.
op.waitFor(getElement("GDPRModal"));
- Send text to an input box or textarea
op.sendText(getElement("MyInput"));
- BasePage is the parent page object for other page objects to extend
It has Operation object as a member variable, HashMap for storing web elements, and convenient methods to set/get elements in the HashMap.
public abstract class BasePage {
protected WebDriver driver;
protected Operation op;
protected Map<String, Element> elements = new HashMap<>();
protected String url;
public BasePage(WebDriver driver) {
this.driver = driver;
this.op = new Operation(this.driver);
}
protected void addElement(String name, String xpath) {
elements.put(name, new Element(name, xpath));
}
protected Element getElement(String name) { return elements.get(name); }
public void navigate() {
if (url == null) throw new RuntimeException("url is null! please set it in constructor or using setUrl method.");
op.navigateTo(url);
}
...
}
- Implement your own page object by extending BasePage
public class LoginPage extends Basepage {
LoginPage(WebDriver driver) {
super(driver);
url = "http://my-site.com/login";
addElement("LoginButton", "xpath-for-login-button");
addElement("LoginForm", "xpath-for-login-form");
addElement("EmailInput", "xpath-for-email-input");
addElement("PasswordInput", "xpath-for-password-input");
addElement("Submit", "xpath-for-submit");
}
public void login(String email, String password) {
op.clickAndWait(getElement("LoginButton"), getElement("LoginForm"));
op.sendText(getElement("EmailInput"), email);
op.sendText(getElement("PasswordInput"), password);
op.click(getElement("Submit"));
}
}
API | Description |
---|---|
getInstance | Get WebDriverWrapper singleton |
setPageLoadTimeoutInSec | Change webdriver page load timeout. It's 60 sec by default. |
addWebDriverSetting | Add a customized webdriver setting to create a customized webdriver later |
addRemoteNode | Add a remote node setting into the WebDriverWrapper to create a remote webdriver for this remote node later |
getCurrentActiveWebDriverSettingList | Get the list of WebDriverSettings in this WebDriverWrapper |
getCurrentActiveRemoteNodeList | Get the list of remote nodes in this WebDriverWrapper |
getWebDriver(String webDriverSettingName, String remoteNodeName) | Get RemoteWebDriver for the specific setting and connect to the remote node |
getWebDriver(String webDriverSettingName) | Get WebDriver runs on local machine without standalone selenium server |
getHttpRequestsInterceptionChromeDriver | Use BrowserMob to intercept http requests so we can get details of the headers/payloads of every requests. Only work when browser = Chrome and Machine = Local |
- Check browser type
API | Description |
---|---|
isIE | Test current webdriver is an IEDriver or not |
- Change default setting
API | Description |
---|---|
setTargetElementWaitTimeoutInSec | Set target element wait timeout |
setWaitForElementWaitTimeoutInSec | Set waitFor element wait timeout |
- "Click and hold" method group
API | Description |
---|---|
clickAndHold | Click and hold "target" element and no need to wait for anything |
clickAndHoldWithOffset | Click and hold "target" element with offset and no need to wait for anything |
clickAndHoldAndWait | Click and hold "target" element and wait for "waitFor" element |
clickAndHoldWithOffsetAndWait | Click and hold "target" element with offset and wait for "waitFor" element |
clickAndHoldAndWait | Click and hold "target" element and wait for "waitFor" element with customized timeout |
clickAndHoldWithOffsetAndWait | Click and hold "target" element with offset and wait for "waitFor" element with customized timeout |
release | Release "target" element after "click and hold" |
- "Hover" method group
API | Description |
---|---|
hover | Hover "target" element and no need to wait for anything |
hoverWithOffset | Hover "target" element with offset and no need to wait for anything |
hoverAndWait | Hover "target" element and wait for "waitFor" element |
hoverWithOffsetAndWait | Hover "target" element with offset and wait for "waitFor" element |
hoverAndWait | Hover "target" element and wait for "waitFor" element with customized timeout |
hoverWithOffsetAndWait | Hover "target" element with offset and wait for "waitFor" element with customized timeout |
- "Right click" method group
API | Description |
---|---|
contextClick | Right click "target" element and no need to wait for anything |
contextClickWithOffset | Right click "target" element with offset and no need to wait for anything |
contextClickAndWait | Right click "target" element and wait for "waitFor" element |
contextClickWithOffsetAndWait | Right click "target" element with offset and wait for "waitFor" element |
contextClickAndWait | Right click "target" element and wait for "waitFor" element with customized timeout |
contextClickWithOffsetAndWait | Right click "target" element with offset and wait for "waitFor" element with customized timeout |
- "Click" method group
API | Description |
---|---|
click | Click "target" element and no need to wait for anything |
clickWithOffset | Click "target" element with offset and no need to wait for anything |
clickAndWait | Click "target" element and wait for "waitFor" element |
clickWithOffsetAndWait | Click "target" element with offset and wait for "waitFor" element |
clickAndWait | Click "target" element and wait for "waitFor" element with customized timeout |
clickWithOffsetAndWait | Click "target" element with offset and wait for "waitFor" element with customized timeout |
clickAndWaitUntilDisappear | Click "target" element and wait for "waitFor" element disappearing |
clickWithOffsetAndWaitUntilDisappear | Click "target" element with offset and wait for "waitFor" element disappearing |
clickAndWaitUntilDisappear | Click "target" element and wait for "waitFor" element disappearing with customized timeout |
clickWithOffsetAndWaitUntilDisappear | Click "target" element with offset and wait for "waitFor" element disappearing with customized timeout |
- Check for existence
API | Description |
---|---|
isExist | Check "target" element is displayed or not |
tryToFind | Test "target" element is exist or not. If "target" is exist, return true, else if "target" isn't exist, return false. No exception would be thrown |
waitFor | Wait for "waitFor" element. If it's not found after timeout, an exception would be thrown |
- Get WebElement(s)
API | Description |
---|---|
findElement | Get single WebElement |
findElements | Get list of WebElements |
- Send text or select
API | Description |
---|---|
sendText | Send text to InputBox or TextArea |
dragAndDropFile | Drag and drop a file into a FileArea |
selectDropdownMenuOptionByValue | Select dropdown menu option by value |
- WebDriver navigation or reload
API | Description |
---|---|
navigateTo | Webdriver navigate to url |
reloadPage | Webdriver reload page |
- Tab-related operations
API | Description |
---|---|
IsNewTabBeingOpened | Check if a new tab being opened |
switchToFirstNewlyOpenedTab | Switch to the first newly opened tab |
closeNewlyOpenedTabs | close newly opened tab |
getCurrentUrl | get current url |
getCurrentOpenedTabsCount | Get current opened tabs count |
getCurrentOpenedTabsSet | Get current opened tabs handles |
switchToTab | Switch to another tab according to handle |
saveCurrentTabAsDefaultTab | Save current tab as default tab |
getDefaultTabHandle | Get default tab handle |
- Click alert
API | Description |
---|---|
clickAlertOK | Click alert OK |
- Iframe-related operations
API | Description |
---|---|
switchToIframe | Switch to Iframe |
switchFromIframeToMainHTML | Switch back from Iframe to main content |
- Scroll-related operations
API | Description |
---|---|
scrollWindowTo | Scroll window to the specified offset |
scrollToElement | Scroll to element (align start) |
scrollToElementAlignCenter | Scroll to element (align center) |
- Webdriver quit
API | Description |
---|---|
quitAndCloseBrowser | Call driver.quit() to close browser |
- LoggingPrefs-related operations
API | Description |
---|---|
getResponseFromLoggingPrefs | Get response of a specific request url according to keywords. Only works for Chrome driver with loggingPrefs enabled |
searchForRequestUrlFromLoggingPrefs | Search for request url according to keywords. Only works for Chrome driver with loggingPrefs enabled |
getAllRequestUrlsFromLoggingPrefs | Get all request urls from logs. |
resetLoggingPrefs | Reset loggingPrefs. All old logs would be discard. |
enableSaveCookieFromLoggingPrefs | Save cookie in Operation instance. Only works for Chrome driver with loggingPrefs enabled |
saveSpecialHeader | Save specific header in Operation instance. Only works for Chrome driver with loggingPrefs enabled |
- Thread.sleep
API | Description |
---|---|
sleep | Sleep for millis |
- WebDriver screenshot
API | Description |
---|---|
screenshot | Screenshot |
screenshotAndEmbedInCucumberReport | Screenshot and embed in Cucumber report |
API | Description |
---|---|
addElement | Store the element in the HashMap of BasePage |
getElement | Get the element from the HashMap |
setUrl | Set url for this page |
getUrl | Get url for this page |
navigate | Navigate to url |
getOperation | Get Operation instance |
- Number-related functions
API | Description |
---|---|
NumberTool.findIntFromString | Find integer from string |
NumberTool.parseIntFromString | Parse integer from string |
- String-related functions
API | Description |
---|---|
StringTool.replaceTextInFile | Replace all specific text in a file |
- XLSX-related functions
API | Description |
---|---|
XlsxTool.getWorkbookFromHttpURLConnection | Get Xlsx Workbook from HttpUrlConnection |
XlsxTool.getDefaultSheetFromWorkbook | Get default sheet from workbook |
XlsxTool.getRowCountOfSheet | Get row count of sheet |
TODO