A library to run selenium tests from TestNG.
- Run tests in parallel
- Run tests local / against a selenium grid / browserstack
- Create a test report with screenshots and logs
- Publish results to browserstack
- Access localhost from browserstack
- mobile emulation
Create a new mvn project and the following to your pom.xml
<project>
<!-- load webtest dependency from github-->
<repositories>
<repository>
<id>github-public</id>
<url>https://public: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@maven.pkg.github.com/it-ony/webtest
</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.onfido.qa.webdriver</groupId>
<artifactId>webtest</artifactId>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Create your first test class in the src/test/java
directory named <MyTest>IT.java
.
public class GithubIT extends WebTest {
public class FooIT extends WebTest {
@Test()
public void testGithubCodeSearch() {
driver().get("https://github.com/");
verifyPage(GithubMainPage.class)
.search("it-ony/webtest")
.clickFirstResult();
}
}
}
and create the PageObjects that we want to use. The PageObject needs to extend from Page and can
overwrite the verifyPage
method. By doing we can make sure that we landed on the correct page.
public static class GithubMainPage extends Page {
public static final By SEARCH = By.cssSelector(".header-search-input");
public GithubMainPage(Driver driver) {
super(driver);
}
public GithubSearchPage search(String searchTerm) {
driver.waitFor.clickable(SEARCH).sendKeys(searchTerm + Keys.ENTER);
return new GithubSearchPage(driver);
}
@Override
protected void verifyPage(Driver driver) {
super.verifyPage(driver);
driver.waitFor.visibility(SEARCH);
}
}
public static class GithubSearchPage extends Page {
public static final By CODE_SEARCH_RESULTS = By.cssSelector(".codesearch-results");
public GithubSearchPage(Driver driver) {
super(driver);
}
@Override
protected void verifyPage(Driver driver) {
super.verifyPage(driver);
driver.waitFor.visibility(CODE_SEARCH_RESULTS);
}
public void clickFirstResult() {
driver.waitFor.clickable(new ByChained(CODE_SEARCH_RESULTS, By.cssSelector("li a"))).click();
}
}
From the above examples you see that clicking an element or even typing in a search field should be done in conjunction of waiting for the element to be clickable. By doing so, we make sure that the element is on the page displayed and can be interacted with.
Webtest comes with the ability to load properties from properties files in the resource folder. Properties
can either be set with the -Dmyproperty=myvalue
syntax of mvn or via the property files.
The resource folder is scanned and properties are taken in the following order:
- local
- ENVIRONMENT-REGION
- REGION
- ENVIRONMENT
- common
where ENVIRONMENT
and REGION
are based on the system properties named environment
and region
.
By default the environment is DEV
and region is EU
.
A best practice for local testing is to create a local.properties
file and put the local test
properties into it.
Properties support a templating syntax, e.g. you can put into your common.properties
host=defaulthost.com
url=https://${host}/some/resource
apiEndpoint=https://${host}/api/v2
and instead of repeating yourself you can simply overwrite the url
and apiEndpoint
by setting the
url
in your local.properties file to e.g. localhost:8080
. url
will be for the test run then
https://localhost:8081/some/resource
and apiEndpoint
will be https://localhost:8081/api/v2
.
The browser can be either chooses with the property browser
. A fallback to chrome
is given by the framework.
The version is set by browserVersion
property and the platform can be specified by setting the platform
property
to a valid value.
As an alternative way all the values can be overwritten with the @Browser
annotation on a method or the test class.
For debugging tests and developing test code running code locally is key. You can see and inspect the web app while stepping through the test code. Right now you can run tests against Firefox and Chrome locally.
To run local a property local=true
needs to be specified. For Chrome you need to install a
chromedriver that matches your chrome version. For Firefox you need
geckodriver
For chrome you need to define the path to chromedriver either via the browserPath
or webdriver.chrome.driver
property. If not defined it tries to find the driver executable in your path.
You can run your tests a selenium grid by defining a property named gridUrl
. The property local
needs
to be false
.
Browserstack is a selenium grid hosting company. Webtest is prepared for browserstack.
Just define browserstack.username
and browserstack.accessKey
as system properties or BROWSERSTACK_USERNAME
and
BROWSERSTACK_ACCESS_KEY
as environment variables.
If you need to your local system from browserstack set the property browserstack.local=true
and it will create a tunnel
between browserstack and your system executing the tests.
The BrowserStackListener
takes care of setting the test results. To make use of it annotate your test class
@Listeners({BrowserStackListener.class})
public class MyTestIT extends WebTest {
...
}
Extend your pom.xml with the maven-failsafe-plugin
<project>
<properties>
<threadCount>5</threadCount>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<properties>
<property>
<name>configfailurepolicy</name>
<value>continue</value>
</property>
</properties>
<parallel>methods</parallel>
<threadCount>${threadCount}</threadCount>
<forkCount>0</forkCount>
</configuration>
</plugin>
</plugins>
</build>
</project>
Then execute
mvn -DthreadCount=10 -Dbrowser=chrome clean verify
You can set properties with the -D
option. Those are taken with priority to the ones defined in your property files.
To ease debugging and running tests most IDEs can execute test methods directly from the IDE. Give Intellij Idea a try if you like.
Webtest comes with Screenshot listener giving you details for failed tests. Annotate your testng tests to include the
ScreenshotListener
and find your reports under the target directory after the test run.
@Listeners({ScreenshotListener.class})
public class MyTestIT extends WebTest {
...
}
To emulate a mobile device use the @Mobile
annotation. You can define the width
and height
of the screen as well as the
pixelRatio
. You can disallow emulation by setting allowEmulation=false
and define the device
and the `osVersion.
Mobile emulation is only available on chrome (and most likely on edge).
A best practice is to run your tests against local and testing them before the commit against a remote grid that your CI system is testing against. You can do this easily by having different property files for the environments.
In your local.properties
file only put
environment=_local
#environment=_remote
Create a _local.properties
local=true
and a _remote.properties
file
local=false
browserstack.username=
browserstack.accessKey=
browserstack.local=true
and set your properties. You can easily toggle now between the environments by setting the desired environment in the local.properties
file.