Skip to content
This repository has been archived by the owner on May 7, 2018. It is now read-only.

Selenium WebDriver testing support for qooxdoo desktop applications in .NET platform

License

Notifications You must be signed in to change notification settings

tfreitasleal/QxWebDriver-NET

Repository files navigation

QxWebDriver-NET

NuGet

WebDriver test automation support for qooxdoo desktop and mobile applications.

Version 1.0.8 is available on NuGet as Qooxdoo-WebDriver. This is the last release and is NET 4.5 only.

The SimpleDemo sample uses Chrome, Edge, Firefox and Opera (Internet Explorer isn't planned). It includes test projects for NUnit and MSTest. It also includes an "How to run.txt" to make your life easier.

QxWebDriver-NET is a port of qxwebdriver-java to C#.

This file was adapted from qxwebdriver-java.

Project Status

This project was instrumental for starting Wisej-Selenium.

QxWebDriver-NET is no longer supported. The project was archived (read only) to prevent user interaction (issues, etc). You can still fork it.

I would be happy to unarchive and donate it to someone that can take care of it.

Project Goal

The goal of this project is to provide an API that facilitates writing WebDriver-based interaction tests for qx.Desktop and qx.Mobile applications by abstracting away the implementation details of qooxdoo widgets. Here's a quick example:

QxWebDriver driver = new QxWebDriver(new ChromeDriver());
// Open the page and wait until the qooxdoo application is loaded
driver.Url = "http://www.qooxdoo.org/current/api/index.html";

// Find the 'Search' button in the tool bar
// @label is the button text
By buttonByLabel = By.Qxh("apiviewer.Viewer/*/[@label=Search]");
IWidget buttonWidget = driver.FindWidget(buttonByLabel);

// Click the button if it's not already selected
if (!buttonWidget.Selected)
{
    buttonWidget.Click();
}

// Now click the 'Legend' button
buttonByLabel = By.Qxh("apiviewer.Viewer/*/[@label=Legend]");
buttonWidget = driver.FindWidget(buttonByLabel);
if (!buttonWidget.Selected)
{
    buttonWidget.Click();
}

// Now click the 'Content' button
buttonByLabel = By.Qxh("apiviewer.Viewer/*/[@label=Content]");
buttonWidget = driver.FindWidget(buttonByLabel);
if (!buttonWidget.Selected)
{
    buttonWidget.Click();
}

// Select the "data" item from the package tree
By tree = By.Qxh("apiviewer.Viewer/*/apiviewer.ui.PackageTree");
ISelectable packageTree = (ISelectable) driver.FindWidget(tree);
packageTree.SelectItem("data");

Widget Interfaces

QxWebDriver provides a set of widget classes similar to WebDriver's support classes, each of which implements Qooxdoo.WebDriver.UI.IWidget or one or more of the interfaces inheriting from it, such as ITouchable, ISelectable or IScrollable. These interfaces allow complex actions to be performed by relatively few API calls.

Widgets are obtained by calling QxWebDriver.FindWidget(by). where by is any locator strategy that finds a DOM element which is part of a qooxdoo widget. FindWidget will determine the qooxdoo class of the widget, its inheritance hierarchy and the interfaces it implements, and use this information to decide which IWidget implementation to return.

Similar to IWebElement.FindElement, IWidget.FindWidget will restrict the search to children of the current widget.

Examples

The best way to learn about the various widget interfaces is to check out the sample integration tests in Samples.

Locating Widget Elements

WebDriver's built-in "By" strategies like By.XPath or By.ClassName generally don't work too well with the entangled and dynamic DOM structures generated by qx.Desktop applications. The By.Qxh strategy (Qx for qooxdoo, h for hierarchy) provides an alternative approach that searches for elements by using JavaScript to traverse the application's widget hierarchy.

For example, the qooxdoo Feed Reader's UI hierarchy looks like this (easily determined by opening the Feed Reader in the Inspector):

qx.ui.root.Application
- qx.ui.container.Composite
  - feedreader.view.desktop.Header
  - feedreader.view.desktop.ToolBar
    - qx.ui.toolbar.Button
  [...]

A Qxh locator that finds a toolbar button with the label Reload could look like this:

By by = By.Qxh("child[0]/feedreader.view.desktop.ToolBar/[@label=Reload]");

As you can see, the syntax is similar to XPath, consisting of location steps separated by slashes. While searching, each location step selects a widget which will be used as the root for the rest of the search.

Supported Steps

  • foo.bar.Baz A string containing dots will be interpreted as the class name of a widget. Uses instanceof internally so inheriting widgets will be found as well.

  • child[N] Signifies the Nth child of the object returned by the previous step.

  • [@attrib{=value}] Selects a child that has a property attrib which has a value of value. "Property" here covers both qooxdoo as well as generic JavaScript properties. As for the values, only string comparisons are possible, but you can specify a RegExp which the property value will be matched against. toString() is used to compare non-String values.

  • * is a wildcard operator. The wildcard can span zero to multiple levels of the object hierarchy. This saves you from always specifying absolute locators, e.g. the example above could be rewritten as

    By by = By.Qxh("*/[@label=Reload]");

This will recursively search from the first level below the search root for an object with a label property that matches the regular expression /Reload/. As you might expect, these recursive searches take more time than other searches, so it is good practice to be as specific in your locator as possible.

Note that the Qxh strategy will only return the first match for the locator expression, so it can't be used with WebDriver.FindElements.

Relative Locators

The root node where a By.Qxh locator will begin searching is determined by its context: When used with QxWebDriver.FindWidget, the children of the qooxdoo application's root widget will be matched against the first step. When used with IWidget.FindWidget, the widget itself will be the root node for the search.

Inline Applications

Inline applications extending qx.application.Inline can have multiple root widgets. To locate a child widget, first find the DOM node to which the inline root is attached, then search within it:

WebElement root = driver.FindElement(By.Id("inlineRoot"));
// Within a WebElement, we can't use FindWidget, so we use FindElement...
WebElement buttonEl = root.FindElement(By.Qxh("qx.ui.container.Composite/qx.ui.form.Button"));
// ...and get a IWidget for it
IWidget button = (IWidget) driver.GetWidgetForElement(buttonEl);

Extending QxWebDriver

FindWidget uses a IWidgetFactory to determine which widget class to instantiate. An alternative class implementing IWidgetFactory and probably extending DefaultWidgetFactory can be passed to the QxWebDriver constructor to support custom widgets.

Browser Support

In theory, QxWebDriver should work with any WebDriver that implements IJavascriptExecutor. Drivers for Chrome, Firefox, Edge and Opera do work all right although the Edge driver only supports one running instance. The current Internet Explorer driver is said to work but in practice is too hard to get it working.