The webResolvers module

4.2+For most use cases, registering a resolver using the resolvers module as described in the last chapter section 52.1 is the best way to adapt the component recognition of QF-Test. If the custom resolvers are used for a web context and heavily interacting with the browser content directly, the webResolvers module provides an option to run the resolver code directly in the browser.

General Information

Note QF-Test internally caches the state of the displayed web page and runs most of the commands, which are usually invoked in a resolver, on the cached representation of the web page. This tremendously improves resolving time. Resolvers registered on the webResolver module are always executed directly in the browser, which might slow down component recognition. On the other hand, resolvers registered using the webResolvers module are convenient if it requires several downcalls to the browser, i.e. if using the getAttributeIfSpecified method or evalJS(...).

In general, the webResolvers module mimics the resolvers module, so its methods and their usage is similar to those described in the last chapter. In difference to those, the methods have to be written as JavaScript functions, wrapped in Strings. The resolver code is then directly executed in the browser, so its function arguments are also Browser objects and JavaScript objects.

NoteIf you write your SUT script in JavaScript, you can use a function directly as argument for the register call. The given function will then be stringified and registered as resolver in the browser. Be aware that this resolver function is executed in the browser, not in the QF-Test SUT script environment, and variables are not shared between the two contexts.

The webResolvers module is limited to these resolvers types:

addResolver

The generic method addResolver has a central role in the webResolvers module. The method registers a new resolver. It identifies the type of the resolver using the name of the JavaScript function which not always is equal to the name of the variable which references the function) and its parameter count.

 
 
addResolver(String resolverName, String function, Object target=None, ...):
Register the webResolver determined by the given JavaScript function for the given target(s). If another resolver was previously registered under the given name, deregister that first.
Parameters
name The name under which to register the resolver.
function The JavaScript function implementing the resolver. The name of the function defines the type of the registered resolver. Valid names are e.g.: getName, getClassName, getGenericClassName, getFeature, getExtraFeatures, getItemName, getItemValue, isInterestingParent, getTooltip, getId, isEnabled, isVisible, getMainText, matchExtraFeature, and applicationIsBusy.
target One or more optional targets to register the resolver for. Each can be any of the following:
  • An individual component
  • The fully qualified tag name of a class
If no target is given a global resolver for all components is registered.
 
 

removeResolver

The function removeResolver may be used to deregister resolvers installed via the webResolvers module.

 
 
void removeAll()
Deregister all resolvers registered via the webResolvers module from all targets they were registered for.
 
void removeResolver(String name)
Deregister a resolver from all the targets it was registered for.
Parameters
nameThe name the resolver was registered under.
 
 

The example first removes a resolver registered under the name "myName", then deregisters all resolvers registered via the webResolvers module.

webResolvers.removeResolver("myName")
webResolvers.removeAll()
Example 52.29:  SUT script deregistering webResolvers

listNames

Return a list of resolver names registered via the webResolvers module.

 
 
List<String> listNames()
List the registered resolvers.
 
 

The example checks whether a certain resolver has been registered. If not, an error message is written to the run log.

if (! webResolvers.listNames().contains("specialNames")) {
    rc.logError("Special names resolver not registered!")
}
Example 52.30:  Groovy SUT script searching for a certain resolver registered via the webResolvers module

Examples

Since the role and usage of webResolvers is equal to those registered using the resolvers module, we refer to the last chapter for a detailed description of the specific resolvers. Here, we demonstrate the usage of webResolvers in selected examples:

getNameFunc = """
function getName(node, name) {
    if (! name) return node.getAttribute("__name__");
}
"""

webResolvers.addResolver("myNames", getNameFunc, "DIV")
Example 52.31:  Registering a webNameResolver in Jython
def getFeatureFunc = """
function getFeature(node, feature) {
    try {
        var title = node.firstChild.textContent;
        if (title) return title;
    } catch (e) {}
}
"""

