appium-ios-driver
Version:
Appium driver for iOS
228 lines (185 loc) • 7.8 kB
JavaScript
/* globals $ */
(function () {
$._elementOrElementsByType = function (targetElement, opts) {
if (!targetElement || targetElement.isNil()) {
throw new Error("Target element must exist");
}
return targetElement._elementOrElementsByType(opts);
};
UIAElement.prototype._elementOrElementsByType = function (opts) {
var typeArray = opts.typeArray,
onlyFirst = opts.onlyFirst,
onlyVisible = opts.onlyVisible,
nameObject = opts.name,
labelObject = opts.label,
valueObject = opts.value;
if (!typeArray) throw new Error("Must provide typeArray when calling _elementOrElementsByType");
var numTypes = typeArray.length;
// allow '*' to match on all types.
var allTypes = false;
if (numTypes === 1 && typeArray[0] === '*') allTypes = true;
onlyFirst = onlyFirst === true;
onlyVisible = onlyVisible !== false;
var validateObject = function (objectName, object) {
if (object && (typeof object.substring === "undefined" ||
typeof object.target === "undefined" ||
typeof object.insensitive === "undefined")) {
throw new Error(objectName + " object must contain substring, target, and insensitive");
}
};
validateObject("name", nameObject);
validateObject("label", labelObject);
validateObject("value", valueObject);
var target = $.target();
target.pushTimeout(0);
var attributeMatch = function (elementProperty, attributeObject) {
if (!elementProperty || !attributeObject) return false;
var target = attributeObject.target;
if (!target) return false;
if (attributeObject.insensitive) {
elementProperty = elementProperty.toLowerCase();
target = target.toLowerCase();
}
if (attributeObject.substring) {
return elementProperty.indexOf(target) !== -1;
} else {
return elementProperty === target;
}
};
var getTree = function (element) {
var elems = [];
// element.elements() may return nil children.
if (element.isNil()) {
return elems;
}
// process element
var visible = element.isVisible() === 1;
var elType = element.type();
for (var i = 0; i < numTypes; i++) {
if (allTypes || elType === typeArray[i]) {
if (!onlyVisible || visible) {
// if an object isn't provided then it's a match.
var nameMatch = nameObject ? attributeMatch(element.name(), nameObject) : false;
var labelMatch = labelObject ? attributeMatch(element.label(), labelObject) : false;
var valueMatch = valueObject ? attributeMatch(element.value(), valueObject) : false;
// If we're only searching for a type then skip attribute matching.
if (!nameObject && !labelObject && !valueObject) nameMatch = true;
if (element.checkIsValid() && (nameMatch || labelMatch || valueMatch)) {
elems.push(element);
}
if (onlyFirst && elems.length === 1) return elems;
break;
}
}
}
if (element.hasChildren()) {
var children = element.elements();
var numChildren = children.length;
for (i = 0; i < numChildren; i++) {
if (onlyFirst && elems.length === 1) return elems;
elems = elems.concat(getTree(children[i]));
}
}
return elems;
};
var foundElements = getTree(this);
target.popTimeout();
return $.smartWrap(foundElements).dedup();
};
UIAElement.prototype.getFirstWithPredicateWeighted = function (predicate) {
var weighting = [
'secureTextFields'
, 'textFields'
, 'buttons'
, 'elements'
];
var elems = this._elementOrElementsWithPredicateWeighted(predicate,
weighting, true);
return $.smartWrap(elems).dedup()[0];
};
UIAElement.prototype.getFirstWithPredicate = function (predicate, onlyVisible) {
var weighting = ['elements'];
var elems = this._elementOrElementsWithPredicateWeighted(
predicate, weighting, true, onlyVisible);
return $.smartWrap(elems).dedup()[0];
};
UIAElement.prototype.getAllWithPredicate = function (predicate, onlyVisible) {
var weighting = ['elements'];
var elems = this._elementOrElementsWithPredicateWeighted(predicate, weighting, false, onlyVisible);
return $.smartWrap(elems).dedup();
};
UIAElement.prototype._elementOrElementsWithPredicateWeighted = function (predicate, weighting, onlyFirst, onlyVisible) {
weighting = weighting || ['elements'];
onlyFirst = (onlyFirst === true);
onlyVisible = onlyVisible !== false;
UIATarget.localTarget().pushTimeout(0);
var results = [];
var element = this;
var found, prop;
for (var i = 0; i < weighting.length; i++) {
prop = weighting[i];
if (typeof element[prop] === 'function') {
found = element[prop]();
if (predicate) found = found.withPredicate(predicate);
if (onlyVisible) found = found.withValueForKey(true, 'isVisible');
} else {
throw new Error("Invalid function '" + prop + "'");
}
if (found.isValid()) {
results = results.concat(found.toArray());
}
// If we don't find anything or if we aren't just trying to find the first
// match, keep looking. Otherwise exit the loop.
if (onlyFirst && results.length > 0) break;
}
// Only look through children if we have to.
if (!onlyFirst || results.length === 0) {
var child;
var children = this.elements();
for (var a = 0; a < children.length; a++) {
child = children[a];
// make sure child isn't nil and isn't a webview
// (we don't care about them for native and they tend to have tons
// of children which make performance bad)
if (!child.isNil() && child.type() !== "UIAWebView") {
results = results.concat(child
._elementOrElementsWithPredicateWeighted(predicate,
weighting, onlyFirst, onlyVisible));
}
}
}
UIATarget.localTarget().popTimeout();
return results;
};
var _formatPredicate = function (targetName, contains) {
targetName = targetName || "";
if (typeof targetName !== 'string') {
throw new Error("You must supply a string for an element predicate search.");
}
// escape unescaped single and double quotation marks and return a predicate condition
// string in the format 'name VERB "TARGET" || label VERB "TARGET"'.
var verb = contains ? 'contains[c]' : '==';
var comparison = verb + ' "' + targetName.replace(/\\?['"]/g, "\\$&") + '"';
return 'name ' + comparison + ' || label ' + comparison;
};
UIAElement.prototype.getWithName = function (targetName, onlyVisible) {
return this.getFirstWithPredicate(_formatPredicate(targetName, false), onlyVisible);
};
UIAElement.prototype.getAllWithName = function (targetName, onlyVisible) {
return this.getAllWithPredicate(_formatPredicate(targetName, false), onlyVisible);
};
UIAElement.prototype.getNameContains = function (targetName, onlyVisible) {
return this.getFirstWithPredicate(_formatPredicate(targetName, true), onlyVisible);
};
UIAElement.prototype.getAllNameContains = function (targetName, onlyVisible) {
return this.getAllWithPredicate(_formatPredicate(targetName, true), onlyVisible);
};
UIAElement.prototype.getWithNameAndTap = function (targetName, onlyVisible) {
var el = this.getWithName(targetName, onlyVisible);
if (!el || el.isNil()) {
throw new Error("Could not find the element to tap");
}
el.tap();
return el;
};
})();