Skip to content

Testing

Josh edited this page Jul 22, 2016 · 24 revisions

Automated testing

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 indepedently, 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 contructor will use a PhantomJSWebDriver 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.
    WComponentWebDriver 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 = WComponentSeleniumUtil.getDialog(driver);
    String title = dialog.getHeadingText();
    Assert.assertEquals("Dialog title does not match.", "MyTitle", title);
}

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.

WComponentSeleniumUtil

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

WComponentWebDriver

WComponentWebDriver 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. PhantomJS 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.

Other Tools

Page Ready

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

JS

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

Clone this wiki locally