appium-xcuitest-driver-conan
Version:
Appium driver for iOS using XCUITest for backend
1,210 lines (986 loc) • 88.3 kB
JavaScript
'use strict';
var _slicedToArray = require('babel-runtime/helpers/sliced-to-array')['default'];
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _Object$assign = require('babel-runtime/core-js/object/assign')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
var _appiumBaseDriver = require('appium-base-driver');
var _appiumSupport = require('appium-support');
var _appiumIosDriver = require('appium-ios-driver');
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _logger = require('../logger');
var _logger2 = _interopRequireDefault(_logger);
var helpers = {},
extensions = {},
commands = {};
commands.moveTo = _appiumIosDriver.iosCommands.gesture.moveTo;
commands.click = function callee$0$0(el) {
var atomsElement;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (this.isWebContext()) {
context$1$0.next = 4;
break;
}
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.nativeClick(el));
case 3:
return context$1$0.abrupt('return', context$1$0.sent);
case 4:
el = _appiumSupport.util.unwrapElement(el);
if (!(this.opts.nativeWebTap && !this.isRealDevice())) {
context$1$0.next = 10;
break;
}
context$1$0.next = 8;
return _regeneratorRuntime.awrap(this.nativeWebTap(el));
case 8:
context$1$0.next = 14;
break;
case 10:
atomsElement = this.useAtomsElement(el);
context$1$0.next = 13;
return _regeneratorRuntime.awrap(this.executeAtom('click', [atomsElement]));
case 13:
return context$1$0.abrupt('return', context$1$0.sent);
case 14:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
function isSameGestures(gestures, candidates) {
try {
if (gestures.length !== candidates.length) {
return false;
}
for (var i = 0; i < gestures.length; i++) {
var gestureObj = gestures[i];
var candidateObj = candidates[i];
if (!_lodash2['default'].isPlainObject(gestureObj) || !_lodash2['default'].isPlainObject(candidateObj)) {
return false;
}
if (_lodash2['default'].difference(_lodash2['default'].keys(candidateObj), _lodash2['default'].keys(gestureObj)).length) {
return false;
}
if (gestureObj.action.toLowerCase() !== candidateObj.action.toLowerCase()) {
return false;
}
if (candidateObj.options && gestureObj.options.count !== candidateObj.options.count) {
return false;
}
}
} catch (err) {
_logger2['default'].debug('Error "' + err.message + '" while comparing gestures. Considering them as not equal');
return false;
}
return true;
}
function gesturesChainToString(gestures) {
var keysToInclude = arguments.length <= 1 || arguments[1] === undefined ? ['options'] : arguments[1];
return gestures.map(function (item) {
var otherKeys = _lodash2['default'].difference(_lodash2['default'].keys(item), ['action']);
otherKeys = _lodash2['default'].isArray(keysToInclude) ? _lodash2['default'].intersection(otherKeys, keysToInclude) : otherKeys;
if (otherKeys.length) {
return '' + item.action + ('(' + _lodash2['default'].map(otherKeys, function (x) {
return x + '=' + (_lodash2['default'].isPlainObject(item[x]) ? JSON.stringify(item[x]) : item[x]);
}).join(', ') + ')');
}
return item.action;
}).join('-');
}
commands.performTouch = function callee$0$0(gestures) {
var supportedGesturesMapping, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step$value, cmd, info, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, candidateMatch, availableGestures, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _step2$value, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
var _this = this;
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_logger2['default'].debug('Received the following touch action: ' + gesturesChainToString(gestures));
supportedGesturesMapping = {
doubleTap: {
handler: function handler(x) {
return _regeneratorRuntime.async(function handler$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.next = 2;
return _regeneratorRuntime.awrap(this.handleDoubleTap(x));
case 2:
case 'end':
return context$2$0.stop();
}
}, null, _this);
},
matches: [[{ action: 'doubletap' }], [{ action: 'tap', options: { count: 2 } }]]
},
tap: {
handler: function handler(x) {
return _regeneratorRuntime.async(function handler$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.next = 2;
return _regeneratorRuntime.awrap(this.handleTap(x[0]));
case 2:
case 'end':
return context$2$0.stop();
}
}, null, _this);
},
matches: [[{ action: 'tap' }], [{ action: 'tap' }, { action: 'release' }], [{ action: 'press' }, { action: 'release' }]]
},
longPress: {
handler: function handler(x) {
return _regeneratorRuntime.async(function handler$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.next = 2;
return _regeneratorRuntime.awrap(this.handleLongPress(x));
case 2:
case 'end':
return context$2$0.stop();
}
}, null, _this);
},
matches: [[{ action: 'longpress' }], [{ action: 'press' }, { action: 'wait' }, { action: 'release' }]]
},
drag: {
handler: function handler(x) {
return _regeneratorRuntime.async(function handler$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.next = 2;
return _regeneratorRuntime.awrap(this.handleDrag(x));
case 2:
case 'end':
return context$2$0.stop();
}
}, null, _this);
},
matches: [[{ action: 'press' }, { action: 'wait' }, { action: 'moveTo' }, { action: 'release' }]]
},
scroll: {
handler: function handler(x) {
return _regeneratorRuntime.async(function handler$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.next = 2;
return _regeneratorRuntime.awrap(this.handleScroll(x));
case 2:
case 'end':
return context$2$0.stop();
}
}, null, _this);
},
matches: [[{ action: 'press' }, { action: 'moveTo' }, { action: 'release' }]]
}
};
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
context$1$0.prev = 5;
_iterator = _getIterator(_lodash2['default'].toPairs(supportedGesturesMapping));
case 7:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
context$1$0.next = 43;
break;
}
_step$value = _slicedToArray(_step.value, 2);
cmd = _step$value[0];
info = _step$value[1];
_iteratorNormalCompletion3 = true;
_didIteratorError3 = false;
_iteratorError3 = undefined;
context$1$0.prev = 14;
_iterator3 = _getIterator(info.matches);
case 16:
if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
context$1$0.next = 26;
break;
}
candidateMatch = _step3.value;
if (!isSameGestures(gestures, candidateMatch)) {
context$1$0.next = 23;
break;
}
_logger2['default'].debug('Found matching gesture: ' + cmd);
context$1$0.next = 22;
return _regeneratorRuntime.awrap(info.handler(gestures));
case 22:
return context$1$0.abrupt('return', context$1$0.sent);
case 23:
_iteratorNormalCompletion3 = true;
context$1$0.next = 16;
break;
case 26:
context$1$0.next = 32;
break;
case 28:
context$1$0.prev = 28;
context$1$0.t0 = context$1$0['catch'](14);
_didIteratorError3 = true;
_iteratorError3 = context$1$0.t0;
case 32:
context$1$0.prev = 32;
context$1$0.prev = 33;
if (!_iteratorNormalCompletion3 && _iterator3['return']) {
_iterator3['return']();
}
case 35:
context$1$0.prev = 35;
if (!_didIteratorError3) {
context$1$0.next = 38;
break;
}
throw _iteratorError3;
case 38:
return context$1$0.finish(35);
case 39:
return context$1$0.finish(32);
case 40:
_iteratorNormalCompletion = true;
context$1$0.next = 7;
break;
case 43:
context$1$0.next = 49;
break;
case 45:
context$1$0.prev = 45;
context$1$0.t1 = context$1$0['catch'](5);
_didIteratorError = true;
_iteratorError = context$1$0.t1;
case 49:
context$1$0.prev = 49;
context$1$0.prev = 50;
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
case 52:
context$1$0.prev = 52;
if (!_didIteratorError) {
context$1$0.next = 55;
break;
}
throw _iteratorError;
case 55:
return context$1$0.finish(52);
case 56:
return context$1$0.finish(49);
case 57:
availableGestures = '';
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
context$1$0.prev = 61;
_iterator2 = _getIterator(_lodash2['default'].toPairs(supportedGesturesMapping));
case 63:
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
context$1$0.next = 90;
break;
}
_step2$value = _slicedToArray(_step2.value, 2);
cmd = _step2$value[0];
info = _step2$value[1];
availableGestures += '\t' + cmd + ': ';
_iteratorNormalCompletion4 = true;
_didIteratorError4 = false;
_iteratorError4 = undefined;
context$1$0.prev = 71;
for (_iterator4 = _getIterator(info.matches); !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
candidateMatch = _step4.value;
availableGestures += '\t\t' + gesturesChainToString(candidateMatch) + '\n';
}
context$1$0.next = 79;
break;
case 75:
context$1$0.prev = 75;
context$1$0.t2 = context$1$0['catch'](71);
_didIteratorError4 = true;
_iteratorError4 = context$1$0.t2;
case 79:
context$1$0.prev = 79;
context$1$0.prev = 80;
if (!_iteratorNormalCompletion4 && _iterator4['return']) {
_iterator4['return']();
}
case 82:
context$1$0.prev = 82;
if (!_didIteratorError4) {
context$1$0.next = 85;
break;
}
throw _iteratorError4;
case 85:
return context$1$0.finish(82);
case 86:
return context$1$0.finish(79);
case 87:
_iteratorNormalCompletion2 = true;
context$1$0.next = 63;
break;
case 90:
context$1$0.next = 96;
break;
case 92:
context$1$0.prev = 92;
context$1$0.t3 = context$1$0['catch'](61);
_didIteratorError2 = true;
_iteratorError2 = context$1$0.t3;
case 96:
context$1$0.prev = 96;
context$1$0.prev = 97;
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
case 99:
context$1$0.prev = 99;
if (!_didIteratorError2) {
context$1$0.next = 102;
break;
}
throw _iteratorError2;
case 102:
return context$1$0.finish(99);
case 103:
return context$1$0.finish(96);
case 104:
throw new _appiumBaseDriver.errors.NotYetImplementedError('Support for ' + gesturesChainToString(gestures) + ' gesture is not implemented. ' + 'Try to use "mobile: *" interface to workaround the issue. ' + ('Only these gestures are supported:\n' + availableGestures));
case 105:
case 'end':
return context$1$0.stop();
}
}, null, this, [[5, 45, 49, 57], [14, 28, 32, 40], [33,, 35, 39], [50,, 52, 56], [61, 92, 96, 104], [71, 75, 79, 87], [80,, 82, 86], [97,, 99, 103]]);
};
commands.performMultiAction = function callee$0$0(actions) {
var i;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_logger2['default'].debug('Received the following multi touch action:');
for (i in actions) {
_logger2['default'].debug(' ' + (i + 1) + ': ' + _lodash2['default'].map(actions[i], 'action').join('-'));
}
if (!isPinchOrZoom(actions)) {
context$1$0.next = 6;
break;
}
context$1$0.next = 5;
return _regeneratorRuntime.awrap(this.handlePinchOrZoom(actions));
case 5:
return context$1$0.abrupt('return', context$1$0.sent);
case 6:
throw new _appiumBaseDriver.errors.NotYetImplementedError('Support for this multi-action is not implemented. Try to use "mobile: *" interface to workaround the issue.');
case 7:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
commands.nativeClick = function callee$0$0(el) {
var endpoint;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
el = _appiumSupport.util.unwrapElement(el);
endpoint = '/element/' + el + '/click';
context$1$0.next = 4;
return _regeneratorRuntime.awrap(this.proxyCommand(endpoint, 'POST', {}));
case 4:
return context$1$0.abrupt('return', context$1$0.sent);
case 5:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
function isScroll(gestures) {
if (gestures.length === 3 && gestures[0].action === 'press' && gestures[1].action === 'moveTo' && gestures[2].action === 'release') {
return true;
}
return false;
}
function isPinchOrZoom() {
var actions = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
// symmetric two-finger action consisting of press-moveto-release
if (actions.length === 2) {
if (actions[0].length === 3 && actions[1].length === 3) {
return _lodash2['default'].every(actions, function (gestures) {
return isScroll(gestures);
});
}
}
return false;
}
helpers.handleScroll = function callee$0$0(gestures) {
var dragGestures;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (!gestures[1].options.element) {
context$1$0.next = 4;
break;
}
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.mobileScroll({
element: gestures[1].options.element,
toVisible: true
}));
case 3:
return context$1$0.abrupt('return', context$1$0.sent);
case 4:
dragGestures = [gestures[0], { action: 'wait', options: { ms: 0 } }, gestures[1], gestures[2]];
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.handleDrag(dragGestures));
case 7:
return context$1$0.abrupt('return', context$1$0.sent);
case 8:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.handleDrag = function callee$0$0(gestures) {
var press, wait, moveTo, pressCoordinates, duration, moveToCoordinates, params, endpoint;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
press = gestures[0];
wait = gestures[1];
moveTo = gestures[2];
context$1$0.next = 5;
return _regeneratorRuntime.awrap(this.getCoordinates(press));
case 5:
pressCoordinates = context$1$0.sent;
duration = parseInt(wait.options.ms, 10) / 1000;
context$1$0.next = 9;
return _regeneratorRuntime.awrap(this.getCoordinates(moveTo));
case 9:
moveToCoordinates = context$1$0.sent;
// update moveTo coordinates with offset
moveToCoordinates = this.applyMoveToOffset(pressCoordinates, moveToCoordinates);
// build drag command
params = {};
params.fromX = pressCoordinates.x;
params.fromY = pressCoordinates.y;
params.toX = moveToCoordinates.x;
params.toY = moveToCoordinates.y;
params.duration = duration;
endpoint = '/wda/dragfromtoforduration';
context$1$0.next = 20;
return _regeneratorRuntime.awrap(this.proxyCommand(endpoint, 'POST', params));
case 20:
return context$1$0.abrupt('return', context$1$0.sent);
case 21:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.handleTap = function callee$0$0(gesture) {
var options, params, el, endpoint;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
options = gesture.options || {};
params = {};
if (_appiumSupport.util.hasValue(options.x) && _appiumSupport.util.hasValue(options.y)) {
params.x = options.x;
params.y = options.y;
}
el = _appiumSupport.util.hasValue(options.element) ? options.element : '0';
endpoint = '/wda/tap/' + el;
if (_appiumSupport.util.hasValue(this.opts.tapWithShortPressDuration)) {
// in some cases `tap` is too slow, so allow configurable long press
_logger2['default'].debug('Translating tap into long press with \'' + this.opts.tapWithShortPressDuration + '\' duration');
params.duration = parseFloat(this.opts.tapWithShortPressDuration);
endpoint = '/wda/element/' + el + '/touchAndHold';
params.duration = parseFloat(this.opts.tapWithShortPressDuration);
}
context$1$0.next = 8;
return _regeneratorRuntime.awrap(this.proxyCommand(endpoint, 'POST', params));
case 8:
return context$1$0.abrupt('return', context$1$0.sent);
case 9:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.handleDoubleTap = function callee$0$0(gestures) {
var gesture, opts, el, endpoint;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
gesture = gestures[0];
opts = gesture.options || {};
if (!opts.element) {
_logger2['default'].errorAndThrow('WDA double tap needs an element');
}
el = _appiumSupport.util.unwrapElement(opts.element);
endpoint = '/wda/element/' + el + '/doubleTap';
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.proxyCommand(endpoint, 'POST'));
case 7:
return context$1$0.abrupt('return', context$1$0.sent);
case 8:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.handleLongPress = function callee$0$0(gestures) {
var pressOpts, el, duration, params, endpoint;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
pressOpts = gestures[0].options || {};
el = _appiumSupport.util.unwrapElement(pressOpts.element);
duration = undefined;
// In seconds (not milliseconds)
if (gestures.length === 1 && _appiumSupport.util.hasValue(pressOpts.duration)) {
duration = pressOpts.duration / 1000;
} else if (gestures.length === 3) {
// duration is the `wait` action
// upstream system expects seconds not milliseconds
duration = parseFloat(gestures[1].options.ms) / 1000;
} else {
// give a sane default duration
duration = 0.8;
}
params = {
duration: duration,
x: pressOpts.x,
y: pressOpts.y
};
endpoint = undefined;
if (el) {
endpoint = '/wda/element/' + el + '/touchAndHold';
} else {
params.x = pressOpts.x;
params.y = pressOpts.y;
endpoint = '/wda/touchAndHold';
}
context$1$0.next = 9;
return _regeneratorRuntime.awrap(this.proxyCommand(endpoint, 'POST', params));
case 9:
return context$1$0.abrupt('return', context$1$0.sent);
case 10:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
function determinePinchScale(x, y, pinch) {
var scale = x > y ? x - y : y - x;
if (pinch) {
// TODO: revisit this when pinching actually works, since it is impossible to
// know what the scale factor does at this point (Xcode 8.1)
scale = 1 / scale;
if (scale < 0.02) {
// this is the minimum that Apple will allow
// but WDA will not throw an error if it is too low
scale = 0.02;
}
} else {
// for zoom, each 10px is one scale factor
scale = scale / 10;
}
return scale;
}
helpers.handlePinchOrZoom = function callee$0$0(actions) {
var el, scale, velocity, thumb, forefinger, params;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
// currently we can only do this action on an element
if (!actions[0][0].options.element || actions[0][0].options.element !== actions[1][0].options.element) {
_logger2['default'].errorAndThrow('Pinch/zoom actions must be done on a single element');
}
el = actions[0][0].options.element;
scale = undefined, velocity = undefined;
if (actions[0][0].options.y === actions[0][1].options.y) {
thumb = actions[0][0].options.x <= actions[1][0].options.x ? actions[0] : actions[1];
// now decipher pinch vs. zoom,
// pinch: thumb moving from left to right
// zoom: thumb moving from right to left
scale = determinePinchScale(thumb[0].options.x, thumb[1].options.x, thumb[0].options.x <= thumb[1].options.x);
} else {
forefinger = actions[0][0].options.y <= actions[1][0].options.y ? actions[0] : actions[1];
// now decipher pinch vs. zoom
// pinch: forefinger moving from top to bottom
// zoom: forefinger moving from bottom to top
scale = determinePinchScale(forefinger[0].options.y, forefinger[1].options.y, forefinger[0].options.y <= forefinger[1].options.y);
}
velocity = scale < 1 ? -1 : 1;
_logger2['default'].debug('Decoded ' + (scale < 1 ? 'pinch' : 'zoom') + ' action with scale \'' + scale + '\' and velocity \'' + velocity + '\'');
if (scale < 1) {
_logger2['default'].warn('Pinch actions may not work, due to Apple issue.');
}
params = {
scale: scale,
velocity: velocity
};
context$1$0.next = 10;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/element/' + el + '/pinch', 'POST', params));
case 10:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
/*
* See https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Commands/FBElementCommands.m
* to get the info about available WDA gestures API
*
* See https://developer.apple.com/reference/xctest/xcuielement and
* https://developer.apple.com/reference/xctest/xcuicoordinate to get the detailed description of
* all XCTest gestures
*/
helpers.mobileScroll = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var swipe = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var params, msg, element, endpoint;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (opts.element) {
context$1$0.next = 4;
break;
}
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.findNativeElementOrElements('class name', 'XCUIElementTypeApplication', false));
case 3:
opts.element = context$1$0.sent;
case 4:
params = {};
if (opts.name && !swipe) {
params.name = opts.name;
} else if (opts.direction) {
if (['up', 'down', 'left', 'right'].indexOf(opts.direction.toLowerCase()) < 0) {
msg = 'Direction must be up, down, left or right';
_logger2['default'].errorAndThrow(msg);
}
params.direction = opts.direction;
} else if (opts.predicateString && !swipe) {
params.predicateString = opts.predicateString;
} else if (opts.toVisible && !swipe) {
params.toVisible = opts.toVisible;
} else {
msg = swipe ? 'Mobile swipe requires direction' : 'Mobile scroll supports the following strategies: name, direction, predicateString, and toVisible. Specify one of these';
_logger2['default'].errorAndThrow(msg);
}
element = opts.element.ELEMENT || opts.element;
endpoint = '/wda/element/' + element + '/' + (swipe ? 'swipe' : 'scroll');
context$1$0.next = 10;
return _regeneratorRuntime.awrap(this.proxyCommand(endpoint, 'POST', params));
case 10:
return context$1$0.abrupt('return', context$1$0.sent);
case 11:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
function parseFloatParameter(paramName, paramValue, methodName) {
if (_lodash2['default'].isUndefined(paramValue)) {
_logger2['default'].errorAndThrow('"' + paramName + '" parameter is mandatory for "' + methodName + '" call');
}
var result = parseFloat(paramValue);
if (isNaN(result)) {
_logger2['default'].errorAndThrow('"' + paramName + '" parameter should be a valid number. "' + paramValue + '" is given instead');
}
return result;
}
helpers.mobilePinch = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var params, el;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (opts.element) {
context$1$0.next = 4;
break;
}
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.findNativeElementOrElements('class name', 'XCUIElementTypeApplication', false));
case 3:
opts.element = context$1$0.sent;
case 4:
params = {
scale: parseFloatParameter('scale', opts.scale, 'pinch'),
velocity: parseFloatParameter('velocity', opts.velocity, 'pinch')
};
el = opts.element.ELEMENT || opts.element;
context$1$0.next = 8;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/element/' + el + '/pinch', 'POST', params));
case 8:
return context$1$0.abrupt('return', context$1$0.sent);
case 9:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.mobileDoubleTap = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var el, params;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (!opts.element) {
context$1$0.next = 5;
break;
}
el = opts.element.ELEMENT || opts.element;
context$1$0.next = 4;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/element/' + el + '/doubleTap', 'POST'));
case 4:
return context$1$0.abrupt('return', context$1$0.sent);
case 5:
params = {
x: parseFloatParameter('x', opts.x, 'doubleTap'),
y: parseFloatParameter('y', opts.y, 'doubleTap')
};
context$1$0.next = 8;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/doubleTap', 'POST', params));
case 8:
return context$1$0.abrupt('return', context$1$0.sent);
case 9:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.mobileTwoFingerTap = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var el;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (opts.element) {
context$1$0.next = 4;
break;
}
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.findNativeElementOrElements('class name', 'XCUIElementTypeApplication', false));
case 3:
opts.element = context$1$0.sent;
case 4:
el = opts.element.ELEMENT || opts.element;
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/element/' + el + '/twoFingerTap', 'POST'));
case 7:
return context$1$0.abrupt('return', context$1$0.sent);
case 8:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.mobileTouchAndHold = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var params, el;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
params = {
duration: parseFloatParameter('duration', opts.duration, 'touchAndHold')
};
if (!opts.element) {
context$1$0.next = 6;
break;
}
el = opts.element.ELEMENT || opts.element;
context$1$0.next = 5;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/element/' + el + '/touchAndHold', 'POST', params));
case 5:
return context$1$0.abrupt('return', context$1$0.sent);
case 6:
// Long tap coordinates
params.x = parseFloatParameter('x', opts.x, 'touchAndHold');
params.y = parseFloatParameter('y', opts.y, 'touchAndHold');
context$1$0.next = 10;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/touchAndHold', 'POST', params));
case 10:
return context$1$0.abrupt('return', context$1$0.sent);
case 11:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.mobileTap = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var params, el;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
params = {
x: parseFloatParameter('x', opts.x, 'tap'),
y: parseFloatParameter('y', opts.y, 'tap')
};
el = opts.element ? opts.element.ELEMENT || opts.element : '0';
context$1$0.next = 4;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/tap/' + el, 'POST', params));
case 4:
return context$1$0.abrupt('return', context$1$0.sent);
case 5:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.mobileDragFromToForDuration = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var params, el;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
params = {
duration: parseFloatParameter('duration', opts.duration, 'dragFromToForDuration'),
fromX: parseFloatParameter('fromX', opts.fromX, 'dragFromToForDuration'),
fromY: parseFloatParameter('fromY', opts.fromY, 'dragFromToForDuration'),
toX: parseFloatParameter('toX', opts.toX, 'dragFromToForDuration'),
toY: parseFloatParameter('toY', opts.toY, 'dragFromToForDuration')
};
if (!opts.element) {
context$1$0.next = 6;
break;
}
el = opts.element.ELEMENT || opts.element;
context$1$0.next = 5;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/element/' + el + '/dragfromtoforduration', 'POST', params));
case 5:
return context$1$0.abrupt('return', context$1$0.sent);
case 6:
context$1$0.next = 8;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/dragfromtoforduration', 'POST', params));
case 8:
return context$1$0.abrupt('return', context$1$0.sent);
case 9:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.mobileSelectPickerWheelValue = function callee$0$0() {
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var el, params;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (!opts.element) {
_logger2['default'].errorAndThrow('Element id is expected to be set for selectPickerWheelValue method');
}
if (!_lodash2['default'].isString(opts.order) || ['next', 'previous'].indexOf(opts.order.toLowerCase()) === -1) {
_logger2['default'].errorAndThrow('The mandatory "order" parameter is expected to be equal either to \'next\' or \'previous\'. ' + ('\'' + opts.order + '\' is given instead'));
}
el = opts.element.ELEMENT || opts.element;
params = { order: opts.order };
if (opts.offset) {
params.offset = parseFloatParameter('offset', opts.offset, 'selectPickerWheelValue');
}
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.proxyCommand('/wda/pickerwheel/' + el + '/select', 'POST', params));
case 7:
return context$1$0.abrupt('return', context$1$0.sent);
case 8:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.getCoordinates = function callee$0$0(gesture) {
var el, coordinates, optionX, optionY, rect, pos, size, offsetX, offsetY;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
el = gesture.options.element;
coordinates = { x: 0, y: 0, areOffsets: false };
optionX = null;
if (gesture.options.x) {
optionX = parseFloatParameter('x', gesture.options.x, 'getCoordinates');
}
optionY = null;
if (gesture.options.y) {
optionY = parseFloatParameter('y', gesture.options.y, 'getCoordinates');
}
// figure out the element coordinates.
if (!el) {
context$1$0.next = 19;
break;
}
context$1$0.next = 9;
return _regeneratorRuntime.awrap(this.getRect(el));
case 9:
rect = context$1$0.sent;
pos = { x: rect.x, y: rect.y };
size = { w: rect.width, h: rect.height };
offsetX = 0;
offsetY = 0;
// get the real offsets
if (optionX || optionY) {
offsetX = optionX || 0;
offsetY = optionY || 0;
} else {
offsetX = size.w / 2;
offsetY = size.h / 2;
}
// apply the offsets
coordinates.x = pos.x + offsetX;
coordinates.y = pos.y + offsetY;
context$1$0.next = 22;
break;
case 19:
// moveTo coordinates are passed in as offsets
coordinates.areOffsets = gesture.action === 'moveTo';
coordinates.x = optionX || 0;
coordinates.y = optionY || 0;
case 22:
return context$1$0.abrupt('return', coordinates);
case 23:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
helpers.applyMoveToOffset = function (firstCoordinates, secondCoordinates) {
if (secondCoordinates.areOffsets) {
return {
x: firstCoordinates.x + secondCoordinates.x,
y: firstCoordinates.y + secondCoordinates.y
};
} else {
return secondCoordinates;
}
};
_Object$assign(extensions, helpers, commands);
exports.extensions = extensions;
exports.helpers = helpers;
exports.commands = commands;
exports.isSameGestures = isSameGestures;
exports.gesturesChainToString = gesturesChainToString;
exports['default'] = extensions;
// there are multiple commands that map here, so manually proxy
// atoms-based clicks don't always work in safari 7
// use the to-visible option of scrolling in WDA
// otherwise, for now, just translate into a drag with short duration
// get gestures
// get drag data
// assume that action is in a single plane (x or y, not horizontal at all)
// terminology all assuming right handedness
// horizontal, since y offset is the same in press and moveTo
// vertical
// WDA supports four scrolling strategies: predication based on name, direction,
// predicateString, and toVisible, in that order. Swiping requires direction.
// Double tap element
// Double tap coordinates
// Long tap element
// Drag element
// Drag coordinates
// defaults
// defaults
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9jb21tYW5kcy9nZXN0dXJlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Z0NBQXVCLG9CQUFvQjs7NkJBQ3RCLGdCQUFnQjs7K0JBQ1QsbUJBQW1COztzQkFDakMsUUFBUTs7OztzQkFDTixXQUFXOzs7O0FBRzNCLElBQUksT0FBTyxHQUFHLEVBQUU7SUFBRSxVQUFVLEdBQUcsRUFBRTtJQUFFLFFBQVEsR0FBRyxFQUFFLENBQUM7O0FBRWpELFFBQVEsQ0FBQyxNQUFNLEdBQUcsNkJBQVksT0FBTyxDQUFDLE1BQU0sQ0FBQzs7QUFFN0MsUUFBUSxDQUFDLEtBQUssR0FBRyxvQkFBZ0IsRUFBRTtNQVUzQixZQUFZOzs7O1lBVGIsSUFBSSxDQUFDLFlBQVksRUFBRTs7Ozs7O3lDQUVULElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDOzs7Ozs7QUFFbkMsVUFBRSxHQUFHLG9CQUFLLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQzs7Y0FDeEIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUE7Ozs7Ozt5Q0FFMUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7Ozs7Ozs7QUFFdkIsb0JBQVksR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQzs7eUNBQzlCLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUM7Ozs7Ozs7Ozs7Q0FFekQsQ0FBQzs7QUFFRixTQUFTLGNBQWMsQ0FBRSxRQUFRLEVBQUUsVUFBVSxFQUFFO0FBQzdDLE1BQUk7QUFDRixRQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssVUFBVSxDQUFDLE1BQU0sRUFBRTtBQUN6QyxhQUFPLEtBQUssQ0FBQztLQUNkO0FBQ0QsU0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFF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