Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | 2x 23x 23x 23x 23x 23x 23x 23x 23x 23x 4x 21x 16x 5x 5x 23x 23x 23x 23x 23x 22x 23x 11x 23x 3x 3x 2x 1x 1x 2x 1x 23x 4x 4x 2x 1x 1x 1x 2x 1x 1x 1x 1x 23x 23x 2x 2x 2x 2x 2x 2x 2x 2x 23x 414x 12x 12x 23x | import { EventEmitter } from 'events' import logger from '@wdio/logger' import { commandCallStructure, overwriteElementCommands } from './utils' const SCOPE_TYPES = { 'browser': /* istanbul ignore next */ function Browser () {}, 'element': /* istanbul ignore next */ function Element () {} } export default function WebDriver (options, modifier, propertiesObject = {}) { /** * In order to allow named scopes for elements we have to propagate that * info within the `propertiesObject` object. This doesn't have any functional * advantages just provides better description of objects when debugging them */ const scopeType = SCOPE_TYPES[propertiesObject.scope] || SCOPE_TYPES['browser'] delete propertiesObject.scope const prototype = Object.create(scopeType.prototype) const log = logger('webdriver') const eventHandler = new EventEmitter() const EVENTHANDLER_FUNCTIONS = Object.getPrototypeOf(eventHandler) /** * WebDriver monad */ function unit (sessionId, commandWrapper) { propertiesObject.commandList = { value: Object.keys(propertiesObject) } propertiesObject.options = { value: options } /** * allow to wrap commands if necessary * e.g. in wdio-cli to make them synchronous */ if (typeof commandWrapper === 'function') { for (const [commandName, { value }] of Object.entries(propertiesObject)) { if (typeof value !== 'function') { continue } propertiesObject[commandName].value = commandWrapper(commandName, value) propertiesObject[commandName].configurable = true } } /** * overwrite native element commands with user defined */ overwriteElementCommands.call(this, propertiesObject) /** * assign propertiesObject to itself so the client can be recreated */ propertiesObject['__propertiesObject__'] = { value: propertiesObject } let client = Object.create(prototype, propertiesObject) client.sessionId = sessionId /** * register capabilities only to browser scope */ if (scopeType.name === 'Browser') { client.capabilities = options.capabilities } if (typeof modifier === 'function') { client = modifier(client, options) } client.addCommand = function (name, func, attachToElement = false, proto, instances) { const customCommand = typeof commandWrapper === 'function' ? commandWrapper(name, func) : func if (attachToElement) { /** * add command to every multiremote instance */ if (instances) { Object.values(instances).forEach(instance => { instance.__propertiesObject__[name] = { value: customCommand } }) } this.__propertiesObject__[name] = { value: customCommand } } else { unit.lift(name, customCommand, proto) } } /** * overwriteCommand * @param {String} name command name to be overwritten * @param {Function} func function to replace original command with; * takes original function as first argument. * @param {boolean=} attachToElement overwrite browser command (false) or element command (true) * @param {Object=} proto prototype to add function to (optional) * @param {Object=} instances multiremote instances */ client.overwriteCommand = function (name, func, attachToElement = false, proto, instances) { let customCommand = typeof commandWrapper === 'function' ? commandWrapper(name, func) : func if (attachToElement) { if (instances) { /** * add command to every multiremote instance */ Object.values(instances).forEach(instance => { instance.__propertiesObject__.__elementOverrides__.value[name] = customCommand }) } else { /** * regular mode */ this.__propertiesObject__.__elementOverrides__.value[name] = customCommand } } else if (client[name]) { const origCommand = client[name] delete client[name] unit.lift(name, customCommand, proto, (...args) => origCommand.apply(this, args)) } else { throw new Error('overwriteCommand: no command to be overwritten: ' + name) } } return client } /** * Enhance monad prototype with function * @param {String} name name of function to attach to prototype * @param {Function} func function to be added to prototype * @param {Object} proto prototype to add function to (optional) * @param {Function} origCommand original command to be passed to custom command as first argument */ unit.lift = function (name, func, proto, origCommand) { (proto || prototype)[name] = function next (...args) { log.info('COMMAND', commandCallStructure(name, args)) /** * set name of function for better error stack */ Object.defineProperty(func, 'name', { value: name, writable: false, }) const result = func.apply(this, origCommand ? [origCommand, ...args] : args) /** * always transform result into promise as we don't know whether or not * the user is running tests with wdio-sync or not */ Promise.resolve(result).then((res) => { log.info('RESULT', res) this.emit('result', { name, result: res }) }).catch(() => {}) return result } } /** * register event emitter */ for (let eventCommand in EVENTHANDLER_FUNCTIONS) { prototype[eventCommand] = function (...args) { eventHandler[eventCommand](...args) return this } } return unit } |