The in are a powerful feature, not only with the ability to look up objects, but also to synchronise on them. In 6.4 this became even more flexible with the introduction of the script-based object map. But there are some situations left where the Squish object names don’t fit all the needs. The Squish for Web edition has an lookup mechanism using expressions. Using this is useful in the following circumstances:

  • The users who create the tests already have XPath knowledge.
  • You want to start the object lookup at a certain object and only look at its children.
  • You need to specify more complex relationships between objects than a simple containment.
  • You want to look up not a single object, but all object that match the criterion. This is also possible with Squish’s object names in Squish 6.4 and later by using the findAllObjects() script function.

The evaluateXPath() function on a HTML object in Squish for performs the XPath lookup. It returns a XPath result object on which you can query the number of objects that matched the XPath expression with snapshotLength(). And you can get Squish object references to the matched objects with snapshotItem() and singleNodeValue().

This is a simple example for using this on the Google page to find the text input field, i.e. the INPUT tag that has type attribute with value text. The script starts the search at the FORM object which we look up with a normal Squish object name:

var form = waitForObject(names.googleFFORM);
var result = form.evaluateXPath("//INPUT[@type='text']");
test.compare(result.snapshotLength, 1);
typeText(result.singleNodeValue(), "Squish");
Google search page with different INPUT elements and their types used in the XPath expressions

Types of the INPUT elements on Google search

The normal Squish object name would be more suitable for this particular case, but this is just a simple case for showing how the XPath API in Squish works at all. It gets more interesting if the result contains not only one result object but multiple ones. For this, let’s change the expression to look for object with submit for the type attribute on the Google main page:

var form = waitForObject(names.googleFFORM);
var result = form.evaluateXPath("//INPUT[@type='submit']");
for (var i = 0; i < result.snapshotLength; i++) {
    var o = result.snapshotItem(i)
    test.log("Item " + i + ": " + o.value);
}

This yields two results (the two search buttons). So the test result contains the two log results:

Item 0: Google Search
Item 1: I'm Feeling Lucky

In the above examples we started the lookup always from the FORM object. But if you want to search the whole HTML DOM tree, just use the BODY object as the object to call evaluateXPath() on.

The XPath lookup does not do any synchronisation on the existence of the object. So if you want to use XPath expressions as an alternative to object names, you need an alternative to Squish’s waitForObject() function. So let’s implement a waitForXPathObject() that waits for exactly one matching object and that returns the Squish object for it:

function waitForXPathObject(startObj, xpath, timeout=20*1000)
{
    var result;
    waitFor(function() {
        result = startObj.evaluateXPath(xpath);
        return result.snapshotLength == 1;
    }, timeout);
    test.compare(
        result.snapshotLength, 1,
        'waitForXPathObject: verify that exactly one object was found'
    );
    return result.snapshotItem(0);
}

function main() {
    ...
    var form = waitForObject(names.googleFFORM);
    var result = waitForXPathObject(form, "//INPUT[@type='text']");
    ...
}

This is useful for the case that your expected result contains just one object. The following waitForXPath()  function is useful if you expect more than one object or if you want to synchronise for more generic conditions:

function waitForXPath(startObj, xpath, condition, timeout=20*1000)
{
    var result;
    waitFor(function() {
        result = startObj.evaluateXPath(xpath);
        return condition(result);
    }, timeout);
    test.verify(
        condition(result),
        'waitForXPath: verify that a result for the condition was found'
    )
    var ret = [];
    for (var i = 0; i < result.snapshotLength; i++) {
        ret.push(result.snapshotItem(i));
    }
    return ret;
}

function main() {
    ...
    var form = waitForObject(names.googleFFORM);
    var result = waitForXPath(form, "//INPUT[@type='submit']", function(r) { return r.snapshotLength == 2; });
    ...
}

The caller of the waitForXPath()  function passes a function that waits until the matched result contains exactly two objects.

So if you are not able to express the object you are looking for with a Squish object name, maybe you can use an XPath expression instead.



Source link https://www..com/blog/xpath-in-squish-for-web-as-object-names/

LEAVE A REPLY

Please enter your comment!
Please enter your name here