Skip to content

Hybridity And View Management

hekra01 edited this page Jan 12, 2017 · 9 revisions

QtWebDriver can drive UIs based on:

  • QWebViews.
  • QWidgets views.
  • QDeclarativeViews.
  • QGraphicsWebViews.
  • Hybrids of the these. (QWeb/DeclarativeViews embedded in QWidgets, etc...)

Navigation Principles & View Transitions

When navigating to an URL WebDriver will do the following checks:

  • If the current view is compatible with the requested content then use it.
  • Otherwise apply the view transition policy to the current view.
  • Then create a view of a type that is compatible with the requested content.

View Creation Policy

Views can be created either at session startup or when transitioning between content.

View Creation at session startup

The class of the View to create at session startup can be specified:

  • On client side, use the Selenium browserClass capability to specificy the class to create:
capabilities.setCapability("browserClass", "MyWebView");
driver = new RemoteWebDriver(ip:port, capabilities);
etc...
  • On server side, register the class to create, or one of its subclasses must have been registered to WebDriver.
    e.g:
//Configure web support
webdriver::ViewCreator* webCreator = new webdriver::QWebViewCreator();
//Register custom web view subclass
webCreator->RegisterViewClass<QWebViewExt>("MyWebView");

When creating a session with such capabilities QtWebDriver will try to create an instance of MyWebView or one of its subclasses.

View creation at Transition Time

When QtWebDriver detects the requested content (as in WebDriver.get(URL content)) cannot be displayed by the current view (as in WebDriver.getWindowHandle()), then it will:

  • apply the configured transition policy
    e.g: to close all previous views
webdriver::ViewTransitionManager::SetURLTransitionAction(new webdriver::URLTransitionAction_CloseOldView());
  • attempt to create a view that can manage the requested content:
QtWebDriver wd = new QtWebKitDriver(host, caps);

// This will trigger creation of a QWebView
wd.get("http://html5test.com/");
...
// This will trigger creation of a QDeclarativeView
wd.get("http://qmltest.com/foo.qml");
...
// This will trigger creation of a MyWidgetClass
wd.get("qtwidget://MyWidgetClass");
//etc...

See Headers.h for an example to configure QtWebDriver.
See Doxygen

Native UIs

HTML Widget QML
Compatible views QWebViews QWidgets QDeclarativeViews
Supported URL scheme
  • html://
  • file://
  • etc...
qtwidget://<widget class> any qml file URL
UI source
<!DOCTYPE html>
<html>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
</body>
</html>
<MainWindow name="WD_native">
<QLineEdit id="InputText"/>
<QPushButton id="PushButton"/>
<QPushButton id="PushButton2"/>
<QWidget id="Frame">
<QPushButton id="FrameButton"/>
<QPushButton id="FrameButton2"/>
</QWidget>
</MainWindow>
<QDeclarativeView>
<Rectangle id="theRectangle"/>
<Rectangle id="theRectangle2"/>
</QDeclarativeView>
Locator strategies
  • id
  • linkText
  • partialLinkText
  • name
  • tagName
  • className
  • cssSelector
  • xpath
  • id
  • name
  • tagName
  • className
  • xpath
*: "id" attribute can be set by using QWidget.setObjectName.
  • id
  • tagName
  • className
  • xpath*
*: "id" attribute can be set by defining "objectName" in QML.
Javascript Injection Y, as specified by W3C spec N/A Partial, as permitted in QML

Hybrid UIs

Hybrid UI are made of different type of content. e.g: html inside widget, QML inside widget, etc...

hybrid UI In the hybrid UI above (a WebView and andother menu widgets), WebDriver will consider there are 2 document roots (cf http://www.w3.org/TR/webdriver/#defining-window-and-frame):

The "source" for this type of UI would look like this:

<!- Main window, a window handle -> 
<MainWindow name="WD_native" elementId=":qtw:5bc59415"> 
  <QLineEdit id="InputText" elementId=":qtw:7c5c413e"/> 
  <QPushButton id="PushButton" elementId=":qtw:002e6aa8"/> 
  <QPushButton id="PushButton2" elementId=":qtw:68a743bf"/> 
  <QWidget id="Frame" elementId=":qtw:155c2ecd"> 
    <QPushButton id="FrameButton" elementId=":qtw:5067ef6e"/> 
    <QPushButton id="FrameButton2" elementId=":qtw:3e34e310"/> 
  </QWidget> 
 
  <!- Embedded web window, another window handle -> 
  <QWebView elementId=":qtw:5135c3c1"/> 
</MainWindow>

Handles to the windows roots will be returned by org.openqa.selenium.WebDriver.getWindowHandles().

In this case it will return:

  • 1 handle for the main window
  • 1 handle for the web view

Each window can be navigated to with WebDriver.switchTo().window(handle), then WebDriver will work relatively to the focused window.
e.g:

public class Test extends TestCase {
    QtWebKitDriver driver;
    String webDriverUrl = "http://192.168.0.2:9517";
 
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        DesiredCapabilities capability = new DesiredCapabilities();
 
        //Start WebDriver by reusing existing widget UI
        capability.setCapability("browserStartWindow", "*");
        driver = new RemoteWebDriver(new URL(webDriverUrl), capability);
    }
 
    public void test() throws InterruptedException, IOException {
        //First the current window is the browser window (i.e: widget root)
        String rootWindowHandle = driver.getWindowHandle();
        System.out.println("Browser window handle is " + rootWindowHandle);
 
        //Assert there are 2 windows, one for the widget root, one for the web documents in each tab
        Set<String> windowHandles = driver.getWindowHandles();
        assertTrue(windowHandles.size() == 2);
 
        //Select http
        String httpHandle = selectWindow("http");
        assertNotNull(httpHandle);
 
        //Then navigate html as usual
        WebElement elt = driver.findElement(By.xpath("//html/body"));
    }
 
    private String selectWindow(String protocol) {
        Set<String> windowHandles = driver.getWindowHandles();
 
        for (Iterator<String> iterator = windowHandles.iterator(); iterator.hasNext();) {
            String w = iterator.next();
            driver.switchTo().window(w);
            if (driver.getCurrentUrl().startsWith(protocol))
                return w;
        }
        return null;
    }
}

View Support matrix

Qt4 Qt5
QWidget Y Y
QWebView Y Y
QDeclarativeView Y Y
QDeclarativeWebView Y N (see note 1)
QGraphicsWebView Y Y
note 1: Support of webview in Quick2 requires suport for multiprocess web views available in Webkit2 or QWebEngine. This feature will be provided when QWebEngine is available