refactor(appium)!: remove support for -custom locator strategy(should be handled by plugins instead)
MODIFY
packages/base-driver/lib/basedriver/commands/find.js
packages/base-driver/lib/basedriver/commands/find.js
import log from '../logger';
-import { logger } from 'appium-support';
-import _ from 'lodash';
-import { errors } from '../../..';
const commands = {}, helpers = {}, extensions = {};
-const CUSTOM_STRATEGY = '-custom';
// Override the following function for your own driver, and the rest is taken
// care of!
@@ -37,18 +33,10 @@ helpers.findElOrElsWithProcessing = async function findElOrElsWithProcessing (st
};
commands.findElement = async function findElement (strategy, selector) {
- if (strategy === CUSTOM_STRATEGY) {
- return await this.findByCustom(selector, false);
- }
-
return await this.findElOrElsWithProcessing(strategy, selector, false);
};
commands.findElements = async function findElements (strategy, selector) {
- if (strategy === CUSTOM_STRATEGY) {
- return await this.findByCustom(selector, true);
- }
-
return await this.findElOrElsWithProcessing(strategy, selector, true);
};
@@ -60,115 +48,7 @@ commands.findElementsFromElement = async function findElementsFromElement (strat
return await this.findElOrElsWithProcessing(strategy, selector, true, elementId);
};
-/**
- * Find an element using a custom plugin specified by the customFindModules cap.
- *
- * @param {string} selector - the selector which the plugin will use to find
- * elements
- * @param {boolean} multiple - whether we want one element or multiple
- *
- * @returns {WebElement} - WebDriver element or list of elements
- */
-commands.findByCustom = async function findByCustom (selector, multiple) {
- const plugins = this.opts.customFindModules;
-
- // first ensure the user has registered one or more find plugins
- if (!plugins) {
- // TODO this info should go in docs instead; update when docs for this
- // feature exist
- throw new Error('Finding an element using a plugin is currently an ' +
- 'incubating feature. To use it you must manually install one or more ' +
- 'plugin modules in a way that they can be required by Appium, for ' +
- 'example installing them from the Appium directory, installing them ' +
- 'globally, or installing them elsewhere and passing an absolute path as ' +
- 'the capability. Then construct an object where the key is the shortcut ' +
- 'name for this plugin and the value is the module name or absolute path, ' +
- 'for example: {"p1": "my-find-plugin"}, and pass this in as the ' +
- "'customFindModules' capability.");
- }
-
- // then do some basic checking of the type of the capability
- if (!_.isPlainObject(plugins)) {
- throw new Error("Invalid format for the 'customFindModules' capability. " +
- 'It should be an object with keys corresponding to the short names and ' +
- 'values corresponding to the full names of the element finding plugins');
- }
-
- // get the name of the particular plugin used for this invocation of find,
- // and separate it from the selector we will pass to the plugin
- let [plugin, realSelector] = selector.split(':');
-
- // if the user didn't specify a plugin for this find invocation, and we had
- // multiple plugins registered, that's a problem
- if (_.size(plugins) > 1 && !realSelector) {
- throw new Error(`Multiple element finding plugins were registered ` +
- `(${_.keys(plugins)}), but your selector did not indicate which plugin ` +
- `to use. Ensure you put the short name of the plugin followed by ':' as ` +
- `the initial part of the selector string.`);
- }
-
- // but if they did not specify a plugin and we only have one plugin, just use
- // that one
- if (_.size(plugins) === 1 && !realSelector) {
- realSelector = plugin;
- plugin = _.keys(plugins)[0];
- }
-
- if (!plugins[plugin]) {
- throw new Error(`Selector specified use of element finding plugin ` +
- `'${plugin}' but it was not registered in the 'customFindModules' ` +
- `capability.`);
- }
-
- let finder;
- try {
- log.debug(`Find plugin '${plugin}' requested; will attempt to use it ` +
- `from '${plugins[plugin]}'`);
- finder = require(plugins[plugin]);
- } catch (err) {
- throw new Error(`Could not load your custom find module '${plugin}'. Did ` +
- `you put it somewhere Appium can 'require' it? Original error: ${err}`);
- }
-
- if (!finder || !_.isFunction(finder.find)) {
- throw new Error('Your custom find module did not appear to be constructed ' +
- 'correctly. It needs to export an object with a `find` method.');
- }
-
- const customFinderLog = logger.getLogger(plugin);
-
- let elements;
- const condition = async () => {
- // get a list of matched elements from the custom finder, which can
- // potentially use the entire suite of methods the current driver provides.
- // the finder should always return a list of elements, but may use the
- // knowledge of whether we are looking for one or many to perform internal
- // optimizations
- elements = await finder.find(this, customFinderLog, realSelector, multiple);
-
- // if we're looking for multiple elements, or if we're looking for only
- // one and found it, we're done
- if (!_.isEmpty(elements) || multiple) {
- return true;
- }
-
- // otherwise we should retry, so return false to trigger the retry loop
- return false;
- };
-
- try {
- // make sure we respect implicit wait
- await this.implicitWaitForCondition(condition);
- } catch (err) {
- if (err.message.match(/Condition unmet/)) {
- throw new errors.NoSuchElementError();
- }
- throw err;
- }
-
- return multiple ? elements : elements[0];
-};
Object.assign(extensions, commands, helpers);
-export { commands, helpers, CUSTOM_STRATEGY };
+export { commands, helpers };
export default extensions;

