Handbuch | Tutorial | Standardbibliothek | Release Notes

Release Notes

48.2
Das webResolvers-Modul

4.2+In den meisten Fällen kann man die Komponenten-Erkennung von QF-Test am besten mit einem klassischen Resolver anpassen, wie im letzen Kapitel Abschnitt 48.1 beschrieben. Wenn der Resolver jedoch für ein Web-Projekt verwendet wird und stark mit dem Browser interagiert, dann bietet sich mit dem webResolvers-Modul die Möglichkeit, den Resolver-Code direkt im Browser auszuführen.

48.2.1
Allgemeine Informationen

Hinweis QF-Test speichert den aktuellen Zustand der Webseite, die aktuell im Browser angezeigt wird, in einem lokalen Cache. Die meisten Methoden, die üblicherweise in einem Resolver verwendet werden, können von QF-Test mit Hilfe dieses Caches ausgeführt werden. Dies führt zu einer wesentlichen Steigerung der Ausführungs-Geschwindigkeit. Resolver, die mit dem webResolvers-Modul registriert werden, kommen immer direkt im Browser zur Ausführung, wodurch die Komponenten-Erkennung verlangsamt werden kann. Allerdings ist es sinnvoll, resolver mit dem webResolvers-Modul zu registrieren, wenn diese grundsätzlich stark auf Browser-Funktionen angewiesen sind, d.h. wenn sie auf Aufrufen der Methoden getAttributeIfSpecified oder evalJS(...) basieren.

Die API des webResolvers-Moduls imitiert diejenige des resolvers-Moduls. Daher haben die vorhandenen Methoden dieselben Namen und werden auch genauso verwendet wie die im letzen Kapitel vorgestellten Methoden. Der wesentliche Unterschied besteht bei der Definition des Resolver-Algorithmus: Hier werden immer JavaScript-Methoden (eingepackt in Strings) erwartet, die dann direkt im Browser ausgeführt werden. Dort erhalten Sie dann auch Browser- und JavaScript-Objekte als Argumente.

HinweisWenn das SUT-Skript, in welchem die Resolver registriert werden, selbst bereits in JavaScript geschrieben ist, so kann man als Argument auch direkt Funktionen angeben. Diese werden dann beim Aufruf in Strings umgewandelt und so im Browser registriert. Da sie dann aber im Browser-Kontext (und nicht in der SUT-Skript-Umgebung von QF-Test) ausgeführt werden, können keine Daten über gemeinsame Variablen zwischen dem registrierenden Skript und der Resolver-Funktion ausgetauscht werden

Das webResolvers-Modul beschränkt sich auf diese Resolver-Typen:

48.2.2
addResolver

Die generische Methode addResolver ist zentral für das webResolvers-Module. Sie registriert einen neuen Resolver. Der Typ wird dabei bestimmt anhand des Namens der JavaScript-Funktion (welcher nicht immer identisch mit dem Name der Variable, in der die Funktion gespeichert wurde) und der Anzahl der von ihr spezifierten Argumente.

 
 
addResolver(String resolverName, String function, Object target=None, ...):
Registriert den oder die über die JavaScript Function festgelegten webResolver für die angegebenen Ziele. Falls bereits ein Resolver unter dem angegebenen Resolver-Namen registriert war, wird dieser zunächst deregistriert.
Parameter
name Der Name unter dem der Resolver registriert werden soll.
function Die JavaScript-Funktion, welche die Methode des Resolvers implementiert. Der Name dieser Methode definiert den Typ des registrierten Resolvers. Zulässige Werte sind z.B.: getName, getClassName, getGenericClassName, getFeature, getExtraFeatures, getItemName, getItemValue, isInterestingParent, getTooltip, getId, isEnabled, isVisible, getMainText, matchExtraFeature und applicationIsBusy.
target Ein oder mehrere optionale Ziele für die der Resolver registriert werden soll. Für jedes Ziel gibt es folgende Varianten:
  • Eine individuelle Komponente
  • Der Name einer Klasse
Ist kein Ziel angegeben, wird der Resolver global für alle Komponenten registriert.
 
 
48.2.3
removeResolver

Die über das webResolvers Modul registrierten Resolver können mittels der Funktion removeResolver deregistriert werden.

 
 
