diff --git a/lib/devices/android/android-controller.js b/lib/devices/android/android-controller.js index f19012d2a..cd9deb8b9 100644 --- a/lib/devices/android/android-controller.js +++ b/lib/devices/android/android-controller.js @@ -4,6 +4,7 @@ var errors = require('../../server/errors.js') , _ = require('underscore') , logger = require('../../server/logger.js').get('appium') , deviceCommon = require('../common.js') + , helpers = require('../../helpers.js') , jwpSuccess = deviceCommon.jwpSuccess , status = require('../../server/status.js') , NotYetImplementedError = errors.NotYetImplementedError @@ -64,6 +65,9 @@ androidController.findUIElementOrElements = function (strategy, selector, many, params = _.extend(params, xpathParams); } } + if (strategy === "name") { + helpers.logDeprecationWarning("Locator strategy", '"name"', '"accessibility_id"'); + } var doFind = function (findCb) { this.proxy(["find", params], function (err, res) { this.handleFindCb(err, res, many, findCb); diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/Find.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/Find.java index 3946723df..bd40b072f 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/Find.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/Find.java @@ -392,6 +392,13 @@ public class Find extends CommandHandler { } } break; + case ACCESSIBILITY_ID: + sel = sel.description(text); + if (!many) { + sel = sel.instance(0); + } + selectors.add(sel); + break; case NAME: sel = selectNameOrText(many, text); selectors.add(sel); diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/selector/Strategy.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/selector/Strategy.java index cd190c0ed..d08815f0b 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/selector/Strategy.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/selector/Strategy.java @@ -10,7 +10,7 @@ public enum Strategy { CLASS_NAME(0, "class name"), CSS_SELECTOR(1, "css selector"), ID(2, "id"), NAME( 3, "name"), LINK_TEXT(4, "link text"), PARTIAL_LINK_TEXT(5, "partial link text"), TAG_NAME(6, "tag name"), XPATH(7, "xpath"), DYNAMIC( - 8, "dynamic"); + 8, "dynamic"), ACCESSIBILITY_ID(9, "accessibility_id"); public static Strategy fromString(final String text) throws InvalidStrategyException { if (text != null) { diff --git a/lib/devices/common.js b/lib/devices/common.js index e7048f289..982312d28 100644 --- a/lib/devices/common.js +++ b/lib/devices/common.js @@ -204,6 +204,7 @@ exports.checkValidLocStrat = function (strat, includeWeb, cb) { 'xpath', 'id', 'name', + 'accessibility_id', 'dynamic', 'class name' ]; diff --git a/lib/devices/ios/ios-controller.js b/lib/devices/ios/ios-controller.js index fdc099a7b..9d63e3e15 100644 --- a/lib/devices/ios/ios-controller.js +++ b/lib/devices/ios/ios-controller.js @@ -50,6 +50,10 @@ iOSController.findUIElementOrElements = function (strategy, selector, ctx, many, var command = ""; switch (strategy) { case "name": + helpers.logDeprecationWarning("Locator Strategy", '"name"', '"accessibility_id"'); + command = ["au.getElement", ext, "ByName('", selector, "'", ctx, ")"].join(''); + break; + case "accessibility_id": command = ["au.getElement", ext, "ByName('", selector, "'", ctx, ")"].join(''); break; case "xpath": diff --git a/lib/devices/ios/ios.js b/lib/devices/ios/ios.js index a4f6fb651..923c17d2c 100644 --- a/lib/devices/ios/ios.js +++ b/lib/devices/ios/ios.js @@ -89,7 +89,7 @@ IOS.prototype.init = function () { this.curWebCoords = null; this.onPageChangeCb = null; this.dontDeleteSimApps = false; - this.supportedStrategies = ["name", "tag name", "xpath", "id", "-ios_uiautomation"]; + this.supportedStrategies = ["name", "accessibility_id", "tag name", "xpath", "id", "-ios_uiautomation"]; this.localizableStrings = {}; this.keepAppToRetainPrefs = false; }; diff --git a/test/functional/android/apidemos/find-element-specs.js b/test/functional/android/apidemos/find-element-specs.js index dfa7a1dad..548f817a3 100644 --- a/test/functional/android/apidemos/find-element-specs.js +++ b/test/functional/android/apidemos/find-element-specs.js @@ -75,13 +75,13 @@ describe("apidemo - find elements -", function () { .elementById("buttons_1_normal").text().should.become("Normal") .nodeify(done); }); - // TODO: find by resource id doesn't seem to work - it('should find a single element by resource-id @skip-android-all', function (done) { + + it('should find a single element by resource-id', function (done) { driver .elementById('android:id/home').should.eventually.exist .nodeify(done); }); - it('should find multiple elements by resource-id @skip-android-all', function (done) { + it('should find multiple elements by resource-id', function (done) { driver .elementsById('android:id/text1') .should.eventually.have.length.at.least(10) @@ -156,6 +156,19 @@ describe("apidemo - find elements -", function () { }); }); + describe('find elements using accessibility_id locator strategy', function () { + it('should find an element by name', function (done) { + driver.element('accessibility_id', 'Animation').then(function (el) { + el.should.exist; + }).nodeify(done); + }); + it('should return an array of one element if the plural "elements" is used', function (done) { + driver.elements('accessibility_id', 'Animation').then(function (els) { + els.length.should.equal(1); + }).nodeify(done); + }); + }); + describe('unallowed tag names', function () { it('should not find secure fields', function (done) { driver diff --git a/test/functional/ios/uicatalog/find-element-specs.js b/test/functional/ios/uicatalog/find-element-specs.js index 7de5895ff..ad1eed153 100644 --- a/test/functional/ios/uicatalog/find-element-specs.js +++ b/test/functional/ios/uicatalog/find-element-specs.js @@ -66,6 +66,31 @@ describe('uicatalog - find element -', function () { }).nodeify(done); }); + describe('find elements using accessibility_id locator strategy', function () { + it('should find an element by name', function (done) { + driver.element('accessibility_id', 'UICatalog').then(function (el) { + el.should.exist; + }).nodeify(done); + }); + it('should find a deeply nested element by name', function (done) { + driver.element('accessibility_id', 'UINavigationBarBackIndicatorDefault.png').then(function (el) { + el.should.exist; + }).nodeify(done); + }); + it('should find an element by name beneath another element', function (done) { + driver.element('accessibility_id', 'Empty list').then(function (el) { + el.element('accessibility_id', 'Controls, Various uses of UIControl').then(function (innerEl) { + innerEl.should.exist; + }).nodeify(done); + }); + }); + it('should return an array of one element if the plural "elements" is used', function (done) { + driver.elements('accessibility_id', 'UICatalog').then(function (els) { + els.length.should.equal(1); + }).nodeify(done); + }); + }); + describe('findElementsByTagName', function () { it('should return all image elements with internally generated ids', function (done) { driver.elementsByTagName('image').then(function (els) { @@ -187,9 +212,9 @@ describe('uicatalog - find element -', function () { driver.element('-ios_uiautomation', '.navigationBars()[0]') .getAttribute('name').then(function (name) { if (name !== 'UICatalog') { - driver.back().then(done); + driver.back().delay(2000).nodeify(done); } else { - done(); + Q.delay(500).nodeify(done); } }); });