DELETE
packages/base-driver/test/basedriver/commands/find-specs.js
-import chai from 'chai';
-import path from 'path';
-import chaiAsPromised from 'chai-as-promised';
-import { BaseDriver } from '../../..';
-import { CUSTOM_STRATEGY } from '../../../lib/basedriver/commands/find';
-
-chai.use(chaiAsPromised);
-
-const CUSTOM_FIND_MODULE = path.resolve(__dirname, '..', '..', '..', '..',
- 'test', 'basedriver', 'fixtures', 'custom-element-finder');
-const BAD_CUSTOM_FIND_MODULE = path.resolve(__dirname, '..', '..', '..', '..',
- 'test', 'basedriver', 'fixtures', 'custom-element-finder-bad');
-
-describe('custom element finding plugins', function () {
- // happys
- it('should find a single element using a custom finder', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'f:foo').should.eventually.eql('bar');
- });
- it('should not require selector prefix if only one find plugin is registered', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'foo').should.eventually.eql('bar');
- });
- it('should find multiple elements using a custom finder', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE};
- await d.findElements(CUSTOM_STRATEGY, 'f:foos').should.eventually.eql(['baz1', 'baz2']);
- });
- it('should give a hint to the plugin about whether multiple are requested', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'f:foos').should.eventually.eql('bar1');
- });
- it('should be able to use multiple find modules', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE, g: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'f:foo').should.eventually.eql('bar');
- await d.findElement(CUSTOM_STRATEGY, 'g:foo').should.eventually.eql('bar');
- });
-
- // errors
- it('should throw an error if customFindModules is not set', async function () {
- const d = new BaseDriver();
- await d.findElement(CUSTOM_STRATEGY, 'f:foo').should.eventually.be.rejectedWith(/customFindModules/);
- });
- it('should throw an error if customFindModules is the wrong shape', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = CUSTOM_FIND_MODULE;
- await d.findElement(CUSTOM_STRATEGY, 'f:foo').should.eventually.be.rejectedWith(/customFindModules/);
- });
- it('should throw an error if customFindModules is size > 1 and no selector prefix is used', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE, g: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'foo').should.eventually.be.rejectedWith(/multiple element finding/i);
- });
- it('should throw an error in attempt to use unregistered plugin', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE, g: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'z:foo').should.eventually.be.rejectedWith(/was not registered/);
- });
- it('should throw an error if plugin cannot be loaded', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: './foo.js'};
- await d.findElement(CUSTOM_STRATEGY, 'f:foo').should.eventually.be.rejectedWith(/could not load/i);
- });
- it('should throw an error if plugin is not the right shape', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: BAD_CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'f:foo').should.eventually.be.rejectedWith(/constructed correctly/i);
- });
- it('should pass on an error thrown by the finder itself', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'f:error').should.eventually.be.rejectedWith(/plugin error/i);
- });
- it('should throw no such element error if element not found', async function () {
- const d = new BaseDriver();
- d.opts.customFindModules = {f: CUSTOM_FIND_MODULE};
- await d.findElement(CUSTOM_STRATEGY, 'f:nope').should.eventually.be.rejectedWith(/could not be located/);
- });
-});

refactor(appium)!: remove support for -custom locator strategy(should be handled by plugins instead) (#15452)