removeResolver(String name)
Deregistriert einen Resolver von allen Zielen, für die er registriert war.
Parameter
nameDer Name, unter dem der Resolver registriert war.
 
removeAll()
Deregistriert alle über das webResolvers Modul registrierten Resolver von allen Zielen, für die sie registriert waren.
 
 

Im Beispiel wird zunächst ein unter dem Namen "myName" registrierter Resolver entfernt, danach alle über das webResolvers-Modul registrierten Resolver.

webResolvers.removeResolver("myName")
webResolvers.removeAll()
Beispiel 48.26:  SUT-Skript zur Deregistrierung eines Resolvers
48.2.4
listNames

Gibt eine Liste der Namen der Resolver zurück, die über das webResolvers Modul registriert wurden.

 
 
List<String> listNames()
Listet die Namen der registrierten Resolver auf.
 
 

Im Beispiel wird überprüft, ob ein spezifischer Resolver registriert wurde. Falls nicht wird dem Protokoll eine Fehlermeldung hinzugefügt.

if (! webResolvers.listNames().contains("specialNames")) {
    rc.logError("Special names resolver not registered!")
}
Beispiel 48.27:  Groovy SUT-Skript zur Abfrage registrierter Resolver über das webResolvers Modul
48.2.5
Beispiele

Die Benutzung der webResolver ist identisch zu Resolvern, welche über das resolvers-Modul registriert werden. Daher wird hier auf eine ausführliche Beschreibung der Resolver selbst und ihrer Funktionalität verzichtet und auf das vorangehende Kapitel verwiesen. Statt dessen wird hier durch ausgewählte Beispiele die Anwendung des webResolvers-Moduls dargestellt:

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

webResolvers.addResolver("myNames", getNameFunc, "DIV")
Beispiel 48.28:  Ein webNameResolver wird mit Jython registriert
def getFeatureFunc = """
function getFeature(node, feature) {
    try {
        var title = node.firstChild.textContent;
        if (title) return title;
    } catch (e) {}
}
"""

webResolvers.addResolver("paneltitle", getFeatureFunc, "Panel")
Beispiel 48.29:  Ein webFeatureResoler, registriert mit einem Groovy SUT-Skript
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);
Beispiel 48.30:   Ein webExtraFeatureResolver welcher ein 'Weiteres Merkmal' für ein spezifisches Attribut hinzufügt, registriert mit einem JavaScript SUT-Skript
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");
Beispiel 48.31:   Ein webExtraFeatureResolver welcher ein bestehendes 'Weiteres Merkmal' ändert
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")
Beispiel 48.32:  Ein webItemNameResolver, registriert mit einem Jython SUT-Skript
def getTooltipFunc = """
function getTooltip(node, tooltip) {
    if (tooltip) {
        var userLang = navigator.language || navigator.userLanguage;
        if (userLang) {
            return tooltip + "-" + userLang;
        }
    }
}
"""

webResolvers.addResolver("tootip-lang", getTooltipFunc)
Beispiel 48.33:  Ein webTooltipResoler, registriert mit einem Groovy SUT-Skript
function isEnabled(node) {
    try {
        return ! node.className.split(' ').contains("v-disabled");
    } catch (e) {
        return true;
    }
}

webResolvers.addResolver("vEnabledResolver",isEnabledFunc);
Beispiel 48.34:  Ein webEnabledResolver, registriert mit einem JavaScript SUT-Skript
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);
Beispiel 48.35:  Ein webVisibilityResolver
getMainTextFunc = """
function getMainText(element,text) {
    if (text) return text.replace("TO-DO","")
}
"""

webResolvers.addResolver("removeMarkFromText",getMainTextFunc)
Beispiel 48.36:  Ein webMainTextResolver, registriert mit einem Jython SUT-Skript
function isBusy(element) {
    const overlay = element.getElementsByClassName("overlay")[0];
    return !!overlay;
}

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

webResolvers.addResolver("taskChecker",applicationIsBusy);
Beispiel 48.38:  Ein 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)
Beispiel 48.39:  Ein 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");
Beispiel 48.40:  Die Verwendung von addSpecificExtraFeatureMatcher für einen webExtraFeatureMatcher