UNPKG

macaca-wd

Version:

Macaca webdirver API for Node.js

322 lines (283 loc) 8.58 kB
'use strict'; const __slice = Array.prototype.slice; const url = require('url'); const SPECIAL_KEYS = require('webdriver-keycode'); let Webdriver = require('./webdriver'); let Element = require('./element'); const utils = require('./utils'); const deprecator = utils.deprecator; const config = require('./config'); const _ = require('./lodash'); const Q = require('q'); const actions = require('./actions'); function buildConfigUrl(remoteWdConfig) { const configUrl = _(remoteWdConfig).clone(); // for backward compatibility if (configUrl.host && (configUrl.host.indexOf(':') < 0) && configUrl.port) { configUrl.hostname = configUrl.host; delete configUrl.host; } // for backward compatibility if (configUrl.username) { configUrl.user = configUrl.username; delete configUrl.username; } // for backward compatibility if (configUrl.accessKey) { configUrl.pwd = configUrl.accessKey; delete configUrl.accessKey; } // for backward compatibility if (configUrl.https) { configUrl.protocol = 'https:'; delete configUrl.https; } // for backward compatibility if (configUrl.path) { configUrl.pathname = configUrl.path; delete configUrl.path; } // setting auth from user/password if (configUrl.user && configUrl.pwd) { configUrl.auth = configUrl.user + ':' + configUrl.pwd; delete configUrl.user; delete configUrl.pwd; } _.defaults(configUrl, { protocol: 'http:', hostname: '127.0.0.1', port: '4444', pathname: '/wd/hub', }); // strip any trailing slashes from pathname const parsed = url.parse(url.format(configUrl), true); if (parsed.pathname[parsed.pathname.length - 1] === '/') { parsed.pathname = parsed.pathname.slice(0, parsed.pathname.length - 1); } return parsed; } // parses server parameters const parseRemoteWdConfig = function(args) { let config; if ((typeof args[0]) === 'object') { if (args[0].href && args[0].format) { // was constructed with url.parse, so we don't modify it config = args[0]; } else { config = buildConfigUrl(args[0]); } } else if ((typeof args[0]) === 'string' && (args[0].match(/^https?:\/\//))) { config = url.parse(args[0]); } else { config = buildConfigUrl({ hostname: args[0], port: args[1], user: args[2], pwd: args[3], }); } return config; }; let PromiseWebdriver, PromiseElement, PromiseChainWebdriver, PromiseChainElement; // Creates the Webdriver object // server parameters can be passed in 4 ways // - as a url string // - as a url object, constructed via url.parse // - as a list of arguments host,port, user, pwd // - as an option object containing the fields above // A `driverType` string may be passed at the end of the argument list. // If it is a valid type it will be detected even if the other arguments // are ommited. Valide types are: `remote`, `promise` and `promiseChain`. function remote() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; const driverProtos = { async: Webdriver, promise: PromiseWebdriver, promiseChain: PromiseChainWebdriver, }; const driverTypes = _(driverProtos).keys().value(); const driverType = driverTypes.indexOf(_(args).last()) > 0 ? args.pop() : 'async'; const rwc = parseRemoteWdConfig(args); return new (driverProtos[driverType])(rwc); } function wrap() { const promiseProtos = require('./promise-webdriver')(Webdriver, Element, false); PromiseWebdriver = promiseProtos.PromiseWebdriver; PromiseElement = promiseProtos.PromiseElement; const promiseChainProtos = require('./promise-webdriver')(Webdriver, Element, true); PromiseChainWebdriver = promiseChainProtos.PromiseWebdriver; PromiseChainElement = promiseChainProtos.PromiseElement; } // todo: allow adding element methods function addPromiseChainMethod(name, method) { const wrappedMethod = function() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; const promise = new Q(method.apply(this, args)); this._enrich(promise); return promise; }; PromiseChainWebdriver.prototype[name] = wrappedMethod; } function addElementPromiseChainMethod(name, method) { const wrappedMethod = function() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; const promise = new Q(method.apply(this, args)); this._enrich(promise); return promise; }; PromiseChainElement.prototype[name] = wrappedMethod; } function addPromiseMethod(name, method) { const wrappedMethod = function() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; return new Q(method.apply(this, args)); }; PromiseWebdriver.prototype[name] = wrappedMethod; addPromiseChainMethod(name, method); } function addElementPromiseMethod(name, method) { const wrappedMethod = function() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; return new Q(method.apply(this, args)); }; PromiseElement.prototype[name] = wrappedMethod; addElementPromiseChainMethod(name, method); } function addAsyncMethod(name, method) { Webdriver.prototype[name] = method; PromiseWebdriver.prototype[name] = PromiseWebdriver._wrapAsync(method); PromiseChainWebdriver.prototype[name] = PromiseChainWebdriver._wrapAsync(method); } function addElementAsyncMethod(name, method) { Element.prototype[name] = method; PromiseElement.prototype[name] = PromiseWebdriver._wrapAsync(method); PromiseChainElement.prototype[name] = PromiseChainWebdriver._wrapAsync(method); } function removeMethod(name) { delete Webdriver.prototype[name]; delete PromiseWebdriver.prototype[name]; delete PromiseChainWebdriver.prototype[name]; } // creates a webdriver object using the Q promise wrap not chained function asyncRemote() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; const rwc = parseRemoteWdConfig(args); return new Webdriver(rwc); } // creates a webdriver object using the Q promise wrap not chained function promiseRemote() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; const rwc = parseRemoteWdConfig(args); return new PromiseWebdriver(rwc); } // creates a webdriver object using the Q promise wrap chained function promiseChainRemote() { const args = arguments.length >= 1 ? __slice.call(arguments, 0) : []; const rwc = parseRemoteWdConfig(args); return new PromiseChainWebdriver(rwc); } // initial wrapping wrap(); module.exports = { // Retrieves browser remote, asyncRemote, // Retrieves wrap browser promiseRemote, promiseChainRemote, // Webdriver and Wrapper base classes Webdriver, webdriver: Webdriver, // for backward compatibility Element, PromiseChainWebdriver, PromiseWebdriver, TouchAction: actions.TouchAction, MultiAction: actions.MultiAction, // Actualizes promise wrappers rewrap() { deprecator.warn('rewrap', 'rewrap has been deprecated, use addAsyncMethod instead.'); wrap(); }, // config /** * wd.configureHttp(opts) * * opts example: * {timeout:60000, retries: 3, 'retryDelay': 15, baseUrl='http://example.com/'} * more info in README. * * @wd */ configureHttp: config.configureHttp, getHttpConfig() { return _(config.httpConfig).clone(); }, // deprecation /** * wd.showHideDeprecation(boolean) * * @wd */ showHideDeprecation: deprecator.showHideDeprecation.bind(deprecator), // add/remove methods /** * wd.addAsyncMethod(name, func) * * @wd */ addAsyncMethod, /** * wd.addElementAsyncMethod(name, func) * * @wd */ addElementAsyncMethod, /** * wd.addPromiseMethod(name, func) * * @wd */ addPromiseMethod, /** * wd.addElementPromiseMethod(name, func) * * @wd */ addElementPromiseMethod, /** * wd.addPromiseChainMethod(name, func) * * @wd */ addPromiseChainMethod, /** * wd.addElementPromiseChainMethod(name, func) * * @wd */ addElementPromiseChainMethod, /** * wd.removeMethod(name, func) * * @wd */ removeMethod, // Useful stuff Asserter: require('./asserters').Asserter, asserters: require('./asserters'), SPECIAL_KEYS, Q, findCallback: utils.findCallback, varargs: utils.varargs, transferPromiseness: utils.transferPromiseness, // This is for people who write wrapper // todo: That should not be needed. utils, setBaseClasses(_Webdriver, _Element) { Webdriver = _Webdriver; Element = _Element; wrap(); }, };