Skip to content

Testing

Rick Brown edited this page Mar 30, 2020 · 24 revisions

WComponents endeavors to provide first class support for automated testing. If you encounter any obstacles please report an issue.

Selenium

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.

Quick Start

Extending WComponentSeleniumTestCase

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

Manual implementation

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);
}
// ...
}

Configuration

The full list of configuration properties are available here.

Utilities

WebDriverCache

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

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

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

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.

WComponent Element Wrappers

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.

In-JVM Utilities

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.

ByWComponent | ByWComponentPath

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

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

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

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.

JUnit convenience classes

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

WComponentSeleniumTestCase is an abstract class for Selenium testing - extending this class is the easiest way to test WComponents with Selenium.

Constructors

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).

Property Configuration

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.

WebDriver

The method getDriver() will create, launch and cache the configured driver automatically. The session will automatically be reset between tests.

MultiBrowserRunner

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.

WebDriverManager

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.

WebDriverManager Configure a Mirror

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.

WebDriverManager Configure a Proxy

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

Other Tools

Page Ready

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).

DOM

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".

JavaScript

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);
    });
});

Finding Elements

By ID

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).

Testing JavaScript

The JavaScript in wcomponents-theme is tested by the Intern. How to do it is detailed in Theme testing.

Further information

Clone this wiki locally