webResolvers.addResolver("paneltitle", getFeatureFunc, "Panel")
Example 52.32:  A webFeatureResoler registered using a Groovy SUT script
function getExtraFeatures(node, features) {
    try {
        const myId = node.getAttribute("myId");
        if (myId) {
            features.add(ExtraFeature.STATE_MUST_MATCH,"myId", myId);
            return features;
        }
    } catch (e) {}
}

webResolvers.addResolver("myId", getExtraFeatures);
Example 52.33:   webExtraFeatureResolver adding an 'Extra feature' for a special attribute using a JavaScript SUT script
function getExtraFeatures(node, features) {
    const labelFeature == features.get("qfs:label");
    if (labelFeature && labelFeature.value == "bad name") {
        labelFeature.value = "good name";
        return features;
    }
}
webResolvers.addResolver("get label example", getExtraFeatures,"TextField");
Example 52.34:   webExtraFeatureResolver changing an existing 'Extra feature'
getColumnIdFunc = """
function getColumnId(table, item, name) {
    var id;
    if (item[1] < 0 ) { // whole column addressed
        id = table.getElementsByTagName("TH")[0].id;
    }
    if (id) return id;
}
"""

webResolvers.addResolver("tableColumnId", getColumnIdFunc, "TableColumn")
Example 52.35:  A webItemNameResolver registered using a Jython SUT script
def getTooltipFunc = """
function getTooltip(node, tooltip) {
    if (tooltip) {
        var userLang = navigator.language || navigator.userLanguage;
        if (userLang) {
            return tooltip + "-" + userLang;
        }
    }
}
"""

webResolvers.addResolver("tootip-lang", getTooltipFunc)
Example 52.36:  A webTooltipResoler registered using a Groovy SUT script
function isEnabled(node) {
    try {
        return ! node.className.split(' ').contains("v-disabled");
    } catch (e) {
        return true;
    }
}

webResolvers.addResolver("vEnabledResolver",isEnabledFunc);
Example 52.37:  A webEnabledResolver, registered using a JavaScript SUT script
function isVisible(element, visible) {
    const getOpacity = function(el) { // inner function, so it is part
                                           // of the registered resolver
        const style = window.getComputedStyle(el);
        const opacity = style.getPropertyValue("opacity")
        if (! opacity) return 1;
        return parseFloat(opacity);
    }
    return visible && getOpacity(element) > 0;
}

webResolvers.addResolver("opacityResolver",isVisible);
Example 52.38:  A webVisibilityResolver
getMainTextFunc = """
function getMainText(element,text) {
    if (text) return text.replace("TO-DO","")
}
"""

webResolvers.addResolver("removeMarkFromText",getMainTextFunc)
Example 52.39:  A webMainTextResolver, registered in a Jython SUT script
function isBusy(element) {
    const overlay = element.getElementsByClassName("overlay")[0];
    return !!overlay;
}

webResolvers.addResolver("overlayBusyResolver",isBusy);
Example 52.40:  A webBusyPaneResolver
function applicationIsBusy() {
    const tasks = $specialFramework.waitingTasks();
    return tasks && tasks.length() > 0;
}

webResolvers.addResolver("taskChecker",applicationIsBusy);
Example 52.41:  A webBusyApplicationDetector
function matchExtraFeature(element, name, value, regexp, negate) {
    if (name != "my:label") return;
    const label = element.getAttribute("my-label");
    var match = false;
    if (label) {
        if (regexp) {
           match = !! label.match(value);
        } else {
           match = (value == label);
        }
    }
    return negate ? ! match : match;
}

webResolvers.addResolver("myLabelResolver", matchExtraFeature)
Example 52.42:  A webExtraFeatureMatcher
function matchExtraFeature(element, name, value, regexp, negate) {
    const label = element.getAttribute("my-label");
    var match = false;
    if (label) {
        if (regexp) {
           match = !! label.match(value);
        } else {
           match = (value == label);
        }
    }
    return negate ? ! match : match;
}

webResolvers.addSpecificExtraFeatureMatcher("myLabelResolver",
                               matchExtraFeature, "my:label");
Example 52.43:  Using addSpecificExtraFeatureMatcher for a webExtraFeatureMatcher