-
Notifications
You must be signed in to change notification settings - Fork 17
Testing
WComponents endeavors to provide first class support for automated testing. If you encounter any obstacles please report an issue.
- Selenium
- Other Tools
- Finding Elements
- Testing JavaScript
- Further information
The Selenium testing framework is made up of a few separate utility classes that can be used independently, and a few JUnit convenience classes that tie everything together. Either option can be used depending on the application's needs.
Extending from WComponentSeleniumTestCase
is the easiest way to write a Selenium test. The default constructor will use a FirefoxWebDriver
and will launch an LDE using the PlainLauncher
configuration. All you need to do is call getDriver();
to access the Selenium WebDriver
which will be created, launched, cached and shutdown automatically.
public class MyText extends WComponentSeleniumTestCase {
@Test
public void testSomething() {
// Will create/launch/cache the WebDriver, and track it for shutdown at
// the end of the test.
getDriver().findElement(By.id("my_button_id")).click();
//Framework will automatically wait for page to load an AJAX to finish
Assert.assertFalse("Button should be disabled.",
By.id("my_button_id")).isEnabled());
}
}
You can change which component is launched by setting bordertech.wcomponents.lde.component.to.launch
.
You can change which driver to use by calling a non-default constructor:
super(new ChromeWebDriverType());
You can also change the driver by setting the ParameterizedWebDriverType
property: bordertech.wcomponents.test.selenium.webdriver=org.openqa.selenium.chrome
You can point to an external server by setting launchServer
and the serverUrl
:
bordertech.wcomponents.test.selenium.launchServer=false
bordertech.wcomponents.test.selenium.serverUrl=https://dev.local:8080/app
If you cannot, or do not want to, extend WComponentSeleniumTestCase
, then you can still call all the utility functions.
public class MyTest extends MyAbstractTestClass {
@Test
public void someTest() {
// Will create/launch/cache the WebDriver, and track it for shutdown at
// the end of the test.
SeleniumWComponentsWebDriver driver =
WebDriverCache.getDriver(new ChromeWebDriverType());
// Fetch the page, will automatically wait for the page to be ready
driver.get("http://localhost:8080/app");
// Fetch the dialog, will automatically wait for the page to be ready
SeleniumWDialogWebElement dialog =
SeleniumWComponentsUtil.getDialog(driver);
String title = dialog.getHeadingText();
Assert.assertEquals("Dialog title does not match.", "MyTitle", title);
}
// ...
}
The full list of configuration properties are available here.
WebDriverCache
is a convenience class that can be used to create/cache/destroy Selenium WebDriver instances. This cache will ensure that the very heavy start-up cost of drivers is minimized when running multiple tests, and will also handle safe multi-threaded behaviour.
ParameterizedWebDriverType
can be used by tests to determine the WebDriver
implementation at runtime using Configuration
properties. This enables tests to conveniently switch browser types.
SeleniumWComponentsUtil
is a static utility class that provides the implementation of all special WComponents functions, such as the wait condition for the page to be ready.
SeleniumWComponentsWebDriver implements the Selenium WebDriver
interface and wraps the actual driver implementation. The class exposes some custom WComponents functions as well as ensuring the WComponent page has actually loaded between actions.
There are a number of wrapper classes for Selenium WebElement
to wrap WComponent functionality. For example, SeleniumWTableWebElement
provides an API to access pagination controls, cell content, table headers etc. The library of WebElement
wrappers will continue to grow and can be found in the package com.github.bordertech.wcomponents.test.selenium.element
.
The below components are supplied to speed-up development of Selenium tests, but they should be avoided if possible. Using these components requires the test class and the server (LDE) to run in the same JVM. As such using these components will prevent the test from being run against non-dev environments.
These classes are WComponent specific implementations of Selenium's By
interface to search for element. These classes require the LdeLauncher
to be a subclass of SeleniumLauncher
SeleniumLauncher
is an LdeLauncher
subclass of PlainLauncher
that keeps track of the UIContext so that ByWComponent
and ByWcomponentPath
can be used to find elements.
DynamicLauncher
is an LdeLauncher
subclass of SeleniumLauncher
that can dynamically set the launched component at runtime using setComponentToLaunch();
. This launcher is useful if you want to test different sub-components in a test suite without re-launching the server.
ServerCache
is a caching utility class that will launch the LDE server and keep it running between tests. This works like WebDriverCache
to ensure the significant start-up delay only occurs once. Ideally all tests will use the ServerCache
when running in LDE mode, but will defer to an external server if configured to point to a URL. See WComponentSeleniumTestCase
for an example of how this could work.
There are a few JUnit specific classes that bring all the Selenium components together to simplify the testing process. These components can be used for JUnit tests, or otherwise can be used as an example of how to do it.
WComponentSeleniumTestCase
is an abstract class for Selenium testing - extending this class is the easiest way to test WComponents with Selenium.
The parameterized constructors can be used to define a particular driver instance (e.g. Firefox or Chrome), and optionally a target URL (for an already running server).
The boolean property bordertech.wcomponents.test.selenium.launchServer
is used to determine whether to launch a new LDE at start-up, while the String property bordertech.wcomponents.test.selenium.serverUrl
can be used to point to an existing server.
The method getDriver()
will create, launch and cache the configured driver automatically. The session will automatically be reset between tests.
MultiBrowserRunner
is a custom JUnit test runner that will execute the test multiple times for each WebDriver
defined in the property bordertech.wcomponents.test.selenium.driverTypes
. The property bordertech.wcomponents.test.selenium.runParallel
can be set to run the different driver tests in parallel. The WebDriverCache
used by the MultiBrowserRunner
will ensure thread-safe behaviour between threads.
Since v1.5.17 WComponents uses WebDriverManager to automate the download, caching and configuration of Selenium WebDriver binaries. This greatly simplifies setup, however in corporate environments without a direct line of sight to the internet there is some configuration necessary. WebDriverManager supports configuration via its API, commandline arguments or environment variables, as described here: https://github.com/bonigarcia/webdrivermanager The examples below show environment variable usage.
Without a clear line of sight to the internet you will need to configure either a proxy or an on-prem webdriver mirror, discussed below.
Assuming your mirror is hosted on Nexus Repository Manager raw repositories you will need to configure minimum TWO options to get an on-prem mirror working:
WDM_CHROMEDRIVERMIRRORURL=http://nexus.example.com/service/rest/repository/browse/MY_RAW/chromedriver/
WDM_VERSIONPROPERTIESURL=http://nexus.example.com/repository/MY_RAW/webdrivermanager/versions.properties
Note that versions.properties
will need to be kept up to date.
At the time of writing WebDriverManager can not handle Nexus mirrors, but it shouldn't be long.
As an alternative to the use of a mirror, WebDriverManager can be configured to use an HTTP proxy including support for NTLM authentication. For example your proxy configuration may look like this: domain\username:[email protected]:1234
More details found here: https://github.com/bonigarcia/webdrivermanager
The JavaScript module wc/a8n provides both a javascript and pure DOM "hook" to determine if the page is "ready".
Ready means:
- The DOM is ready.
- Initialization scripts have run.
- There is no pending AJAX.
- There are no pending timeouts (
window.setTimeout
).
The body
element has an attribute data-wc-domready
which will be false
if the DOM is potentially pending an update and true
when there are no pending updates.
This attribute will always exist (it will never be removed) and will always be either "true" or "false".
The automation module provides a subscribe
method which can be used to register a function that will be called with a boolean, true
if the DOM is "ready" or false
if the DOM is potentially pending an update.
Example:
require(["wc/a8n"], function(a8n) {
a8n.subscribe(function(isReady) {
console.log("isReady:", isReady);
});
});
Static IDs are optional in WComponents but they make certain types of automated testing much easier. Ensure that application developers take the time to set meaningful IDs for WComponents widgets. This is especially important for form controls (as opposed to layout widgets).
The JavaScript in wcomponents-theme is tested by the Intern. How to do it is detailed in Theme testing.