6725 lines
345 KiB
JavaScript
6725 lines
345 KiB
JavaScript
|
window['%hammerhead%'].utils.removeInjectedScript();
|
||
|
|
||
|
// NOTE: We should have the capability to initialize scripts with different contexts.
|
||
|
// This is required for iframes without the src attribute because Hammerhead does not
|
||
|
// inject scripts into such iframes. So, we wrap all scripts in initialization functions.
|
||
|
(function () {
|
||
|
function initTestCafeAutomation(window, isIFrameWithoutSrc) {
|
||
|
var document = window.document;
|
||
|
|
||
|
(function (hammerhead, Promise$e, testCafeCore, testCafeUI) {
|
||
|
var hammerhead__default = 'default' in hammerhead ? hammerhead['default'] : hammerhead;
|
||
|
Promise$e = Promise$e && Object.prototype.hasOwnProperty.call(Promise$e, 'default') ? Promise$e['default'] : Promise$e;
|
||
|
var testCafeCore__default = 'default' in testCafeCore ? testCafeCore['default'] : testCafeCore;
|
||
|
testCafeUI = testCafeUI && Object.prototype.hasOwnProperty.call(testCafeUI, 'default') ? testCafeUI['default'] : testCafeUI;
|
||
|
|
||
|
var nativeMethods = hammerhead__default.nativeMethods;
|
||
|
var MOUSE_EVENT_NAME_RE = /^((mouse\w+)|((dbl)?click)|(contextmenu))$/;
|
||
|
var DRAG_EVENT_NAME_RE = /^((drag\w*)|(drop))$/;
|
||
|
var KEY_EVENT_NAME_RE = /^key\w+$/;
|
||
|
var INPUT_EVENT_NAME_RE = /^(before)?input$/;
|
||
|
var FOCUS_EVENT_NAME_RE = /^(blur|(focus(in|out)?))$/;
|
||
|
var POINTER_EVENT_NAME_RE = /^pointer\w+/;
|
||
|
var DEFAULT_MOUSE_EVENT_DETAIL_PROP_VALUE = {
|
||
|
click: 1,
|
||
|
dblclick: 2,
|
||
|
mousedown: 1,
|
||
|
mouseup: 1,
|
||
|
};
|
||
|
// NOTE: default e.buttons for left button pressed
|
||
|
var DEFAULT_BUTTONS_PARAMETER = 1;
|
||
|
var EVENT_CTORS = {
|
||
|
MouseEvent: 'MouseEvent',
|
||
|
PointerEvent: 'PointerEvent',
|
||
|
KeyboardEvent: 'KeyboardEvent',
|
||
|
InputEvent: 'InputEvent',
|
||
|
FocusEvent: 'FocusEvent',
|
||
|
};
|
||
|
var DispatchEventAutomation = /** @class */ (function () {
|
||
|
function DispatchEventAutomation(element, eventName, options) {
|
||
|
this.element = element;
|
||
|
this.eventName = eventName;
|
||
|
this.options = options;
|
||
|
}
|
||
|
DispatchEventAutomation.prototype.run = function () {
|
||
|
var _a = this.options, bubbles = _a.bubbles, cancelable = _a.cancelable, detail = _a.detail, view = _a.view, buttons = _a.buttons;
|
||
|
bubbles = bubbles !== false;
|
||
|
cancelable = cancelable !== false;
|
||
|
detail = detail || DEFAULT_MOUSE_EVENT_DETAIL_PROP_VALUE[this.eventName];
|
||
|
view = window;
|
||
|
buttons = buttons === void 0 ? DEFAULT_BUTTONS_PARAMETER : buttons;
|
||
|
// eslint-disable-next-line no-restricted-globals
|
||
|
Object.assign(this.options, { bubbles: bubbles, cancelable: cancelable, detail: detail, view: view, buttons: buttons });
|
||
|
var Ctor = DispatchEventAutomation._getEventCtorByEventType(this.eventName, this.options.eventConstructor);
|
||
|
if (Ctor) {
|
||
|
var event_1 = new Ctor(this.eventName, this.options);
|
||
|
this.element.dispatchEvent(event_1);
|
||
|
}
|
||
|
};
|
||
|
DispatchEventAutomation._getEventCtorByEventType = function (eventName, eventConstructor) {
|
||
|
if (eventConstructor && typeof DispatchEventAutomation._getEventCtorFromWindow(eventConstructor) === 'function') {
|
||
|
var Ctor = DispatchEventAutomation._getEventCtorFromNativeMethods(eventConstructor);
|
||
|
if (Ctor && typeof Ctor === 'function')
|
||
|
return Ctor;
|
||
|
}
|
||
|
if (MOUSE_EVENT_NAME_RE.test(eventName))
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods(EVENT_CTORS.MouseEvent);
|
||
|
if (DRAG_EVENT_NAME_RE.test(eventName))
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods(EVENT_CTORS.MouseEvent);
|
||
|
if (POINTER_EVENT_NAME_RE.test(eventName))
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods(EVENT_CTORS.PointerEvent);
|
||
|
if (KEY_EVENT_NAME_RE.test(eventName))
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods(EVENT_CTORS.KeyboardEvent);
|
||
|
if (INPUT_EVENT_NAME_RE.test(eventName))
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods(EVENT_CTORS.InputEvent);
|
||
|
if (FOCUS_EVENT_NAME_RE.test(eventName))
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods(EVENT_CTORS.FocusEvent);
|
||
|
return DispatchEventAutomation._getEventCtorFromNativeMethods('CustomEvent');
|
||
|
};
|
||
|
DispatchEventAutomation._getEventCtorFromNativeMethods = function (eventCtor) {
|
||
|
var ctor = nativeMethods['Window' + eventCtor] || DispatchEventAutomation._getEventCtorFromWindow(eventCtor);
|
||
|
return ctor;
|
||
|
};
|
||
|
DispatchEventAutomation._getEventCtorFromWindow = function (eventCtor) {
|
||
|
// @ts-ignore
|
||
|
return window[eventCtor];
|
||
|
};
|
||
|
return DispatchEventAutomation;
|
||
|
}());
|
||
|
|
||
|
/******************************************************************************
|
||
|
Copyright (c) Microsoft Corporation.
|
||
|
|
||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||
|
purpose with or without fee is hereby granted.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||
|
PERFORMANCE OF THIS SOFTWARE.
|
||
|
***************************************************************************** */
|
||
|
/* global Reflect, Promise */
|
||
|
var extendStatics = function (d, b) {
|
||
|
extendStatics = Object.setPrototypeOf ||
|
||
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||
|
function (d, b) { for (var p in b)
|
||
|
if (Object.prototype.hasOwnProperty.call(b, p))
|
||
|
d[p] = b[p]; };
|
||
|
return extendStatics(d, b);
|
||
|
};
|
||
|
function __extends(d, b) {
|
||
|
if (typeof b !== "function" && b !== null)
|
||
|
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||
|
extendStatics(d, b);
|
||
|
function __() { this.constructor = d; }
|
||
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||
|
}
|
||
|
function __awaiter(thisArg, _arguments, P, generator) {
|
||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||
|
return new (P || (P = Promise$e))(function (resolve, reject) {
|
||
|
function fulfilled(value) { try {
|
||
|
step(generator.next(value));
|
||
|
}
|
||
|
catch (e) {
|
||
|
reject(e);
|
||
|
} }
|
||
|
function rejected(value) { try {
|
||
|
step(generator["throw"](value));
|
||
|
}
|
||
|
catch (e) {
|
||
|
reject(e);
|
||
|
} }
|
||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||
|
});
|
||
|
}
|
||
|
function __generator(thisArg, body) {
|
||
|
var _ = { label: 0, sent: function () { if (t[0] & 1)
|
||
|
throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
|
||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||
|
function step(op) {
|
||
|
if (f)
|
||
|
throw new TypeError("Generator is already executing.");
|
||
|
while (g && (g = 0, op[0] && (_ = 0)), _)
|
||
|
try {
|
||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
|
||
|
return t;
|
||
|
if (y = 0, t)
|
||
|
op = [op[0] & 2, t.value];
|
||
|
switch (op[0]) {
|
||
|
case 0:
|
||
|
case 1:
|
||
|
t = op;
|
||
|
break;
|
||
|
case 4:
|
||
|
_.label++;
|
||
|
return { value: op[1], done: false };
|
||
|
case 5:
|
||
|
_.label++;
|
||
|
y = op[1];
|
||
|
op = [0];
|
||
|
continue;
|
||
|
case 7:
|
||
|
op = _.ops.pop();
|
||
|
_.trys.pop();
|
||
|
continue;
|
||
|
default:
|
||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
||
|
_ = 0;
|
||
|
continue;
|
||
|
}
|
||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
|
||
|
_.label = op[1];
|
||
|
break;
|
||
|
}
|
||
|
if (op[0] === 6 && _.label < t[1]) {
|
||
|
_.label = t[1];
|
||
|
t = op;
|
||
|
break;
|
||
|
}
|
||
|
if (t && _.label < t[2]) {
|
||
|
_.label = t[2];
|
||
|
_.ops.push(op);
|
||
|
break;
|
||
|
}
|
||
|
if (t[2])
|
||
|
_.ops.pop();
|
||
|
_.trys.pop();
|
||
|
continue;
|
||
|
}
|
||
|
op = body.call(thisArg, _);
|
||
|
}
|
||
|
catch (e) {
|
||
|
op = [6, e];
|
||
|
y = 0;
|
||
|
}
|
||
|
finally {
|
||
|
f = t = 0;
|
||
|
}
|
||
|
if (op[0] & 5)
|
||
|
throw op[1];
|
||
|
return { value: op[0] ? op[1] : void 0, done: true };
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var AxisValues = /** @class */ (function () {
|
||
|
function AxisValues(x, y) {
|
||
|
this.x = x;
|
||
|
this.y = y;
|
||
|
}
|
||
|
AxisValues.create = function (a) {
|
||
|
if ('left' in a)
|
||
|
return new AxisValues(a.left, a.top);
|
||
|
else if ('right' in a)
|
||
|
return new AxisValues(a.right, a.bottom);
|
||
|
return new AxisValues(a.x, a.y);
|
||
|
};
|
||
|
AxisValues.prototype.add = function (p) {
|
||
|
this.x += p.x;
|
||
|
this.y += p.y;
|
||
|
return this;
|
||
|
};
|
||
|
AxisValues.prototype.sub = function (p) {
|
||
|
this.x -= p.x;
|
||
|
this.y -= p.y;
|
||
|
return this;
|
||
|
};
|
||
|
AxisValues.prototype.round = function (fn) {
|
||
|
if (fn === void 0) { fn = Math.round; }
|
||
|
this.x = fn(this.x);
|
||
|
this.y = fn(this.y);
|
||
|
return this;
|
||
|
};
|
||
|
AxisValues.prototype.eql = function (p) {
|
||
|
return this.x === p.x && this.y === p.y;
|
||
|
};
|
||
|
AxisValues.prototype.mul = function (n) {
|
||
|
this.x *= n;
|
||
|
this.y *= n;
|
||
|
return this;
|
||
|
};
|
||
|
AxisValues.prototype.distance = function (p) {
|
||
|
return Math.sqrt(Math.pow(this.x - p.x, 2) + Math.pow(this.y - p.y, 2));
|
||
|
};
|
||
|
return AxisValues;
|
||
|
}());
|
||
|
|
||
|
var ARRAY_METHODS_PREFIX = 'array';
|
||
|
function createNativeMethodWrapper(methodName) {
|
||
|
var nativeMethodName = ARRAY_METHODS_PREFIX + methodName.charAt(0).toUpperCase() + methodName.slice(1);
|
||
|
var nativeMethod = hammerhead.nativeMethods[nativeMethodName];
|
||
|
return function () {
|
||
|
var args = [];
|
||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||
|
args[_i] = arguments[_i];
|
||
|
}
|
||
|
return nativeMethod.call.apply(nativeMethod, args);
|
||
|
};
|
||
|
}
|
||
|
var filter = createNativeMethodWrapper('filter');
|
||
|
var map = createNativeMethodWrapper('map');
|
||
|
var slice = createNativeMethodWrapper('slice');
|
||
|
var splice = createNativeMethodWrapper('splice');
|
||
|
var unshift = createNativeMethodWrapper('unshift');
|
||
|
var forEach = createNativeMethodWrapper('forEach');
|
||
|
var indexOf = createNativeMethodWrapper('indexOf');
|
||
|
var some = createNativeMethodWrapper('some');
|
||
|
var reverse = createNativeMethodWrapper('reverse');
|
||
|
var reduce = createNativeMethodWrapper('reduce');
|
||
|
var concat = createNativeMethodWrapper('concat');
|
||
|
var join = createNativeMethodWrapper('join');
|
||
|
|
||
|
var browserUtils = hammerhead__default.utils.browser;
|
||
|
var nativeMethods$1 = hammerhead__default.nativeMethods;
|
||
|
// NOTE: We have to retrieve styleUtils.get from hammerhead
|
||
|
// to avoid circular dependencies between domUtils and styleUtils
|
||
|
var getElementStyleProperty = hammerhead__default.utils.style.get;
|
||
|
var getActiveElement = hammerhead__default.utils.dom.getActiveElement;
|
||
|
var findDocument = hammerhead__default.utils.dom.findDocument;
|
||
|
var find = hammerhead__default.utils.dom.find;
|
||
|
var isElementInDocument = hammerhead__default.utils.dom.isElementInDocument;
|
||
|
var isElementInIframe = hammerhead__default.utils.dom.isElementInIframe;
|
||
|
var getIframeByElement = hammerhead__default.utils.dom.getIframeByElement;
|
||
|
var isCrossDomainWindows = hammerhead__default.utils.dom.isCrossDomainWindows;
|
||
|
var getSelectParent = hammerhead__default.utils.dom.getSelectParent;
|
||
|
var getChildVisibleIndex = hammerhead__default.utils.dom.getChildVisibleIndex;
|
||
|
var getSelectVisibleChildren = hammerhead__default.utils.dom.getSelectVisibleChildren;
|
||
|
var isElementNode = hammerhead__default.utils.dom.isElementNode;
|
||
|
var isTextNode = hammerhead__default.utils.dom.isTextNode;
|
||
|
var isRenderedNode = hammerhead__default.utils.dom.isRenderedNode;
|
||
|
var isIframeElement = hammerhead__default.utils.dom.isIframeElement;
|
||
|
var isInputElement = hammerhead__default.utils.dom.isInputElement;
|
||
|
var isButtonElement = hammerhead__default.utils.dom.isButtonElement;
|
||
|
var isFileInput = hammerhead__default.utils.dom.isFileInput;
|
||
|
var isTextAreaElement = hammerhead__default.utils.dom.isTextAreaElement;
|
||
|
var isAnchorElement = hammerhead__default.utils.dom.isAnchorElement;
|
||
|
var isImgElement = hammerhead__default.utils.dom.isImgElement;
|
||
|
var isFormElement = hammerhead__default.utils.dom.isFormElement;
|
||
|
var isLabelElement = hammerhead__default.utils.dom.isLabelElement;
|
||
|
var isSelectElement = hammerhead__default.utils.dom.isSelectElement;
|
||
|
var isRadioButtonElement = hammerhead__default.utils.dom.isRadioButtonElement;
|
||
|
var isColorInputElement = hammerhead__default.utils.dom.isColorInputElement;
|
||
|
var isCheckboxElement = hammerhead__default.utils.dom.isCheckboxElement;
|
||
|
var isOptionElement = hammerhead__default.utils.dom.isOptionElement;
|
||
|
var isSVGElement = hammerhead__default.utils.dom.isSVGElement;
|
||
|
var isMapElement = hammerhead__default.utils.dom.isMapElement;
|
||
|
var isBodyElement = hammerhead__default.utils.dom.isBodyElement;
|
||
|
var isHtmlElement = hammerhead__default.utils.dom.isHtmlElement;
|
||
|
var isDocument = hammerhead__default.utils.dom.isDocument;
|
||
|
var isWindow = hammerhead__default.utils.dom.isWindow;
|
||
|
var isTextEditableInput = hammerhead__default.utils.dom.isTextEditableInput;
|
||
|
var isTextEditableElement = hammerhead__default.utils.dom.isTextEditableElement;
|
||
|
var isTextEditableElementAndEditingAllowed = hammerhead__default.utils.dom.isTextEditableElementAndEditingAllowed;
|
||
|
var isContentEditableElement = hammerhead__default.utils.dom.isContentEditableElement;
|
||
|
var isDomElement = hammerhead__default.utils.dom.isDomElement;
|
||
|
var isShadowUIElement = hammerhead__default.utils.dom.isShadowUIElement;
|
||
|
var isShadowRoot = hammerhead__default.utils.dom.isShadowRoot;
|
||
|
var isElementFocusable = hammerhead__default.utils.dom.isElementFocusable;
|
||
|
var isHammerheadAttr = hammerhead__default.utils.dom.isHammerheadAttr;
|
||
|
var isElementReadOnly = hammerhead__default.utils.dom.isElementReadOnly;
|
||
|
var getScrollbarSize = hammerhead__default.utils.dom.getScrollbarSize;
|
||
|
var getMapContainer = hammerhead__default.utils.dom.getMapContainer;
|
||
|
var getTagName = hammerhead__default.utils.dom.getTagName;
|
||
|
var closest = hammerhead__default.utils.dom.closest;
|
||
|
var getParents = hammerhead__default.utils.dom.getParents;
|
||
|
var findParent = hammerhead__default.utils.dom.findParent;
|
||
|
var getTopSameDomainWindow = hammerhead__default.utils.dom.getTopSameDomainWindow;
|
||
|
var getParentExceptShadowRoot = hammerhead__default.utils.dom.getParentExceptShadowRoot;
|
||
|
function containsElement(elements, element) {
|
||
|
if (elements.contains)
|
||
|
return elements.contains(element);
|
||
|
return some(elements, function (parent) { return parent.contains(element); });
|
||
|
}
|
||
|
function findIframeByWindow(iframeWindow) {
|
||
|
var iframes = [];
|
||
|
find(document, '*', function (elem) {
|
||
|
if (elem.tagName === 'IFRAME')
|
||
|
iframes.push(elem);
|
||
|
if (elem.shadowRoot)
|
||
|
find(elem.shadowRoot, 'iframe', function (iframe) { return iframes.push(iframe); });
|
||
|
});
|
||
|
for (var i = 0; i < iframes.length; i++) {
|
||
|
if (nativeMethods$1.contentWindowGetter.call(iframes[i]) === iframeWindow)
|
||
|
return iframes[i];
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
function isShadowElement(element) {
|
||
|
return element && element.getRootNode && findDocument(element) !== element.getRootNode();
|
||
|
}
|
||
|
function isNodeEqual(el1, el2) {
|
||
|
return el1 === el2;
|
||
|
}
|
||
|
function getNodeText(el) {
|
||
|
return nativeMethods$1.nodeTextContentGetter.call(el);
|
||
|
}
|
||
|
function getImgMapName(img) {
|
||
|
return img.useMap.substring(1);
|
||
|
}
|
||
|
function getDocumentElement(win) {
|
||
|
return win.document.documentElement;
|
||
|
}
|
||
|
function isDocumentElement(el) {
|
||
|
return el === document.documentElement;
|
||
|
}
|
||
|
|
||
|
var BoundaryValues = /** @class */ (function () {
|
||
|
function BoundaryValues(top, right, bottom, left) {
|
||
|
if (top === void 0) { top = 0; }
|
||
|
if (right === void 0) { right = 0; }
|
||
|
if (bottom === void 0) { bottom = 0; }
|
||
|
if (left === void 0) { left = 0; }
|
||
|
this.top = top;
|
||
|
this.right = right;
|
||
|
this.bottom = bottom;
|
||
|
this.left = left;
|
||
|
}
|
||
|
BoundaryValues.create = function (v) {
|
||
|
return new BoundaryValues(v.top, v.right, v.bottom, v.left);
|
||
|
};
|
||
|
BoundaryValues.prototype.add = function (d) {
|
||
|
this.top += d.top;
|
||
|
this.right += d.right;
|
||
|
this.bottom += d.bottom;
|
||
|
this.left += d.left;
|
||
|
return this;
|
||
|
};
|
||
|
BoundaryValues.prototype.sub = function (d) {
|
||
|
if ('top' in d) {
|
||
|
this.top -= d.top;
|
||
|
this.left -= d.left;
|
||
|
}
|
||
|
this.bottom -= d.bottom;
|
||
|
this.right -= d.right;
|
||
|
return this;
|
||
|
};
|
||
|
BoundaryValues.prototype.round = function (leftTopRound, rightBottomRound) {
|
||
|
if (leftTopRound === void 0) { leftTopRound = Math.round; }
|
||
|
if (rightBottomRound === void 0) { rightBottomRound = leftTopRound; }
|
||
|
this.top = leftTopRound(this.top);
|
||
|
this.right = rightBottomRound(this.right);
|
||
|
this.bottom = rightBottomRound(this.bottom);
|
||
|
this.left = leftTopRound(this.left);
|
||
|
return this;
|
||
|
};
|
||
|
BoundaryValues.prototype.contains = function (point) {
|
||
|
return point.x >= this.left && point.x <= this.right && point.y >= this.top && point.y <= this.bottom;
|
||
|
};
|
||
|
return BoundaryValues;
|
||
|
}());
|
||
|
|
||
|
var styleUtils = hammerhead__default.utils.style;
|
||
|
var getBordersWidth = hammerhead__default.utils.style.getBordersWidth;
|
||
|
var getComputedStyle = hammerhead__default.utils.style.getComputedStyle;
|
||
|
var getElementMargin = hammerhead__default.utils.style.getElementMargin;
|
||
|
var getElementPadding = hammerhead__default.utils.style.getElementPadding;
|
||
|
var getElementScroll = hammerhead__default.utils.style.getElementScroll;
|
||
|
var getOptionHeight = hammerhead__default.utils.style.getOptionHeight;
|
||
|
var getSelectElementSize = hammerhead__default.utils.style.getSelectElementSize;
|
||
|
var isElementVisible = hammerhead__default.utils.style.isElementVisible;
|
||
|
var isSelectVisibleChild = hammerhead__default.utils.style.isVisibleChild;
|
||
|
var getWidth = hammerhead__default.utils.style.getWidth;
|
||
|
var getHeight = hammerhead__default.utils.style.getHeight;
|
||
|
var getInnerWidth = hammerhead__default.utils.style.getInnerWidth;
|
||
|
var getInnerHeight = hammerhead__default.utils.style.getInnerHeight;
|
||
|
var getScrollLeft = hammerhead__default.utils.style.getScrollLeft;
|
||
|
var getScrollTop = hammerhead__default.utils.style.getScrollTop;
|
||
|
var setScrollLeft = hammerhead__default.utils.style.setScrollLeft;
|
||
|
var setScrollTop = hammerhead__default.utils.style.setScrollTop;
|
||
|
var get = hammerhead__default.utils.style.get;
|
||
|
var getBordersWidthFloat = hammerhead__default.utils.style.getBordersWidthFloat;
|
||
|
var getElementPaddingFloat = hammerhead__default.utils.style.getElementPaddingFloat;
|
||
|
function getWindowDimensions(window) {
|
||
|
return new BoundaryValues(0, getWidth(window), getHeight(window), 0);
|
||
|
}
|
||
|
function isFixedElement(node) {
|
||
|
return isElementNode(node) && styleUtils.get(node, 'position') === 'fixed';
|
||
|
}
|
||
|
|
||
|
var shadowUI = hammerhead__default.shadowUI;
|
||
|
var nativeMethods$2 = hammerhead__default.nativeMethods;
|
||
|
|
||
|
var Dimensions = /** @class */ (function () {
|
||
|
function Dimensions(width, height, position, borders, elScroll, scrollbar) {
|
||
|
this.width = width;
|
||
|
this.height = height;
|
||
|
this.left = position.x;
|
||
|
this.top = position.y;
|
||
|
this.right = position.x + width;
|
||
|
this.bottom = position.y + height;
|
||
|
this.border = borders;
|
||
|
this.scrollbar = scrollbar;
|
||
|
this.scroll = elScroll;
|
||
|
}
|
||
|
return Dimensions;
|
||
|
}());
|
||
|
|
||
|
var hiddenReasons = {
|
||
|
notElementOrTextNode: function (targetType) { return "\n The ".concat(targetType, " is neither a DOM element nor a text node.\n "); },
|
||
|
elOutsideBounds: function (target, targetType) { return "\n The ".concat(targetType, " (").concat(target, ") is located outside the the layout viewport.\n "); },
|
||
|
elHasWidthOrHeightZero: function (target, targetType, width, height) { return "\n The ".concat(targetType, " (").concat(target, ") is too small to be visible: ").concat(width, "px x ").concat(height, "px.\n "); },
|
||
|
elHasDisplayNone: function (target, targetType) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible. \n The value of its 'display' property is 'none'.\n "); },
|
||
|
parentHasDisplayNone: function (target, targetType, parent) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible. \n It descends from an element that has the 'display: none' property (").concat(parent, ").\n "); },
|
||
|
elHasVisibilityHidden: function (target, targetType) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible.\n The value of its 'visibility' property is 'hidden'.\n "); },
|
||
|
parentHasVisibilityHidden: function (target, targetType, parent) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible.\n It descends from an element that has the 'visibility: hidden' property (").concat(parent, ").\n "); },
|
||
|
elHasVisibilityCollapse: function (target, targetType) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible.\n The value of its 'visibility' property is 'collapse'.\n "); },
|
||
|
parentHasVisibilityCollapse: function (target, targetType, parent) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible.\n It descends from an element that has the 'visibility: collapse' property (").concat(parent, ").\n "); },
|
||
|
elNotRendered: function (target, targetType) { return "\n The ".concat(targetType, " (").concat(target, ") has not been rendered.\n "); },
|
||
|
optionNotVisible: function (target, targetType, parent) { return "\n The ".concat(targetType, " (").concat(target, ") is invisible. \n The parent element (").concat(parent, ") is collapsed, and its length is shorter than 2.\n "); },
|
||
|
mapContainerNotVisible: function (target, containerHiddenReason) { return "\n The action target (".concat(target, ") is invisible because ").concat(containerHiddenReason, "\n "); },
|
||
|
};
|
||
|
|
||
|
var htmlUtils = hammerhead__default.utils.html;
|
||
|
var nativeMethods$3 = hammerhead__default.nativeMethods;
|
||
|
var MAX_TEXT_CONTENT_LENGTH = 10;
|
||
|
function truncateString(str, length, omission) {
|
||
|
if (omission === void 0) { omission = '...'; }
|
||
|
if (str.length < length)
|
||
|
return str;
|
||
|
return str.substring(0, length - omission.length) + omission;
|
||
|
}
|
||
|
function stringifyElement(element) {
|
||
|
if (!element)
|
||
|
return '';
|
||
|
var emptyElement = nativeMethods$3.cloneNode.call(element);
|
||
|
var outerHtml = htmlUtils.cleanUpHtml(nativeMethods$3.elementOuterHTMLGetter.call(emptyElement));
|
||
|
var text = truncateString(nativeMethods$3.nodeTextContentGetter.call(element), MAX_TEXT_CONTENT_LENGTH);
|
||
|
var children = nativeMethods$3.elementChildrenGetter.call(element);
|
||
|
if (nativeMethods$3.htmlCollectionLengthGetter.call(children) > 0)
|
||
|
return outerHtml.replace('></', '>...</');
|
||
|
if (text)
|
||
|
return outerHtml.replace('></', ">".concat(text, "</"));
|
||
|
return outerHtml;
|
||
|
}
|
||
|
|
||
|
var getElementRectangle = hammerhead__default.utils.position.getElementRectangle;
|
||
|
var getOffsetPosition = hammerhead__default.utils.position.getOffsetPosition;
|
||
|
var offsetToClientCoords = hammerhead__default.utils.position.offsetToClientCoords;
|
||
|
function getClientDimensions(target) {
|
||
|
var isHtmlElement$1 = isHtmlElement(target);
|
||
|
var body = isHtmlElement$1 ? target.getElementsByTagName('body')[0] : null;
|
||
|
var elementRect = target.getBoundingClientRect();
|
||
|
var elBorders = BoundaryValues.create(getBordersWidth(target));
|
||
|
var elScroll = getElementScroll(target);
|
||
|
var isElementInIframe$1 = isElementInIframe(target);
|
||
|
var isCompatMode = target.ownerDocument.compatMode === 'BackCompat';
|
||
|
var elPosition = isHtmlElement$1 ? new AxisValues(0, 0) : AxisValues.create(elementRect);
|
||
|
var elHeight = elementRect.height;
|
||
|
var elWidth = elementRect.width;
|
||
|
if (isHtmlElement$1) {
|
||
|
if (body && isCompatMode) {
|
||
|
elHeight = body.clientHeight;
|
||
|
elWidth = body.clientWidth;
|
||
|
}
|
||
|
else {
|
||
|
elHeight = target.clientHeight;
|
||
|
elWidth = target.clientWidth;
|
||
|
}
|
||
|
}
|
||
|
if (isElementInIframe$1) {
|
||
|
var iframeElement = getIframeByElement(target);
|
||
|
if (iframeElement) {
|
||
|
var iframeOffset = getOffsetPosition(iframeElement);
|
||
|
var clientOffset = offsetToClientCoords(AxisValues.create(iframeOffset));
|
||
|
var iframeBorders = getBordersWidth(iframeElement);
|
||
|
elPosition.add(clientOffset).add(AxisValues.create(iframeBorders));
|
||
|
if (isHtmlElement$1)
|
||
|
elBorders.add(iframeBorders);
|
||
|
}
|
||
|
}
|
||
|
var hasRightScrollbar = !isHtmlElement$1 && getInnerWidth(target) !== target.clientWidth;
|
||
|
var hasBottomScrollbar = !isHtmlElement$1 && getInnerHeight(target) !== target.clientHeight;
|
||
|
var scrollbar = {
|
||
|
right: hasRightScrollbar ? getScrollbarSize() : 0,
|
||
|
bottom: hasBottomScrollbar ? getScrollbarSize() : 0,
|
||
|
};
|
||
|
return new Dimensions(elWidth, elHeight, elPosition, elBorders, elScroll, scrollbar);
|
||
|
}
|
||
|
function getElementFromPoint(_a) {
|
||
|
var x = _a.x, y = _a.y;
|
||
|
// @ts-ignore
|
||
|
var ieFn = document.getElementFromPoint;
|
||
|
var func = ieFn || document.elementFromPoint;
|
||
|
var el = null;
|
||
|
try {
|
||
|
// Permission denied to access property 'getElementFromPoint' error in iframe
|
||
|
el = func.call(document, x, y);
|
||
|
}
|
||
|
catch (_b) {
|
||
|
return null;
|
||
|
}
|
||
|
//NOTE: elementFromPoint returns null when is's a border of an iframe
|
||
|
if (el === null)
|
||
|
el = func.call(document, x - 1, y - 1);
|
||
|
while (el && el.shadowRoot && el.shadowRoot.elementFromPoint) {
|
||
|
var shadowEl = el.shadowRoot.elementFromPoint(x, y);
|
||
|
if (!shadowEl || el === shadowEl)
|
||
|
break;
|
||
|
el = shadowEl;
|
||
|
}
|
||
|
return el;
|
||
|
}
|
||
|
function calcRelativePosition(dimensions, toDimensions) {
|
||
|
var pos = BoundaryValues.create({
|
||
|
top: dimensions.top - toDimensions.top,
|
||
|
left: dimensions.left - toDimensions.left,
|
||
|
right: toDimensions.right - dimensions.right,
|
||
|
bottom: toDimensions.bottom - dimensions.bottom,
|
||
|
});
|
||
|
return pos.sub(toDimensions.border).sub(toDimensions.scrollbar).round(Math.ceil, Math.floor);
|
||
|
}
|
||
|
function getIframeClientCoordinates(iframe) {
|
||
|
var _a = getOffsetPosition(iframe), left = _a.left, top = _a.top;
|
||
|
var clientPosition = offsetToClientCoords({ x: left, y: top });
|
||
|
var iframeBorders = getBordersWidth(iframe);
|
||
|
var iframePadding = getElementPadding(iframe);
|
||
|
var iframeRectangleLeft = clientPosition.x + iframeBorders.left + iframePadding.left;
|
||
|
var iframeRectangleTop = clientPosition.y + iframeBorders.top + iframePadding.top;
|
||
|
return new BoundaryValues(iframeRectangleTop, iframeRectangleLeft + getWidth(iframe), iframeRectangleTop + getHeight(iframe), iframeRectangleLeft);
|
||
|
}
|
||
|
function containsOffset(el, offsetX, offsetY) {
|
||
|
var dimensions = getClientDimensions(el);
|
||
|
var width = Math.max(el.scrollWidth, dimensions.width);
|
||
|
var height = Math.max(el.scrollHeight, dimensions.height);
|
||
|
var maxX = dimensions.scrollbar.right + dimensions.border.left + dimensions.border.right + width;
|
||
|
var maxY = dimensions.scrollbar.bottom + dimensions.border.top + dimensions.border.bottom + height;
|
||
|
return (typeof offsetX === 'undefined' || offsetX >= 0 && maxX >= offsetX) &&
|
||
|
(typeof offsetY === 'undefined' || offsetY >= 0 && maxY >= offsetY);
|
||
|
}
|
||
|
function getClientPosition(el) {
|
||
|
var _a = getOffsetPosition(el), left = _a.left, top = _a.top;
|
||
|
var clientCoords = offsetToClientCoords({ x: left, y: top });
|
||
|
clientCoords.x = Math.round(clientCoords.x);
|
||
|
clientCoords.y = Math.round(clientCoords.y);
|
||
|
return clientCoords;
|
||
|
}
|
||
|
function getWindowPosition() {
|
||
|
var x = window.screenLeft || window.screenX;
|
||
|
var y = window.screenTop || window.screenY;
|
||
|
return new AxisValues(x, y);
|
||
|
}
|
||
|
function getSubHiddenReason(reason) {
|
||
|
return reason.replace(/.*The/, 'its');
|
||
|
}
|
||
|
function getElOutsideBoundsReason(el, targetType) {
|
||
|
if (targetType === void 0) { targetType = 'action target'; }
|
||
|
var strEl = stringifyElement(el);
|
||
|
if (isMapElement(el)) {
|
||
|
var mapContainer = getMapContainer(closest(el, 'map'));
|
||
|
var containerHiddenReason = getElOutsideBoundsReason(mapContainer, 'container') || '';
|
||
|
var containerError = getSubHiddenReason(containerHiddenReason);
|
||
|
return hiddenReasons.mapContainerNotVisible(strEl, containerError);
|
||
|
}
|
||
|
return hiddenReasons.elOutsideBounds(strEl, targetType);
|
||
|
}
|
||
|
|
||
|
function getAutomationPoint(element, offset) {
|
||
|
return hammerhead.Promise.resolve(isDocumentElement(element))
|
||
|
.then(function (isDocEl) {
|
||
|
if (isDocEl)
|
||
|
return new AxisValues(0, 0);
|
||
|
var roundFn = hammerhead.utils.browser.isFirefox ? Math.ceil : Math.round;
|
||
|
return hammerhead.Promise.resolve(getOffsetPosition(element, roundFn))
|
||
|
.then(function (elementOffset) { return AxisValues.create(elementOffset); });
|
||
|
})
|
||
|
.then(function (point) { return point.add(offset); });
|
||
|
}
|
||
|
|
||
|
var SCROLLABLE_OVERFLOW_STYLE_RE = /auto|scroll|hidden/i;
|
||
|
var DEFAULT_IE_SCROLLABLE_OVERFLOW_STYLE_VALUE = 'visible';
|
||
|
function getScrollable(el) {
|
||
|
var overflowX = get(el, 'overflowX');
|
||
|
var overflowY = get(el, 'overflowY');
|
||
|
var scrollableHorizontally = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowX);
|
||
|
var scrollableVertically = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowY);
|
||
|
// IE11 and MS Edge bug: There are two properties: overflow-x and overflow-y.
|
||
|
// If one property is set so that the browser may show scrollbars (`auto` or `scroll`) and the second one is set to 'visible',
|
||
|
// then the second one will work as if it had the 'auto' value.
|
||
|
if (hammerhead.utils.browser.isIE) {
|
||
|
scrollableHorizontally = scrollableHorizontally || scrollableVertically && overflowX === DEFAULT_IE_SCROLLABLE_OVERFLOW_STYLE_VALUE;
|
||
|
scrollableVertically = scrollableVertically || scrollableHorizontally && overflowY === DEFAULT_IE_SCROLLABLE_OVERFLOW_STYLE_VALUE;
|
||
|
}
|
||
|
return new AxisValues(scrollableHorizontally, scrollableVertically);
|
||
|
}
|
||
|
function hasBodyScroll(el) {
|
||
|
var overflowX = get(el, 'overflowX');
|
||
|
var overflowY = get(el, 'overflowY');
|
||
|
var scrollableHorizontally = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowX);
|
||
|
var scrollableVertically = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowY);
|
||
|
var documentElement = findDocument(el).documentElement;
|
||
|
var bodyScrollHeight = el.scrollHeight;
|
||
|
if (hammerhead.utils.browser.isChrome || hammerhead.utils.browser.isFirefox || hammerhead.utils.browser.isSafari) {
|
||
|
var bodyTop = el.getBoundingClientRect().top;
|
||
|
var documentTop = documentElement.getBoundingClientRect().top;
|
||
|
bodyScrollHeight = bodyScrollHeight - documentTop + bodyTop;
|
||
|
}
|
||
|
return (scrollableHorizontally || scrollableVertically) &&
|
||
|
bodyScrollHeight > documentElement.scrollHeight;
|
||
|
}
|
||
|
function hasHTMLElementScroll(el) {
|
||
|
var overflowX = get(el, 'overflowX');
|
||
|
var overflowY = get(el, 'overflowY');
|
||
|
//T303226
|
||
|
if (overflowX === 'hidden' && overflowY === 'hidden')
|
||
|
return false;
|
||
|
var hasHorizontalScroll = el.scrollHeight > el.clientHeight;
|
||
|
var hasVerticalScroll = el.scrollWidth > el.clientWidth;
|
||
|
if (hasHorizontalScroll || hasVerticalScroll)
|
||
|
return true;
|
||
|
//T174562 - wrong scrolling in iframes without src and others iframes
|
||
|
var body = el.getElementsByTagName('body')[0];
|
||
|
if (!body)
|
||
|
return false;
|
||
|
if (hasBodyScroll(body))
|
||
|
return false;
|
||
|
var clientWidth = Math.min(el.clientWidth, body.clientWidth);
|
||
|
var clientHeight = Math.min(el.clientHeight, body.clientHeight);
|
||
|
return body.scrollHeight > clientHeight || body.scrollWidth > clientWidth;
|
||
|
}
|
||
|
function hasScroll(el) {
|
||
|
if (isBodyElement(el))
|
||
|
return hasBodyScroll(el);
|
||
|
if (isHtmlElement(el))
|
||
|
return hasHTMLElementScroll(el);
|
||
|
var scrollable = getScrollable(el);
|
||
|
if (!scrollable.x && !scrollable.y)
|
||
|
return false;
|
||
|
var hasVerticalScroll = scrollable.y && el.scrollHeight > el.clientHeight;
|
||
|
var hasHorizontalScroll = scrollable.x && el.scrollWidth > el.clientWidth;
|
||
|
return hasHorizontalScroll || hasVerticalScroll;
|
||
|
}
|
||
|
function getScrollableParents(element) {
|
||
|
var parentsArray = getParents(element);
|
||
|
if (isElementInIframe(element)) {
|
||
|
var iframe = getIframeByElement(element);
|
||
|
if (iframe) {
|
||
|
var iFrameParents = getParents(iframe);
|
||
|
parentsArray.concat(iFrameParents);
|
||
|
}
|
||
|
}
|
||
|
return hammerhead.nativeMethods.arrayFilter.call(parentsArray, hasScroll);
|
||
|
}
|
||
|
|
||
|
function convertToClient(element, point) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var elementScroll, hasScroll$1;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0: return [4 /*yield*/, getElementScroll(element)];
|
||
|
case 1:
|
||
|
elementScroll = _a.sent();
|
||
|
hasScroll$1 = hasScroll(element);
|
||
|
if (!/html/i.test(element.tagName) && hasScroll$1) {
|
||
|
point.x -= elementScroll.left;
|
||
|
point.y -= elementScroll.top;
|
||
|
}
|
||
|
return [2 /*return*/, offsetToClientCoords(point)];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function getDevicePoint(clientPoint) {
|
||
|
if (!clientPoint)
|
||
|
return null;
|
||
|
var windowPosition = getWindowPosition();
|
||
|
var screenLeft = windowPosition.x;
|
||
|
var screenTop = windowPosition.y;
|
||
|
var x = screenLeft + clientPoint.x;
|
||
|
var y = screenTop + clientPoint.y;
|
||
|
return new AxisValues(x, y);
|
||
|
}
|
||
|
|
||
|
function calcOffset(size) {
|
||
|
var offset = size / 2;
|
||
|
return offset < 1 ? 0 : Math.round(offset);
|
||
|
}
|
||
|
function getDefaultAutomationOffsets(element) {
|
||
|
var rect = getElementRectangle(element);
|
||
|
var offsetX = calcOffset(rect.width);
|
||
|
var offsetY = calcOffset(rect.height);
|
||
|
return { offsetX: offsetX, offsetY: offsetY };
|
||
|
}
|
||
|
function getOffsetOptions(element, offsetX, offsetY) {
|
||
|
var defaultOffsets = getDefaultAutomationOffsets(element);
|
||
|
offsetX = typeof offsetX === 'number' ? Math.round(offsetX) : defaultOffsets.offsetX;
|
||
|
offsetY = typeof offsetY === 'number' ? Math.round(offsetY) : defaultOffsets.offsetY;
|
||
|
if (offsetX > 0 && offsetY > 0)
|
||
|
return { offsetX: offsetX, offsetY: offsetY };
|
||
|
var dimensions = getClientDimensions(element);
|
||
|
var width = Math.round(Math.max(element.scrollWidth, dimensions.width));
|
||
|
var height = Math.round(Math.max(element.scrollHeight, dimensions.height));
|
||
|
var maxX = dimensions.scrollbar.right + dimensions.border.left + dimensions.border.right + width;
|
||
|
var maxY = dimensions.scrollbar.bottom + dimensions.border.top + dimensions.border.bottom + height;
|
||
|
return {
|
||
|
offsetX: offsetX < 0 ? maxX + offsetX : offsetX,
|
||
|
offsetY: offsetY < 0 ? maxY + offsetY : offsetY,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var positionUtils = testCafeCore__default.positionUtils;
|
||
|
function getElementFromPoint$1(point, underTopShadowUIElement) {
|
||
|
if (underTopShadowUIElement === void 0) { underTopShadowUIElement = false; }
|
||
|
return testCafeUI.hide(underTopShadowUIElement)
|
||
|
.then(function () {
|
||
|
var topElement = positionUtils.getElementFromPoint(point);
|
||
|
return testCafeUI.show(underTopShadowUIElement)
|
||
|
.then(function () { return topElement; });
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// @ts-ignore
|
||
|
function ensureImageMap(imgElement, areaElement) {
|
||
|
return hammerhead.Promise.resolve(closest(areaElement, 'map'))
|
||
|
.then(function (mapElement) {
|
||
|
return mapElement && mapElement.name === getImgMapName(imgElement) ? areaElement : imgElement;
|
||
|
});
|
||
|
}
|
||
|
function findElementOrNonEmptyChildFromPoint(point, element) {
|
||
|
return hammerhead.Promise.resolve(getElementFromPoint(point))
|
||
|
.then(function (topElement) {
|
||
|
return hammerhead.Promise.resolve(containsElement(element, topElement))
|
||
|
.then(function (containsEl) { return containsEl && getNodeText(topElement); })
|
||
|
.then(function (isNonEmptyChild) { return isNonEmptyChild || topElement && isNodeEqual(topElement, element) ? topElement : null; });
|
||
|
});
|
||
|
}
|
||
|
function correctTopElementByExpectedElement(topElement, expectedElement) {
|
||
|
if (!expectedElement || !topElement || isNodeEqual(topElement, expectedElement))
|
||
|
return topElement;
|
||
|
var isTREFElement = getTagName(expectedElement) === 'tref';
|
||
|
// NOTE: 'document.elementFromPoint' can't find these types of elements
|
||
|
if (isTREFElement)
|
||
|
return expectedElement;
|
||
|
// NOTE: T299665 - Incorrect click automation for images with an associated map element in Firefox
|
||
|
// All browsers return the <area> element from document.getElementFromPoint, but
|
||
|
// Firefox returns the <img> element. We should accomplish this for Firefox as well.
|
||
|
var isImageMapArea = getTagName(expectedElement) === 'area' && isImgElement(topElement);
|
||
|
if (hammerhead.utils.browser.isFirefox && isImageMapArea)
|
||
|
return ensureImageMap(topElement, expectedElement);
|
||
|
// NOTE: try to find a multi-line link by its rectangle (T163678)
|
||
|
return hammerhead.Promise.resolve(closest(expectedElement, 'a'))
|
||
|
.then(function (anchor) { return !!anchor; })
|
||
|
.then(function (isLinkOrChildExpected) {
|
||
|
if (!isLinkOrChildExpected)
|
||
|
return false;
|
||
|
return hammerhead.Promise.resolve(containsElement(expectedElement, topElement))
|
||
|
.then(function (containsElement) { return containsElement && getNodeText(topElement); })
|
||
|
.then(function (isTopElementChildOfLink) { return !isTopElementChildOfLink && getNodeText(expectedElement); });
|
||
|
})
|
||
|
.then(function (shouldSearchForMultilineLink) {
|
||
|
if (!shouldSearchForMultilineLink)
|
||
|
return topElement;
|
||
|
return hammerhead.Promise.resolve(getClientDimensions(expectedElement))
|
||
|
.then(function (linkRect) { return findElementOrNonEmptyChildFromPoint({ x: linkRect.right - 1, y: linkRect.top + 1 }, expectedElement)
|
||
|
.then(function (el) { return el || findElementOrNonEmptyChildFromPoint({ x: linkRect.left + 1, y: linkRect.bottom - 1 }, expectedElement); })
|
||
|
.then(function (el) { return el || topElement; }); });
|
||
|
});
|
||
|
}
|
||
|
function getElementFromPoint$2(point, win, expectedEl) {
|
||
|
return getElementFromPoint$1(point)
|
||
|
.then(function (topElement) {
|
||
|
// NOTE: when trying to get an element by elementFromPoint in iframe and the target
|
||
|
// element is under any of shadow-ui elements, you will get null (only in IE).
|
||
|
// In this case, you should hide a top window's shadow-ui root to obtain an element.
|
||
|
var resChain = hammerhead.Promise.resolve(topElement);
|
||
|
if (!topElement && hammerhead.utils.dom.isIframeWindow(win || window) && point.x > 0 && point.y > 0)
|
||
|
resChain = resChain.then(function () { return getElementFromPoint$1(point, true); });
|
||
|
return resChain.then(function (element) { return correctTopElementByExpectedElement(element, expectedEl); });
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
// WARNING: this file is used by both the client and the server.
|
||
|
// Do not use any browser or node-specific API!
|
||
|
// -------------------------------------------------------------
|
||
|
var TEST_RUN_ERRORS = {
|
||
|
uncaughtErrorOnPage: 'E1',
|
||
|
uncaughtErrorInTestCode: 'E2',
|
||
|
uncaughtNonErrorObjectInTestCode: 'E3',
|
||
|
uncaughtErrorInClientFunctionCode: 'E4',
|
||
|
uncaughtErrorInCustomDOMPropertyCode: 'E5',
|
||
|
unhandledPromiseRejection: 'E6',
|
||
|
uncaughtException: 'E7',
|
||
|
missingAwaitError: 'E8',
|
||
|
actionIntegerOptionError: 'E9',
|
||
|
actionPositiveIntegerOptionError: 'E10',
|
||
|
actionBooleanOptionError: 'E11',
|
||
|
actionSpeedOptionError: 'E12',
|
||
|
actionOptionsTypeError: 'E14',
|
||
|
actionBooleanArgumentError: 'E15',
|
||
|
actionStringArgumentError: 'E16',
|
||
|
actionNullableStringArgumentError: 'E17',
|
||
|
actionStringOrStringArrayArgumentError: 'E18',
|
||
|
actionStringArrayElementError: 'E19',
|
||
|
actionIntegerArgumentError: 'E20',
|
||
|
actionRoleArgumentError: 'E21',
|
||
|
actionPositiveIntegerArgumentError: 'E22',
|
||
|
actionSelectorError: 'E23',
|
||
|
actionElementNotFoundError: 'E24',
|
||
|
actionElementIsInvisibleError: 'E26',
|
||
|
actionSelectorMatchesWrongNodeTypeError: 'E27',
|
||
|
actionAdditionalElementNotFoundError: 'E28',
|
||
|
actionAdditionalElementIsInvisibleError: 'E29',
|
||
|
actionAdditionalSelectorMatchesWrongNodeTypeError: 'E30',
|
||
|
actionElementNonEditableError: 'E31',
|
||
|
actionElementNotTextAreaError: 'E32',
|
||
|
actionElementNonContentEditableError: 'E33',
|
||
|
actionElementIsNotFileInputError: 'E34',
|
||
|
actionRootContainerNotFoundError: 'E35',
|
||
|
actionIncorrectKeysError: 'E36',
|
||
|
actionCannotFindFileToUploadError: 'E37',
|
||
|
actionUnsupportedDeviceTypeError: 'E38',
|
||
|
actionIframeIsNotLoadedError: 'E39',
|
||
|
actionElementNotIframeError: 'E40',
|
||
|
actionInvalidScrollTargetError: 'E41',
|
||
|
currentIframeIsNotLoadedError: 'E42',
|
||
|
currentIframeNotFoundError: 'E43',
|
||
|
currentIframeIsInvisibleError: 'E44',
|
||
|
nativeDialogNotHandledError: 'E45',
|
||
|
uncaughtErrorInNativeDialogHandler: 'E46',
|
||
|
setTestSpeedArgumentError: 'E47',
|
||
|
setNativeDialogHandlerCodeWrongTypeError: 'E48',
|
||
|
clientFunctionExecutionInterruptionError: 'E49',
|
||
|
domNodeClientFunctionResultError: 'E50',
|
||
|
invalidSelectorResultError: 'E51',
|
||
|
cannotObtainInfoForElementSpecifiedBySelectorError: 'E52',
|
||
|
externalAssertionLibraryError: 'E53',
|
||
|
pageLoadError: 'E54',
|
||
|
windowDimensionsOverflowError: 'E55',
|
||
|
forbiddenCharactersInScreenshotPathError: 'E56',
|
||
|
invalidElementScreenshotDimensionsError: 'E57',
|
||
|
roleSwitchInRoleInitializerError: 'E58',
|
||
|
assertionExecutableArgumentError: 'E59',
|
||
|
assertionWithoutMethodCallError: 'E60',
|
||
|
assertionUnawaitedPromiseError: 'E61',
|
||
|
requestHookNotImplementedError: 'E62',
|
||
|
requestHookUnhandledError: 'E63',
|
||
|
uncaughtErrorInCustomClientScriptCode: 'E64',
|
||
|
uncaughtErrorInCustomClientScriptCodeLoadedFromModule: 'E65',
|
||
|
uncaughtErrorInCustomScript: 'E66',
|
||
|
uncaughtTestCafeErrorInCustomScript: 'E67',
|
||
|
childWindowIsNotLoadedError: 'E68',
|
||
|
childWindowNotFoundError: 'E69',
|
||
|
cannotSwitchToWindowError: 'E70',
|
||
|
closeChildWindowError: 'E71',
|
||
|
childWindowClosedBeforeSwitchingError: 'E72',
|
||
|
cannotCloseWindowWithChildrenError: 'E73',
|
||
|
targetWindowNotFoundError: 'E74',
|
||
|
parentWindowNotFoundError: 'E76',
|
||
|
previousWindowNotFoundError: 'E77',
|
||
|
switchToWindowPredicateError: 'E78',
|
||
|
actionFunctionArgumentError: 'E79',
|
||
|
multipleWindowsModeIsDisabledError: 'E80',
|
||
|
multipleWindowsModeIsNotSupportedInRemoteBrowserError: 'E81',
|
||
|
cannotCloseWindowWithoutParent: 'E82',
|
||
|
cannotRestoreChildWindowError: 'E83',
|
||
|
executionTimeoutExceeded: 'E84',
|
||
|
actionRequiredCookieArguments: 'E85',
|
||
|
actionCookieArgumentError: 'E86',
|
||
|
actionCookieArgumentsError: 'E87',
|
||
|
actionUrlCookieArgumentError: 'E88',
|
||
|
actionUrlsCookieArgumentError: 'E89',
|
||
|
actionStringOptionError: 'E90',
|
||
|
actionDateOptionError: 'E91',
|
||
|
actionNumberOptionError: 'E92',
|
||
|
actionUrlOptionError: 'E93',
|
||
|
actionUrlSearchParamsOptionError: 'E94',
|
||
|
actionObjectOptionError: 'E95',
|
||
|
actionUrlArgumentError: 'E96',
|
||
|
actionStringOrRegexOptionError: 'E97',
|
||
|
actionSkipJsErrorsArgumentError: 'E98',
|
||
|
actionFunctionOptionError: 'E99',
|
||
|
actionInvalidObjectPropertyError: 'E100',
|
||
|
actionElementIsNotTargetError: 'E101',
|
||
|
};
|
||
|
|
||
|
// Base
|
||
|
//--------------------------------------------------------------------
|
||
|
var TestRunErrorBase = /** @class */ (function () {
|
||
|
function TestRunErrorBase(code, callsite) {
|
||
|
this.code = code;
|
||
|
this.isTestCafeError = true;
|
||
|
this.callsite = callsite || null;
|
||
|
}
|
||
|
return TestRunErrorBase;
|
||
|
}());
|
||
|
var ActionOptionErrorBase = /** @class */ (function (_super) {
|
||
|
__extends(ActionOptionErrorBase, _super);
|
||
|
function ActionOptionErrorBase(code, optionName, actualValue) {
|
||
|
var _this = _super.call(this, code) || this;
|
||
|
_this.optionName = optionName;
|
||
|
_this.actualValue = actualValue;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionOptionErrorBase;
|
||
|
}(TestRunErrorBase));
|
||
|
// Client function errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var ClientFunctionExecutionInterruptionError = /** @class */ (function (_super) {
|
||
|
__extends(ClientFunctionExecutionInterruptionError, _super);
|
||
|
function ClientFunctionExecutionInterruptionError(instantiationCallsiteName, callsite) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.clientFunctionExecutionInterruptionError, callsite) || this;
|
||
|
_this.instantiationCallsiteName = instantiationCallsiteName;
|
||
|
return _this;
|
||
|
}
|
||
|
return ClientFunctionExecutionInterruptionError;
|
||
|
}(TestRunErrorBase));
|
||
|
var DomNodeClientFunctionResultError = /** @class */ (function (_super) {
|
||
|
__extends(DomNodeClientFunctionResultError, _super);
|
||
|
function DomNodeClientFunctionResultError(instantiationCallsiteName, callsite) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.domNodeClientFunctionResultError, callsite) || this;
|
||
|
_this.instantiationCallsiteName = instantiationCallsiteName;
|
||
|
return _this;
|
||
|
}
|
||
|
return DomNodeClientFunctionResultError;
|
||
|
}(TestRunErrorBase));
|
||
|
// Selector errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var SelectorErrorBase = /** @class */ (function (_super) {
|
||
|
__extends(SelectorErrorBase, _super);
|
||
|
function SelectorErrorBase(code, _a, callsite) {
|
||
|
var _b = _a === void 0 ? {} : _a, apiFnChain = _b.apiFnChain, apiFnIndex = _b.apiFnIndex, reason = _b.reason;
|
||
|
var _this = _super.call(this, code, callsite) || this;
|
||
|
_this.apiFnChain = apiFnChain;
|
||
|
_this.apiFnIndex = apiFnIndex;
|
||
|
_this.reason = reason;
|
||
|
return _this;
|
||
|
}
|
||
|
return SelectorErrorBase;
|
||
|
}(TestRunErrorBase));
|
||
|
var InvalidSelectorResultError = /** @class */ (function (_super) {
|
||
|
__extends(InvalidSelectorResultError, _super);
|
||
|
function InvalidSelectorResultError(callsite) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.invalidSelectorResultError, callsite) || this;
|
||
|
}
|
||
|
return InvalidSelectorResultError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CannotObtainInfoForElementSpecifiedBySelectorError = /** @class */ (function (_super) {
|
||
|
__extends(CannotObtainInfoForElementSpecifiedBySelectorError, _super);
|
||
|
function CannotObtainInfoForElementSpecifiedBySelectorError(callsite, apiFnArgs) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.cannotObtainInfoForElementSpecifiedBySelectorError, apiFnArgs, callsite) || this;
|
||
|
}
|
||
|
return CannotObtainInfoForElementSpecifiedBySelectorError;
|
||
|
}(SelectorErrorBase));
|
||
|
// Uncaught errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var UncaughtErrorOnPage = /** @class */ (function (_super) {
|
||
|
__extends(UncaughtErrorOnPage, _super);
|
||
|
function UncaughtErrorOnPage(errStack, pageDestUrl) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.uncaughtErrorOnPage) || this;
|
||
|
_this.errStack = errStack;
|
||
|
_this.pageDestUrl = pageDestUrl;
|
||
|
return _this;
|
||
|
}
|
||
|
return UncaughtErrorOnPage;
|
||
|
}(TestRunErrorBase));
|
||
|
var UncaughtErrorInClientFunctionCode = /** @class */ (function (_super) {
|
||
|
__extends(UncaughtErrorInClientFunctionCode, _super);
|
||
|
function UncaughtErrorInClientFunctionCode(instantiationCallsiteName, err, callsite) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.uncaughtErrorInClientFunctionCode, callsite) || this;
|
||
|
_this.errMsg = String(err);
|
||
|
_this.instantiationCallsiteName = instantiationCallsiteName;
|
||
|
return _this;
|
||
|
}
|
||
|
return UncaughtErrorInClientFunctionCode;
|
||
|
}(TestRunErrorBase));
|
||
|
var UncaughtErrorInCustomDOMPropertyCode = /** @class */ (function (_super) {
|
||
|
__extends(UncaughtErrorInCustomDOMPropertyCode, _super);
|
||
|
function UncaughtErrorInCustomDOMPropertyCode(instantiationCallsiteName, err, prop, callsite) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.uncaughtErrorInCustomDOMPropertyCode, callsite) || this;
|
||
|
_this.errMsg = String(err);
|
||
|
_this.property = prop;
|
||
|
_this.instantiationCallsiteName = instantiationCallsiteName;
|
||
|
return _this;
|
||
|
}
|
||
|
return UncaughtErrorInCustomDOMPropertyCode;
|
||
|
}(TestRunErrorBase));
|
||
|
var UncaughtErrorInCustomClientScriptCode = /** @class */ (function (_super) {
|
||
|
__extends(UncaughtErrorInCustomClientScriptCode, _super);
|
||
|
function UncaughtErrorInCustomClientScriptCode(err) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.uncaughtErrorInCustomClientScriptCode) || this;
|
||
|
_this.errMsg = String(err);
|
||
|
return _this;
|
||
|
}
|
||
|
return UncaughtErrorInCustomClientScriptCode;
|
||
|
}(TestRunErrorBase));
|
||
|
var UncaughtErrorInCustomClientScriptLoadedFromModule = /** @class */ (function (_super) {
|
||
|
__extends(UncaughtErrorInCustomClientScriptLoadedFromModule, _super);
|
||
|
function UncaughtErrorInCustomClientScriptLoadedFromModule(err, moduleName) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.uncaughtErrorInCustomClientScriptCodeLoadedFromModule) || this;
|
||
|
_this.errMsg = String(err);
|
||
|
_this.moduleName = moduleName;
|
||
|
return _this;
|
||
|
}
|
||
|
return UncaughtErrorInCustomClientScriptLoadedFromModule;
|
||
|
}(TestRunErrorBase));
|
||
|
// Action parameters errors
|
||
|
//--------------------------------------------------------------------
|
||
|
// Options errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var ActionIntegerOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionIntegerOptionError, _super);
|
||
|
function ActionIntegerOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionIntegerOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionIntegerOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionPositiveIntegerOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionPositiveIntegerOptionError, _super);
|
||
|
function ActionPositiveIntegerOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionPositiveIntegerOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionPositiveIntegerOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionBooleanOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionBooleanOptionError, _super);
|
||
|
function ActionBooleanOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionBooleanOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionBooleanOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionSpeedOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionSpeedOptionError, _super);
|
||
|
function ActionSpeedOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionSpeedOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionSpeedOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionStringOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionStringOptionError, _super);
|
||
|
function ActionStringOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionStringOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionStringOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionStringOrRegexOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionStringOrRegexOptionError, _super);
|
||
|
function ActionStringOrRegexOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionStringOrRegexOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionStringOrRegexOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionDateOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionDateOptionError, _super);
|
||
|
function ActionDateOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionDateOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionDateOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionNumberOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionNumberOptionError, _super);
|
||
|
function ActionNumberOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionNumberOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionNumberOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionUrlOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionUrlOptionError, _super);
|
||
|
function ActionUrlOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionUrlOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionUrlOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionUrlSearchParamsOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionUrlSearchParamsOptionError, _super);
|
||
|
function ActionUrlSearchParamsOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionUrlSearchParamsOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionUrlSearchParamsOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionObjectOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionObjectOptionError, _super);
|
||
|
function ActionObjectOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionObjectOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionObjectOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionFunctionOptionError = /** @class */ (function (_super) {
|
||
|
__extends(ActionFunctionOptionError, _super);
|
||
|
function ActionFunctionOptionError(optionName, actualValue) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionFunctionOptionError, optionName, actualValue) || this;
|
||
|
}
|
||
|
return ActionFunctionOptionError;
|
||
|
}(ActionOptionErrorBase));
|
||
|
var ActionInvalidObjectPropertyError = /** @class */ (function (_super) {
|
||
|
__extends(ActionInvalidObjectPropertyError, _super);
|
||
|
function ActionInvalidObjectPropertyError(objectName, propertyName, availableProperties) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionInvalidObjectPropertyError) || this;
|
||
|
_this.objectName = objectName;
|
||
|
_this.propertyName = propertyName;
|
||
|
_this.availableProperties = availableProperties;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionInvalidObjectPropertyError;
|
||
|
}(TestRunErrorBase));
|
||
|
// Action execution errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var ActionElementNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementNotFoundError, _super);
|
||
|
function ActionElementNotFoundError(callsite, apiFnArgs) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementNotFoundError, apiFnArgs, callsite) || this;
|
||
|
}
|
||
|
return ActionElementNotFoundError;
|
||
|
}(SelectorErrorBase));
|
||
|
var ActionElementIsInvisibleError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementIsInvisibleError, _super);
|
||
|
function ActionElementIsInvisibleError(callsite, apiFnArgs) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementIsInvisibleError, apiFnArgs, callsite) || this;
|
||
|
}
|
||
|
return ActionElementIsInvisibleError;
|
||
|
}(SelectorErrorBase));
|
||
|
var ActionSelectorMatchesWrongNodeTypeError = /** @class */ (function (_super) {
|
||
|
__extends(ActionSelectorMatchesWrongNodeTypeError, _super);
|
||
|
function ActionSelectorMatchesWrongNodeTypeError(nodeDescription) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionSelectorMatchesWrongNodeTypeError) || this;
|
||
|
_this.nodeDescription = nodeDescription;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionSelectorMatchesWrongNodeTypeError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionAdditionalElementNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(ActionAdditionalElementNotFoundError, _super);
|
||
|
function ActionAdditionalElementNotFoundError(argumentName, apiFnArgs) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionAdditionalElementNotFoundError, apiFnArgs) || this;
|
||
|
_this.argumentName = argumentName;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionAdditionalElementNotFoundError;
|
||
|
}(SelectorErrorBase));
|
||
|
var ActionElementIsNotTargetError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementIsNotTargetError, _super);
|
||
|
function ActionElementIsNotTargetError(callsite) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementIsNotTargetError, callsite) || this;
|
||
|
}
|
||
|
return ActionElementIsNotTargetError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionAdditionalElementIsInvisibleError = /** @class */ (function (_super) {
|
||
|
__extends(ActionAdditionalElementIsInvisibleError, _super);
|
||
|
function ActionAdditionalElementIsInvisibleError(argumentName, apiFnArgs) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionAdditionalElementIsInvisibleError, apiFnArgs) || this;
|
||
|
_this.argumentName = argumentName;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionAdditionalElementIsInvisibleError;
|
||
|
}(SelectorErrorBase));
|
||
|
var ActionAdditionalSelectorMatchesWrongNodeTypeError = /** @class */ (function (_super) {
|
||
|
__extends(ActionAdditionalSelectorMatchesWrongNodeTypeError, _super);
|
||
|
function ActionAdditionalSelectorMatchesWrongNodeTypeError(argumentName, nodeDescription) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionAdditionalSelectorMatchesWrongNodeTypeError) || this;
|
||
|
_this.argumentName = argumentName;
|
||
|
_this.nodeDescription = nodeDescription;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionAdditionalSelectorMatchesWrongNodeTypeError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionElementNonEditableError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementNonEditableError, _super);
|
||
|
function ActionElementNonEditableError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementNonEditableError) || this;
|
||
|
}
|
||
|
return ActionElementNonEditableError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionElementNotTextAreaError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementNotTextAreaError, _super);
|
||
|
function ActionElementNotTextAreaError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementNotTextAreaError) || this;
|
||
|
}
|
||
|
return ActionElementNotTextAreaError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionElementNonContentEditableError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementNonContentEditableError, _super);
|
||
|
function ActionElementNonContentEditableError(argumentName) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionElementNonContentEditableError) || this;
|
||
|
_this.argumentName = argumentName;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionElementNonContentEditableError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionRootContainerNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(ActionRootContainerNotFoundError, _super);
|
||
|
function ActionRootContainerNotFoundError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionRootContainerNotFoundError) || this;
|
||
|
}
|
||
|
return ActionRootContainerNotFoundError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionIncorrectKeysError = /** @class */ (function (_super) {
|
||
|
__extends(ActionIncorrectKeysError, _super);
|
||
|
function ActionIncorrectKeysError(argumentName) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionIncorrectKeysError) || this;
|
||
|
_this.argumentName = argumentName;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionIncorrectKeysError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionCannotFindFileToUploadError = /** @class */ (function (_super) {
|
||
|
__extends(ActionCannotFindFileToUploadError, _super);
|
||
|
function ActionCannotFindFileToUploadError(filePaths, scannedFilePaths) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionCannotFindFileToUploadError) || this;
|
||
|
_this.filePaths = filePaths;
|
||
|
_this.scannedFilePaths = scannedFilePaths;
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionCannotFindFileToUploadError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionElementIsNotFileInputError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementIsNotFileInputError, _super);
|
||
|
function ActionElementIsNotFileInputError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementIsNotFileInputError) || this;
|
||
|
}
|
||
|
return ActionElementIsNotFileInputError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionInvalidScrollTargetError = /** @class */ (function (_super) {
|
||
|
__extends(ActionInvalidScrollTargetError, _super);
|
||
|
function ActionInvalidScrollTargetError(scrollTargetXValid, scrollTargetYValid) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.actionInvalidScrollTargetError) || this;
|
||
|
if (!scrollTargetXValid) {
|
||
|
if (!scrollTargetYValid)
|
||
|
_this.properties = 'scrollTargetX and scrollTargetY properties';
|
||
|
else
|
||
|
_this.properties = 'scrollTargetX property';
|
||
|
}
|
||
|
else
|
||
|
_this.properties = 'scrollTargetY property';
|
||
|
return _this;
|
||
|
}
|
||
|
return ActionInvalidScrollTargetError;
|
||
|
}(TestRunErrorBase));
|
||
|
var InvalidElementScreenshotDimensionsError = /** @class */ (function (_super) {
|
||
|
__extends(InvalidElementScreenshotDimensionsError, _super);
|
||
|
function InvalidElementScreenshotDimensionsError(width, height) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.invalidElementScreenshotDimensionsError) || this;
|
||
|
var widthIsInvalid = width <= 0;
|
||
|
var heightIsInvalid = height <= 0;
|
||
|
if (widthIsInvalid) {
|
||
|
if (heightIsInvalid) {
|
||
|
_this.verb = 'are';
|
||
|
_this.dimensions = 'width and height';
|
||
|
}
|
||
|
else {
|
||
|
_this.verb = 'is';
|
||
|
_this.dimensions = 'width';
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
_this.verb = 'is';
|
||
|
_this.dimensions = 'height';
|
||
|
}
|
||
|
return _this;
|
||
|
}
|
||
|
return InvalidElementScreenshotDimensionsError;
|
||
|
}(TestRunErrorBase));
|
||
|
// Iframe errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var ActionElementNotIframeError = /** @class */ (function (_super) {
|
||
|
__extends(ActionElementNotIframeError, _super);
|
||
|
function ActionElementNotIframeError(callsite) {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionElementNotIframeError, callsite) || this;
|
||
|
}
|
||
|
return ActionElementNotIframeError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ActionIframeIsNotLoadedError = /** @class */ (function (_super) {
|
||
|
__extends(ActionIframeIsNotLoadedError, _super);
|
||
|
function ActionIframeIsNotLoadedError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.actionIframeIsNotLoadedError) || this;
|
||
|
}
|
||
|
return ActionIframeIsNotLoadedError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CurrentIframeIsNotLoadedError = /** @class */ (function (_super) {
|
||
|
__extends(CurrentIframeIsNotLoadedError, _super);
|
||
|
function CurrentIframeIsNotLoadedError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.currentIframeIsNotLoadedError) || this;
|
||
|
}
|
||
|
return CurrentIframeIsNotLoadedError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ChildWindowNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(ChildWindowNotFoundError, _super);
|
||
|
function ChildWindowNotFoundError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.childWindowNotFoundError) || this;
|
||
|
}
|
||
|
return ChildWindowNotFoundError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ChildWindowIsNotLoadedError = /** @class */ (function (_super) {
|
||
|
__extends(ChildWindowIsNotLoadedError, _super);
|
||
|
function ChildWindowIsNotLoadedError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.childWindowIsNotLoadedError) || this;
|
||
|
}
|
||
|
return ChildWindowIsNotLoadedError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CannotSwitchToWindowError = /** @class */ (function (_super) {
|
||
|
__extends(CannotSwitchToWindowError, _super);
|
||
|
function CannotSwitchToWindowError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.cannotSwitchToWindowError) || this;
|
||
|
}
|
||
|
return CannotSwitchToWindowError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CloseChildWindowError = /** @class */ (function (_super) {
|
||
|
__extends(CloseChildWindowError, _super);
|
||
|
function CloseChildWindowError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.closeChildWindowError) || this;
|
||
|
}
|
||
|
return CloseChildWindowError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CannotCloseWindowWithChildrenError = /** @class */ (function (_super) {
|
||
|
__extends(CannotCloseWindowWithChildrenError, _super);
|
||
|
function CannotCloseWindowWithChildrenError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.cannotCloseWindowWithChildrenError) || this;
|
||
|
}
|
||
|
return CannotCloseWindowWithChildrenError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CannotCloseWindowWithoutParentError = /** @class */ (function (_super) {
|
||
|
__extends(CannotCloseWindowWithoutParentError, _super);
|
||
|
function CannotCloseWindowWithoutParentError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.cannotCloseWindowWithoutParent) || this;
|
||
|
}
|
||
|
return CannotCloseWindowWithoutParentError;
|
||
|
}(TestRunErrorBase));
|
||
|
var SwitchToWindowPredicateError = /** @class */ (function (_super) {
|
||
|
__extends(SwitchToWindowPredicateError, _super);
|
||
|
function SwitchToWindowPredicateError(errMsg) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.switchToWindowPredicateError) || this;
|
||
|
_this.errMsg = errMsg;
|
||
|
return _this;
|
||
|
}
|
||
|
return SwitchToWindowPredicateError;
|
||
|
}(TestRunErrorBase));
|
||
|
var WindowNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(WindowNotFoundError, _super);
|
||
|
function WindowNotFoundError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.targetWindowNotFoundError) || this;
|
||
|
}
|
||
|
return WindowNotFoundError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ParentWindowNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(ParentWindowNotFoundError, _super);
|
||
|
function ParentWindowNotFoundError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.parentWindowNotFoundError) || this;
|
||
|
}
|
||
|
return ParentWindowNotFoundError;
|
||
|
}(TestRunErrorBase));
|
||
|
var PreviousWindowNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(PreviousWindowNotFoundError, _super);
|
||
|
function PreviousWindowNotFoundError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.previousWindowNotFoundError) || this;
|
||
|
}
|
||
|
return PreviousWindowNotFoundError;
|
||
|
}(TestRunErrorBase));
|
||
|
var ChildWindowClosedBeforeSwitchingError = /** @class */ (function (_super) {
|
||
|
__extends(ChildWindowClosedBeforeSwitchingError, _super);
|
||
|
function ChildWindowClosedBeforeSwitchingError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.childWindowClosedBeforeSwitchingError) || this;
|
||
|
}
|
||
|
return ChildWindowClosedBeforeSwitchingError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CannotRestoreChildWindowError = /** @class */ (function (_super) {
|
||
|
__extends(CannotRestoreChildWindowError, _super);
|
||
|
function CannotRestoreChildWindowError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.cannotRestoreChildWindowError) || this;
|
||
|
}
|
||
|
return CannotRestoreChildWindowError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CurrentIframeNotFoundError = /** @class */ (function (_super) {
|
||
|
__extends(CurrentIframeNotFoundError, _super);
|
||
|
function CurrentIframeNotFoundError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.currentIframeNotFoundError) || this;
|
||
|
}
|
||
|
return CurrentIframeNotFoundError;
|
||
|
}(TestRunErrorBase));
|
||
|
var CurrentIframeIsInvisibleError = /** @class */ (function (_super) {
|
||
|
__extends(CurrentIframeIsInvisibleError, _super);
|
||
|
function CurrentIframeIsInvisibleError() {
|
||
|
return _super.call(this, TEST_RUN_ERRORS.currentIframeIsInvisibleError) || this;
|
||
|
}
|
||
|
return CurrentIframeIsInvisibleError;
|
||
|
}(TestRunErrorBase));
|
||
|
// Native dialog errors
|
||
|
//--------------------------------------------------------------------
|
||
|
var NativeDialogNotHandledError = /** @class */ (function (_super) {
|
||
|
__extends(NativeDialogNotHandledError, _super);
|
||
|
function NativeDialogNotHandledError(dialogType, url) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.nativeDialogNotHandledError) || this;
|
||
|
_this.dialogType = dialogType;
|
||
|
_this.pageUrl = url;
|
||
|
return _this;
|
||
|
}
|
||
|
return NativeDialogNotHandledError;
|
||
|
}(TestRunErrorBase));
|
||
|
var UncaughtErrorInNativeDialogHandler = /** @class */ (function (_super) {
|
||
|
__extends(UncaughtErrorInNativeDialogHandler, _super);
|
||
|
function UncaughtErrorInNativeDialogHandler(dialogType, errMsg, url) {
|
||
|
var _this = _super.call(this, TEST_RUN_ERRORS.uncaughtErrorInNativeDialogHandler) || this;
|
||
|
_this.dialogType = dialogType;
|
||
|
_this.errMsg = errMsg;
|
||
|
_this.pageUrl = url;
|
||
|
return _this;
|
||
|
}
|
||
|
return UncaughtErrorInNativeDialogHandler;
|
||
|
}(TestRunErrorBase));
|
||
|
|
||
|
var ACTION_STEP_DELAY_DEFAULT = 10;
|
||
|
var MAX_MOUSE_ACTION_STEP_DELAY = 400;
|
||
|
var MAX_KEY_ACTION_STEP_DELAY = 200;
|
||
|
// We use an exponential function to calculate the cursor
|
||
|
// speed according to general test speed
|
||
|
// cursorSpeed = (maxSpeed * k) ^ speed / k
|
||
|
var MAX_CURSOR_SPEED = 100; // pixels/ms
|
||
|
var MAX_DRAGGING_SPEED = 4; // pixels/ms
|
||
|
var CURSOR_FACTOR = 4;
|
||
|
var AutomationSettings = /** @class */ (function () {
|
||
|
function AutomationSettings(speed) {
|
||
|
this._speedFactor = speed || 1;
|
||
|
}
|
||
|
Object.defineProperty(AutomationSettings.prototype, "mouseActionStepDelay", {
|
||
|
get: function () {
|
||
|
return this._speedFactor === 1 ? ACTION_STEP_DELAY_DEFAULT : (1 - this._speedFactor) * MAX_MOUSE_ACTION_STEP_DELAY;
|
||
|
},
|
||
|
enumerable: false,
|
||
|
configurable: true
|
||
|
});
|
||
|
Object.defineProperty(AutomationSettings.prototype, "keyActionStepDelay", {
|
||
|
get: function () {
|
||
|
return this._speedFactor === 1 ? ACTION_STEP_DELAY_DEFAULT : (1 - this._speedFactor) * MAX_KEY_ACTION_STEP_DELAY;
|
||
|
},
|
||
|
enumerable: false,
|
||
|
configurable: true
|
||
|
});
|
||
|
Object.defineProperty(AutomationSettings.prototype, "cursorSpeed", {
|
||
|
get: function () {
|
||
|
return Math.pow(MAX_CURSOR_SPEED * CURSOR_FACTOR, this._speedFactor) / CURSOR_FACTOR;
|
||
|
},
|
||
|
enumerable: false,
|
||
|
configurable: true
|
||
|
});
|
||
|
Object.defineProperty(AutomationSettings.prototype, "draggingSpeed", {
|
||
|
get: function () {
|
||
|
return Math.pow(MAX_DRAGGING_SPEED * CURSOR_FACTOR, this._speedFactor) / CURSOR_FACTOR;
|
||
|
},
|
||
|
enumerable: false,
|
||
|
configurable: true
|
||
|
});
|
||
|
return AutomationSettings;
|
||
|
}());
|
||
|
|
||
|
var Promise = hammerhead__default.Promise;
|
||
|
var nativeMethods$4 = hammerhead__default.nativeMethods;
|
||
|
function delay (ms) {
|
||
|
return new Promise(function (resolve) { return nativeMethods$4.setTimeout.call(window, resolve, ms); });
|
||
|
}
|
||
|
|
||
|
function nextTick() {
|
||
|
return delay(0);
|
||
|
}
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
// WARNING: this file is used by both the client and the server.
|
||
|
// Do not use any browser or node-specific API!
|
||
|
// -------------------------------------------------------------
|
||
|
var objectToString = Object.prototype.toString;
|
||
|
var stringIndexOf = String.prototype.indexOf;
|
||
|
var stringEndsWith = String.prototype.endsWith
|
||
|
|| function (searchString, position) {
|
||
|
var subjectString = objectToString.call(this);
|
||
|
if (position === void 0 || position > subjectString.length)
|
||
|
position = subjectString.length;
|
||
|
position -= searchString.length;
|
||
|
var lastIndex = stringIndexOf.call(subjectString, searchString, position);
|
||
|
return lastIndex !== -1 && lastIndex === position;
|
||
|
};
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
var arrayIndexOf = Array.prototype.indexOf;
|
||
|
var arrayMap = Array.prototype.map;
|
||
|
var arraySort = Array.prototype.sort;
|
||
|
var arrayFilter = Array.prototype.filter;
|
||
|
var arrayConcat = Array.prototype.concat;
|
||
|
var COMMAND_NAME_SUFFIX = 'Command';
|
||
|
function validateObjectProps(obj, dest) {
|
||
|
var objectName = dest.constructor.name;
|
||
|
var validKeys = arrayMap.call(dest.getAllAssignableProperties(), function (p) { return p.name; });
|
||
|
var reportedProperties = arraySort.call(dest.getReportedProperties());
|
||
|
for (var key in obj) {
|
||
|
if (!(arrayIndexOf.call(validKeys, key) > -1 || key in dest))
|
||
|
throw new ActionInvalidObjectPropertyError(objectName, key, reportedProperties);
|
||
|
}
|
||
|
}
|
||
|
function getDisplayTypeName(constructorName, propName) {
|
||
|
if (stringEndsWith.call(constructorName, COMMAND_NAME_SUFFIX))
|
||
|
return propName;
|
||
|
return "".concat(constructorName, ".").concat(propName);
|
||
|
}
|
||
|
var Assignable = /** @class */ (function () {
|
||
|
function Assignable() {
|
||
|
}
|
||
|
Assignable.prototype.getAssignableProperties = function () {
|
||
|
return [];
|
||
|
};
|
||
|
Assignable.prototype.getAllAssignableProperties = function () {
|
||
|
var parent = Object.getPrototypeOf(this);
|
||
|
var result = [];
|
||
|
while (parent && parent.getAssignableProperties) {
|
||
|
result = arrayConcat.call(result, parent.getAssignableProperties());
|
||
|
parent = Object.getPrototypeOf(parent);
|
||
|
}
|
||
|
return result;
|
||
|
};
|
||
|
Assignable.prototype.getNonReportedProperties = function () {
|
||
|
return [];
|
||
|
};
|
||
|
Assignable.prototype.getReportedProperties = function () {
|
||
|
var props = arrayMap.call(this.getAllAssignableProperties(), function (prop) { return prop.name; });
|
||
|
var nonReportedProps = this.getNonReportedProperties();
|
||
|
return arrayFilter.call(props, function (name) { return !(arrayIndexOf.call(nonReportedProps, name) > -1); });
|
||
|
};
|
||
|
Assignable.prototype._assignFrom = function (obj, validate, initOptions) {
|
||
|
if (initOptions === void 0) { initOptions = {}; }
|
||
|
if (!obj)
|
||
|
return;
|
||
|
if (validate)
|
||
|
validateObjectProps(obj, this);
|
||
|
var props = this.getAllAssignableProperties();
|
||
|
for (var i = 0; i < props.length; i++) {
|
||
|
var _a = props[i], name_1 = _a.name, type = _a.type, required = _a.required, init = _a.init, defaultValue = _a.defaultValue;
|
||
|
if (defaultValue !== void 0)
|
||
|
this[name_1] = defaultValue;
|
||
|
var srcVal = obj[name_1];
|
||
|
if (srcVal === void 0 && !required)
|
||
|
continue;
|
||
|
if (validate && type) {
|
||
|
var typeName = getDisplayTypeName(this.constructor.name, name_1);
|
||
|
type(typeName, srcVal);
|
||
|
}
|
||
|
this[name_1] = init ? init(name_1, srcVal, initOptions, validate) : srcVal;
|
||
|
}
|
||
|
};
|
||
|
return Assignable;
|
||
|
}());
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
// WARNING: this file is used by both the client and the server.
|
||
|
// Do not use any browser or node-specific API!
|
||
|
// -------------------------------------------------------------
|
||
|
function createIntegerValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'number')
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
var isInteger = !isNaN(val) &&
|
||
|
isFinite(val) &&
|
||
|
val === Math.floor(val);
|
||
|
if (!isInteger)
|
||
|
throw new ErrorCtor(name, val);
|
||
|
};
|
||
|
}
|
||
|
function createPositiveIntegerValidator(ErrorCtor) {
|
||
|
var integerValidator = createIntegerValidator(ErrorCtor);
|
||
|
return function (name, val) {
|
||
|
integerValidator(name, val);
|
||
|
if (val < 0)
|
||
|
throw new ErrorCtor(name, val);
|
||
|
};
|
||
|
}
|
||
|
function createBooleanValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'boolean')
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
function createSpeedValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'number')
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
if (isNaN(val) || val < 0.01 || val > 1)
|
||
|
throw new ErrorCtor(name, val);
|
||
|
};
|
||
|
}
|
||
|
function createStringValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'string')
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
function createStringOrRegexValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'string' && !(val instanceof RegExp))
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
function createDateValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
if (!(val instanceof Date))
|
||
|
throw new ErrorCtor(name, val);
|
||
|
};
|
||
|
}
|
||
|
function createNumberValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
if (isNaN(Number(val)))
|
||
|
throw new ErrorCtor(name, typeof val);
|
||
|
};
|
||
|
}
|
||
|
function createUrlValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'string' && !(val instanceof URL))
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
function createUrlSearchParamsValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'object' && !(val instanceof URLSearchParams))
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
function createObjectValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'object')
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
function createFunctionValidator(ErrorCtor) {
|
||
|
return function (name, val) {
|
||
|
var valType = typeof val;
|
||
|
if (valType !== 'function')
|
||
|
throw new ErrorCtor(name, valType);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
var integerOption = createIntegerValidator(ActionIntegerOptionError);
|
||
|
var positiveIntegerOption = createPositiveIntegerValidator(ActionPositiveIntegerOptionError);
|
||
|
var booleanOption = createBooleanValidator(ActionBooleanOptionError);
|
||
|
var speedOption = createSpeedValidator(ActionSpeedOptionError);
|
||
|
var stringOption = createStringValidator(ActionStringOptionError);
|
||
|
var stringOrRegexOption = createStringOrRegexValidator(ActionStringOrRegexOptionError);
|
||
|
var dateOption = createDateValidator(ActionDateOptionError);
|
||
|
var numberOption = createNumberValidator(ActionNumberOptionError);
|
||
|
var urlOption = createUrlValidator(ActionUrlOptionError);
|
||
|
var urlSearchParamsOption = createUrlSearchParamsValidator(ActionUrlSearchParamsOptionError);
|
||
|
var objectOption = createObjectValidator(ActionObjectOptionError);
|
||
|
var functionOption = createFunctionValidator(ActionFunctionOptionError);
|
||
|
// Actions
|
||
|
var ActionOptions = /** @class */ (function (_super) {
|
||
|
__extends(ActionOptions, _super);
|
||
|
function ActionOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.speed = null;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
ActionOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'speed', type: speedOption },
|
||
|
];
|
||
|
};
|
||
|
return ActionOptions;
|
||
|
}(Assignable));
|
||
|
// Offset
|
||
|
var OffsetOptions = /** @class */ (function (_super) {
|
||
|
__extends(OffsetOptions, _super);
|
||
|
function OffsetOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.offsetX = null;
|
||
|
_this.offsetY = null;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
OffsetOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'offsetX', type: integerOption },
|
||
|
{ name: 'offsetY', type: integerOption },
|
||
|
{ name: 'isDefaultOffset', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return OffsetOptions;
|
||
|
}(ActionOptions));
|
||
|
var ScrollOptions = /** @class */ (function (_super) {
|
||
|
__extends(ScrollOptions, _super);
|
||
|
function ScrollOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.scrollToCenter = false;
|
||
|
_this.skipParentFrames = false;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
ScrollOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'scrollToCenter', type: booleanOption },
|
||
|
{ name: 'skipParentFrames', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return ScrollOptions;
|
||
|
}(OffsetOptions));
|
||
|
var CropOptions = /** @class */ (function (_super) {
|
||
|
__extends(CropOptions, _super);
|
||
|
function CropOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
CropOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'left', type: integerOption, defaultValue: null },
|
||
|
{ name: 'right', type: integerOption, defaultValue: null },
|
||
|
{ name: 'top', type: integerOption, defaultValue: null },
|
||
|
{ name: 'bottom', type: integerOption, defaultValue: null },
|
||
|
];
|
||
|
};
|
||
|
return CropOptions;
|
||
|
}(Assignable));
|
||
|
// Element Screenshot
|
||
|
var ElementScreenshotOptions = /** @class */ (function (_super) {
|
||
|
__extends(ElementScreenshotOptions, _super);
|
||
|
function ElementScreenshotOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.scrollTargetX = null;
|
||
|
_this.scrollTargetY = null;
|
||
|
_this.includeMargins = false;
|
||
|
_this.includeBorders = true;
|
||
|
_this.includePaddings = true;
|
||
|
_this.crop = {
|
||
|
left: null,
|
||
|
right: null,
|
||
|
top: null,
|
||
|
bottom: null,
|
||
|
};
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
ElementScreenshotOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'scrollTargetX', type: integerOption },
|
||
|
{ name: 'scrollTargetY', type: integerOption },
|
||
|
{ name: 'crop', type: objectOption, init: initCropOptions },
|
||
|
{ name: 'includeMargins', type: booleanOption },
|
||
|
{ name: 'includeBorders', type: booleanOption },
|
||
|
{ name: 'includePaddings', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return ElementScreenshotOptions;
|
||
|
}(ActionOptions));
|
||
|
var ModifiersOptions = /** @class */ (function (_super) {
|
||
|
__extends(ModifiersOptions, _super);
|
||
|
function ModifiersOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
ModifiersOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'ctrl', type: booleanOption, defaultValue: false },
|
||
|
{ name: 'alt', type: booleanOption, defaultValue: false },
|
||
|
{ name: 'shift', type: booleanOption, defaultValue: false },
|
||
|
{ name: 'meta', type: booleanOption, defaultValue: false },
|
||
|
];
|
||
|
};
|
||
|
return ModifiersOptions;
|
||
|
}(Assignable));
|
||
|
// Mouse
|
||
|
var MouseOptions = /** @class */ (function (_super) {
|
||
|
__extends(MouseOptions, _super);
|
||
|
function MouseOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.modifiers = {
|
||
|
ctrl: false,
|
||
|
alt: false,
|
||
|
shift: false,
|
||
|
meta: false,
|
||
|
};
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
MouseOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'modifiers', type: objectOption, init: initModifiersOptions },
|
||
|
];
|
||
|
};
|
||
|
return MouseOptions;
|
||
|
}(OffsetOptions));
|
||
|
// Click
|
||
|
var ClickOptions = /** @class */ (function (_super) {
|
||
|
__extends(ClickOptions, _super);
|
||
|
function ClickOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.caretPos = null;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
ClickOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'caretPos', type: positiveIntegerOption },
|
||
|
];
|
||
|
};
|
||
|
return ClickOptions;
|
||
|
}(MouseOptions));
|
||
|
// Move
|
||
|
var MoveOptions = /** @class */ (function (_super) {
|
||
|
__extends(MoveOptions, _super);
|
||
|
function MoveOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.speed = null;
|
||
|
_this.minMovingTime = null;
|
||
|
_this.holdLeftButton = false;
|
||
|
_this.skipScrolling = false;
|
||
|
_this.skipDefaultDragBehavior = false;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
MoveOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'speed' },
|
||
|
{ name: 'minMovingTime' },
|
||
|
{ name: 'holdLeftButton' },
|
||
|
{ name: 'skipScrolling', type: booleanOption },
|
||
|
{ name: 'skipDefaultDragBehavior', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return MoveOptions;
|
||
|
}(MouseOptions));
|
||
|
// Type
|
||
|
var TypeOptions = /** @class */ (function (_super) {
|
||
|
__extends(TypeOptions, _super);
|
||
|
function TypeOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.replace = false;
|
||
|
_this.paste = false;
|
||
|
_this.confidential = void 0;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
TypeOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'replace', type: booleanOption },
|
||
|
{ name: 'paste', type: booleanOption },
|
||
|
{ name: 'confidential', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return TypeOptions;
|
||
|
}(ClickOptions));
|
||
|
// DragToElement
|
||
|
var DragToElementOptions = /** @class */ (function (_super) {
|
||
|
__extends(DragToElementOptions, _super);
|
||
|
function DragToElementOptions(obj, validate) {
|
||
|
var _this = _super.call(this, obj, validate) || this;
|
||
|
_this.destinationOffsetX = null;
|
||
|
_this.destinationOffsetY = null;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
DragToElementOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'destinationOffsetX', type: integerOption },
|
||
|
{ name: 'destinationOffsetY', type: integerOption },
|
||
|
];
|
||
|
};
|
||
|
return DragToElementOptions;
|
||
|
}(MouseOptions));
|
||
|
//ResizeToFitDevice
|
||
|
var ResizeToFitDeviceOptions = /** @class */ (function (_super) {
|
||
|
__extends(ResizeToFitDeviceOptions, _super);
|
||
|
function ResizeToFitDeviceOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.portraitOrientation = false;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
ResizeToFitDeviceOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'portraitOrientation', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return ResizeToFitDeviceOptions;
|
||
|
}(Assignable));
|
||
|
//Assertion
|
||
|
var AssertionOptions = /** @class */ (function (_super) {
|
||
|
__extends(AssertionOptions, _super);
|
||
|
function AssertionOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.timeout = void 0;
|
||
|
_this.allowUnawaitedPromise = false;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
AssertionOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'timeout', type: positiveIntegerOption },
|
||
|
{ name: 'allowUnawaitedPromise', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return AssertionOptions;
|
||
|
}(Assignable));
|
||
|
// Press
|
||
|
var PressOptions = /** @class */ (function (_super) {
|
||
|
__extends(PressOptions, _super);
|
||
|
function PressOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.confidential = void 0;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
PressOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'confidential', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return PressOptions;
|
||
|
}(ActionOptions));
|
||
|
// Cookie
|
||
|
var CookieOptions = /** @class */ (function (_super) {
|
||
|
__extends(CookieOptions, _super);
|
||
|
function CookieOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
CookieOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'name', type: stringOption },
|
||
|
{ name: 'value', type: stringOption },
|
||
|
{ name: 'domain', type: stringOption },
|
||
|
{ name: 'path', type: stringOption },
|
||
|
{ name: 'expires', type: dateOption },
|
||
|
{ name: 'maxAge', type: numberOption },
|
||
|
{ name: 'secure', type: booleanOption },
|
||
|
{ name: 'httpOnly', type: booleanOption },
|
||
|
{ name: 'sameSite', type: stringOption },
|
||
|
];
|
||
|
};
|
||
|
return CookieOptions;
|
||
|
}(Assignable));
|
||
|
var RequestAuthOptions = /** @class */ (function (_super) {
|
||
|
__extends(RequestAuthOptions, _super);
|
||
|
function RequestAuthOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
RequestAuthOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'username', type: stringOption, required: true },
|
||
|
{ name: 'password', type: stringOption },
|
||
|
];
|
||
|
};
|
||
|
return RequestAuthOptions;
|
||
|
}(Assignable));
|
||
|
var RequestProxyOptions = /** @class */ (function (_super) {
|
||
|
__extends(RequestProxyOptions, _super);
|
||
|
function RequestProxyOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
RequestProxyOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'protocol', type: stringOption },
|
||
|
{ name: 'host', type: stringOption, required: true },
|
||
|
{ name: 'port', type: numberOption, required: true },
|
||
|
{ name: 'auth', type: objectOption, init: initRequestAuthOption },
|
||
|
];
|
||
|
};
|
||
|
return RequestProxyOptions;
|
||
|
}(Assignable));
|
||
|
var RequestOptions = /** @class */ (function (_super) {
|
||
|
__extends(RequestOptions, _super);
|
||
|
function RequestOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
RequestOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'url', type: urlOption },
|
||
|
{ name: 'method', type: stringOption },
|
||
|
{ name: 'headers', type: objectOption },
|
||
|
{ name: 'params', type: urlSearchParamsOption },
|
||
|
{ name: 'body' },
|
||
|
{ name: 'timeout', type: numberOption },
|
||
|
{ name: 'withCredentials', type: booleanOption },
|
||
|
{ name: 'auth', type: objectOption, init: initRequestAuthOption },
|
||
|
{ name: 'proxy', type: objectOption, init: initRequestProxyOptions },
|
||
|
{ name: 'rawResponse', type: booleanOption },
|
||
|
];
|
||
|
};
|
||
|
return RequestOptions;
|
||
|
}(Assignable));
|
||
|
var GetProxyUrlOptions = /** @class */ (function (_super) {
|
||
|
__extends(GetProxyUrlOptions, _super);
|
||
|
function GetProxyUrlOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
GetProxyUrlOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'credentials', type: numberOption },
|
||
|
];
|
||
|
};
|
||
|
return GetProxyUrlOptions;
|
||
|
}(Assignable));
|
||
|
var SkipJsErrorsOptions = /** @class */ (function (_super) {
|
||
|
__extends(SkipJsErrorsOptions, _super);
|
||
|
function SkipJsErrorsOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
SkipJsErrorsOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'stack', type: stringOrRegexOption, required: false },
|
||
|
{ name: 'message', type: stringOrRegexOption, required: false },
|
||
|
{ name: 'pageUrl', type: stringOrRegexOption, required: false },
|
||
|
];
|
||
|
};
|
||
|
return SkipJsErrorsOptions;
|
||
|
}(Assignable));
|
||
|
var SkipJsErrorsCallbackWithOptions = /** @class */ (function (_super) {
|
||
|
__extends(SkipJsErrorsCallbackWithOptions, _super);
|
||
|
function SkipJsErrorsCallbackWithOptions(obj, validate) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this._assignFrom(obj, validate);
|
||
|
return _this;
|
||
|
}
|
||
|
SkipJsErrorsCallbackWithOptions.prototype.getAssignableProperties = function () {
|
||
|
return [
|
||
|
{ name: 'fn', type: functionOption, required: true },
|
||
|
{ name: 'dependencies', type: objectOption, required: false },
|
||
|
];
|
||
|
};
|
||
|
return SkipJsErrorsCallbackWithOptions;
|
||
|
}(Assignable));
|
||
|
// Initializers
|
||
|
function initRequestAuthOption(name, val, initOptions, validate) {
|
||
|
if (validate === void 0) { validate = true; }
|
||
|
return new RequestAuthOptions(val, validate);
|
||
|
}
|
||
|
function initRequestProxyOptions(name, val, initOptions, validate) {
|
||
|
if (validate === void 0) { validate = true; }
|
||
|
return new RequestProxyOptions(val, validate);
|
||
|
}
|
||
|
function initCropOptions(name, val, initOptions, validate) {
|
||
|
if (validate === void 0) { validate = true; }
|
||
|
return new CropOptions(val, validate);
|
||
|
}
|
||
|
function initModifiersOptions(name, val, initOptions, validate) {
|
||
|
if (validate === void 0) { validate = true; }
|
||
|
return new ModifiersOptions(val, validate);
|
||
|
}
|
||
|
|
||
|
var lastHoveredElement = null;
|
||
|
var lastHoveredElementHolder = {
|
||
|
get: function () {
|
||
|
return lastHoveredElement;
|
||
|
},
|
||
|
set: function (element) {
|
||
|
lastHoveredElement = element;
|
||
|
},
|
||
|
};
|
||
|
|
||
|
var Promise$1 = hammerhead__default.Promise;
|
||
|
var nativeMethods$5 = hammerhead__default.nativeMethods;
|
||
|
var listeners = hammerhead__default.eventSandbox.listeners;
|
||
|
var browserUtils$1 = hammerhead__default.utils.browser;
|
||
|
// Imported form the hammerhead
|
||
|
var BUTTON = hammerhead__default.utils.event.BUTTON;
|
||
|
var BUTTONS_PARAMETER = hammerhead__default.utils.event.BUTTONS_PARAMETER;
|
||
|
var DOM_EVENTS = hammerhead__default.utils.event.DOM_EVENTS;
|
||
|
var WHICH_PARAMETER = hammerhead__default.utils.event.WHICH_PARAMETER;
|
||
|
var preventDefault = hammerhead__default.utils.event.preventDefault;
|
||
|
|
||
|
function whilst(condition, iterator) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
if (!condition()) return [3 /*break*/, 2];
|
||
|
return [4 /*yield*/, iterator()];
|
||
|
case 1:
|
||
|
_a.sent();
|
||
|
return [3 /*break*/, 0];
|
||
|
case 2: return [2 /*return*/];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function times(n, iterator) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var i;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
i = 0;
|
||
|
_a.label = 1;
|
||
|
case 1:
|
||
|
if (!(i < n)) return [3 /*break*/, 4];
|
||
|
return [4 /*yield*/, iterator(i)];
|
||
|
case 2:
|
||
|
_a.sent();
|
||
|
_a.label = 3;
|
||
|
case 3:
|
||
|
i++;
|
||
|
return [3 /*break*/, 1];
|
||
|
case 4: return [2 /*return*/];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function isIframeWindow(window) {
|
||
|
return window.top !== window;
|
||
|
}
|
||
|
|
||
|
var Promise$2 = hammerhead__default.Promise;
|
||
|
var messageSandbox = hammerhead__default.eventSandbox.message;
|
||
|
function sendRequestToFrame(msg, responseCmd, receiverWindow) {
|
||
|
return new Promise$2(function (resolve) {
|
||
|
function onMessage(e) {
|
||
|
if (e.message.cmd === responseCmd) {
|
||
|
messageSandbox.off(messageSandbox.SERVICE_MSG_RECEIVED_EVENT, onMessage);
|
||
|
resolve(e.message);
|
||
|
}
|
||
|
}
|
||
|
messageSandbox.on(messageSandbox.SERVICE_MSG_RECEIVED_EVENT, onMessage);
|
||
|
messageSandbox.sendServiceMsg(msg, receiverWindow);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// @ts-ignore
|
||
|
var EventEmitter = /** @class */ (function () {
|
||
|
function EventEmitter() {
|
||
|
this._eventsListeners = {};
|
||
|
}
|
||
|
EventEmitter.prototype.on = function (evt, listener) {
|
||
|
if (!this._eventsListeners[evt])
|
||
|
this._eventsListeners[evt] = [];
|
||
|
this._eventsListeners[evt].push(listener);
|
||
|
};
|
||
|
EventEmitter.prototype.once = function (evt, listener) {
|
||
|
var _this = this;
|
||
|
this.on(evt, function () {
|
||
|
var args = [];
|
||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||
|
args[_i] = arguments[_i];
|
||
|
}
|
||
|
_this.off(evt, listener);
|
||
|
return listener.apply(void 0, args);
|
||
|
});
|
||
|
};
|
||
|
EventEmitter.prototype.off = function (evt, listener) {
|
||
|
var listeners = this._eventsListeners[evt];
|
||
|
if (listeners)
|
||
|
this._eventsListeners[evt] = hammerhead.nativeMethods.arrayFilter.call(listeners, function (item) { return item !== listener; });
|
||
|
};
|
||
|
EventEmitter.prototype.offAll = function (evt) {
|
||
|
if (evt)
|
||
|
this._eventsListeners[evt] = [];
|
||
|
else
|
||
|
this._eventsListeners = {};
|
||
|
};
|
||
|
EventEmitter.prototype.emit = function (evt) {
|
||
|
var args = [];
|
||
|
for (var _i = 1; _i < arguments.length; _i++) {
|
||
|
args[_i - 1] = arguments[_i];
|
||
|
}
|
||
|
var listeners = this._eventsListeners[evt];
|
||
|
if (!listeners)
|
||
|
return;
|
||
|
for (var i = 0; i < listeners.length; i++) {
|
||
|
try {
|
||
|
listeners[i].apply(this, args);
|
||
|
}
|
||
|
catch (e) {
|
||
|
// Hack for IE: after document.write calling IFrameSandbox event handlers
|
||
|
// rises 'Can't execute code from a freed script' exception because document has been
|
||
|
// recreated
|
||
|
if (e.message && e.message.indexOf('freed script') > -1)
|
||
|
this.off(evt, listeners[i]);
|
||
|
else
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
return EventEmitter;
|
||
|
}());
|
||
|
|
||
|
var EventEmitter$1 = EventEmitter;
|
||
|
|
||
|
var listeners$1 = hammerhead.eventSandbox.listeners;
|
||
|
var ScrollController = /** @class */ (function () {
|
||
|
function ScrollController() {
|
||
|
this.initialized = false;
|
||
|
this.stopPropagationFlag = false;
|
||
|
this.events = new EventEmitter$1();
|
||
|
}
|
||
|
ScrollController.prototype._internalListener = function (event, dispatched, preventEvent, cancelHandlers, stopPropagation) {
|
||
|
this.events.emit('scroll', event);
|
||
|
if (this.stopPropagationFlag) {
|
||
|
cancelHandlers();
|
||
|
stopPropagation();
|
||
|
}
|
||
|
};
|
||
|
ScrollController.prototype.init = function () {
|
||
|
var _this = this;
|
||
|
if (this.initialized)
|
||
|
return;
|
||
|
this.initialized = true;
|
||
|
listeners$1.initElementListening(window, ['scroll']);
|
||
|
listeners$1.addFirstInternalEventBeforeListener(window, ['scroll'], function () {
|
||
|
var args = [];
|
||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||
|
args[_i] = arguments[_i];
|
||
|
}
|
||
|
return _this._internalListener.apply(_this, args);
|
||
|
});
|
||
|
};
|
||
|
ScrollController.prototype.waitForScroll = function (scrollElement) {
|
||
|
var _this = this;
|
||
|
var promiseResolver = null;
|
||
|
var promise = new hammerhead.Promise(function (resolve) {
|
||
|
promiseResolver = resolve;
|
||
|
});
|
||
|
promise.cancel = function () { return _this.events.off('scroll', promiseResolver); };
|
||
|
if (this.initialized)
|
||
|
this.handleScrollEvents(scrollElement, promiseResolver);
|
||
|
else
|
||
|
promiseResolver();
|
||
|
return promise;
|
||
|
};
|
||
|
ScrollController.prototype.handleScrollEvents = function (el, handler) {
|
||
|
var _this = this;
|
||
|
this.events.once('scroll', handler);
|
||
|
if (isShadowElement(el)) {
|
||
|
listeners$1.initElementListening(el, ['scroll']);
|
||
|
listeners$1.addFirstInternalEventBeforeListener(el, ['scroll'], function () {
|
||
|
var args = [];
|
||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||
|
args[_i] = arguments[_i];
|
||
|
}
|
||
|
_this._internalListener.apply(_this, args);
|
||
|
listeners$1.cancelElementListening(el);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
ScrollController.prototype.stopPropagation = function () {
|
||
|
this.stopPropagationFlag = true;
|
||
|
};
|
||
|
ScrollController.prototype.enablePropagation = function () {
|
||
|
this.stopPropagationFlag = false;
|
||
|
};
|
||
|
return ScrollController;
|
||
|
}());
|
||
|
var scrollController = new ScrollController();
|
||
|
|
||
|
var DEFAULT_MAX_SCROLL_MARGIN = 50;
|
||
|
var SCROLL_MARGIN_INCREASE_STEP = 20;
|
||
|
var ScrollAutomation = /** @class */ (function () {
|
||
|
function ScrollAutomation(element, scrollOptions, maxScrollMargin) {
|
||
|
this._element = element;
|
||
|
this._offsets = new AxisValues(scrollOptions.offsetX, scrollOptions.offsetY);
|
||
|
this._scrollToCenter = !!scrollOptions.scrollToCenter;
|
||
|
this._skipParentFrames = !!scrollOptions.skipParentFrames;
|
||
|
this._maxScrollMargin = maxScrollMargin || { left: DEFAULT_MAX_SCROLL_MARGIN, top: DEFAULT_MAX_SCROLL_MARGIN };
|
||
|
this._scrollWasPerformed = false;
|
||
|
}
|
||
|
ScrollAutomation._isScrollValuesChanged = function (scrollElement, originalScroll) {
|
||
|
return getScrollLeft(scrollElement) !== originalScroll.left ||
|
||
|
getScrollTop(scrollElement) !== originalScroll.top;
|
||
|
};
|
||
|
ScrollAutomation.prototype._setScroll = function (element, _a) {
|
||
|
var _this = this;
|
||
|
var left = _a.left, top = _a.top;
|
||
|
var scrollElement = isHtmlElement(element) ? findDocument(element) : element;
|
||
|
var originalScroll = {
|
||
|
left: getScrollLeft(scrollElement),
|
||
|
top: getScrollTop(scrollElement),
|
||
|
};
|
||
|
left = Math.max(left, 0);
|
||
|
top = Math.max(top, 0);
|
||
|
var scrollPromise = scrollController.waitForScroll(scrollElement);
|
||
|
setScrollLeft(scrollElement, left);
|
||
|
setScrollTop(scrollElement, top);
|
||
|
if (!ScrollAutomation._isScrollValuesChanged(scrollElement, originalScroll)) {
|
||
|
// @ts-ignore
|
||
|
scrollPromise.cancel();
|
||
|
return hammerhead.Promise.resolve();
|
||
|
}
|
||
|
scrollPromise = scrollPromise.then(function () {
|
||
|
if (!_this._scrollWasPerformed)
|
||
|
_this._scrollWasPerformed = ScrollAutomation._isScrollValuesChanged(scrollElement, originalScroll);
|
||
|
});
|
||
|
return scrollPromise;
|
||
|
};
|
||
|
ScrollAutomation.prototype._getScrollToPoint = function (dimensions, point, maxScrollMargin) {
|
||
|
var horizontalCenter = Math.floor(dimensions.width / 2);
|
||
|
var verticalCenter = Math.floor(dimensions.height / 2);
|
||
|
var leftScrollMargin = this._scrollToCenter ? horizontalCenter : Math.min(maxScrollMargin.left, horizontalCenter);
|
||
|
var topScrollMargin = this._scrollToCenter ? verticalCenter : Math.min(maxScrollMargin.top, verticalCenter);
|
||
|
var _a = dimensions.scroll, left = _a.left, top = _a.top;
|
||
|
var needForwardScrollLeft = point.x >= left + dimensions.width - leftScrollMargin;
|
||
|
var needBackwardScrollLeft = point.x <= left + leftScrollMargin;
|
||
|
var needForwardScrollTop = point.y >= top + dimensions.height - topScrollMargin;
|
||
|
var needBackwardScrollTop = point.y <= top + topScrollMargin;
|
||
|
if (needForwardScrollLeft)
|
||
|
left = point.x - dimensions.width + leftScrollMargin;
|
||
|
else if (needBackwardScrollLeft)
|
||
|
left = point.x - leftScrollMargin;
|
||
|
if (needForwardScrollTop)
|
||
|
top = point.y - dimensions.height + topScrollMargin;
|
||
|
else if (needBackwardScrollTop)
|
||
|
top = point.y - topScrollMargin;
|
||
|
return { left: left, top: top };
|
||
|
};
|
||
|
ScrollAutomation.prototype._getScrollToFullChildView = function (parentDimensions, childDimensions, maxScrollMargin) {
|
||
|
var fullViewScroll = { left: null, top: null };
|
||
|
var canShowFullElementWidth = parentDimensions.width >= childDimensions.width;
|
||
|
var canShowFullElementHeight = parentDimensions.height >= childDimensions.height;
|
||
|
var relativePosition = calcRelativePosition(childDimensions, parentDimensions);
|
||
|
if (canShowFullElementWidth) {
|
||
|
var availableLeftScrollMargin = parentDimensions.width - childDimensions.width;
|
||
|
var leftScrollMargin = Math.min(maxScrollMargin.left, availableLeftScrollMargin);
|
||
|
if (this._scrollToCenter)
|
||
|
leftScrollMargin = availableLeftScrollMargin / 2;
|
||
|
if (relativePosition.left < leftScrollMargin)
|
||
|
fullViewScroll.left = Math.round(parentDimensions.scroll.left + relativePosition.left - leftScrollMargin);
|
||
|
else if (relativePosition.right < leftScrollMargin) {
|
||
|
fullViewScroll.left = Math.round(parentDimensions.scroll.left +
|
||
|
Math.min(relativePosition.left, -relativePosition.right) +
|
||
|
leftScrollMargin);
|
||
|
}
|
||
|
}
|
||
|
if (canShowFullElementHeight) {
|
||
|
var availableTopScrollMargin = parentDimensions.height - childDimensions.height;
|
||
|
var topScrollMargin = Math.min(maxScrollMargin.top, availableTopScrollMargin);
|
||
|
if (this._scrollToCenter)
|
||
|
topScrollMargin = availableTopScrollMargin / 2;
|
||
|
if (relativePosition.top < topScrollMargin)
|
||
|
fullViewScroll.top = Math.round(parentDimensions.scroll.top + relativePosition.top - topScrollMargin);
|
||
|
else if (relativePosition.bottom < topScrollMargin) {
|
||
|
fullViewScroll.top = Math.round(parentDimensions.scroll.top +
|
||
|
Math.min(relativePosition.top, -relativePosition.bottom) +
|
||
|
topScrollMargin);
|
||
|
}
|
||
|
}
|
||
|
return fullViewScroll;
|
||
|
};
|
||
|
ScrollAutomation._getChildPoint = function (parentDimensions, childDimensions, offsets) {
|
||
|
return AxisValues.create(childDimensions)
|
||
|
.sub(AxisValues.create(parentDimensions))
|
||
|
.add(AxisValues.create(parentDimensions.scroll))
|
||
|
.add(AxisValues.create(childDimensions.border))
|
||
|
.add(offsets);
|
||
|
};
|
||
|
ScrollAutomation.prototype._getScrollPosition = function (parentDimensions, childDimensions, offsets, maxScrollMargin) {
|
||
|
var childPoint = ScrollAutomation._getChildPoint(parentDimensions, childDimensions, offsets);
|
||
|
var scrollToPoint = this._getScrollToPoint(parentDimensions, childPoint, maxScrollMargin);
|
||
|
var scrollToFullView = this._getScrollToFullChildView(parentDimensions, childDimensions, maxScrollMargin);
|
||
|
return {
|
||
|
left: Math.max(scrollToFullView.left === null ? scrollToPoint.left : scrollToFullView.left, 0),
|
||
|
top: Math.max(scrollToFullView.top === null ? scrollToPoint.top : scrollToFullView.top, 0),
|
||
|
};
|
||
|
};
|
||
|
ScrollAutomation._getChildPointAfterScroll = function (parentDimensions, childDimensions, currentScroll, offsets) {
|
||
|
return AxisValues.create(childDimensions)
|
||
|
.add(AxisValues.create(parentDimensions.scroll))
|
||
|
.sub(AxisValues.create(currentScroll))
|
||
|
.add(offsets);
|
||
|
};
|
||
|
ScrollAutomation.prototype._isChildFullyVisible = function (parentDimensions, childDimensions, offsets) {
|
||
|
var childPoint = ScrollAutomation._getChildPointAfterScroll(parentDimensions, childDimensions, parentDimensions.scroll, offsets);
|
||
|
var zeroMargin = { left: 0, top: 0 };
|
||
|
var _a = this._getScrollPosition(parentDimensions, childDimensions, offsets, zeroMargin), left = _a.left, top = _a.top;
|
||
|
return !this._isTargetElementObscuredInPoint(childPoint) &&
|
||
|
left === parentDimensions.scroll.left && top === parentDimensions.scroll.top;
|
||
|
};
|
||
|
ScrollAutomation.prototype._scrollToChild = function (parent, child, offsets) {
|
||
|
var parentDimensions = getClientDimensions(parent);
|
||
|
var childDimensions = getClientDimensions(child);
|
||
|
var windowWidth = getInnerWidth(window);
|
||
|
var windowHeight = getInnerHeight(window);
|
||
|
var scrollPos = parentDimensions.scroll;
|
||
|
var needScroll = !this._isChildFullyVisible(parentDimensions, childDimensions, offsets);
|
||
|
while (needScroll) {
|
||
|
scrollPos = this._getScrollPosition(parentDimensions, childDimensions, offsets, this._maxScrollMargin);
|
||
|
var childPoint = ScrollAutomation._getChildPointAfterScroll(parentDimensions, childDimensions, scrollPos, offsets);
|
||
|
var isTargetObscured = this._isTargetElementObscuredInPoint(childPoint);
|
||
|
this._maxScrollMargin.left += SCROLL_MARGIN_INCREASE_STEP;
|
||
|
if (this._maxScrollMargin.left >= windowWidth) {
|
||
|
this._maxScrollMargin.left = DEFAULT_MAX_SCROLL_MARGIN;
|
||
|
this._maxScrollMargin.top += SCROLL_MARGIN_INCREASE_STEP;
|
||
|
}
|
||
|
needScroll = isTargetObscured && this._maxScrollMargin.top < windowHeight;
|
||
|
}
|
||
|
this._maxScrollMargin = { left: DEFAULT_MAX_SCROLL_MARGIN, top: DEFAULT_MAX_SCROLL_MARGIN };
|
||
|
return this._setScroll(parent, scrollPos);
|
||
|
};
|
||
|
ScrollAutomation.prototype._scrollElement = function () {
|
||
|
if (!hasScroll(this._element))
|
||
|
return hammerhead.Promise.resolve();
|
||
|
var elementDimensions = getClientDimensions(this._element);
|
||
|
var scroll = this._getScrollToPoint(elementDimensions, this._offsets, this._maxScrollMargin);
|
||
|
return this._setScroll(this._element, scroll);
|
||
|
};
|
||
|
ScrollAutomation.prototype._scrollParents = function () {
|
||
|
var _this = this;
|
||
|
var parents = getScrollableParents(this._element);
|
||
|
var currentChild = this._element;
|
||
|
var scrollLeft = getScrollLeft(currentChild);
|
||
|
var scrollTop = getScrollTop(currentChild);
|
||
|
var currentOffset = AxisValues.create(this._offsets).sub(new AxisValues(scrollLeft, scrollTop).round());
|
||
|
var childDimensions = null;
|
||
|
var parentDimensions = null;
|
||
|
var scrollParentsPromise = times(parents.length, function (i) {
|
||
|
return _this._scrollToChild(parents[i], currentChild, currentOffset)
|
||
|
.then(function () {
|
||
|
childDimensions = getClientDimensions(currentChild);
|
||
|
parentDimensions = getClientDimensions(parents[i]);
|
||
|
currentOffset.add(AxisValues.create(childDimensions))
|
||
|
.sub(AxisValues.create(parentDimensions))
|
||
|
.add(AxisValues.create(parentDimensions.border));
|
||
|
currentChild = parents[i];
|
||
|
});
|
||
|
});
|
||
|
var state = {
|
||
|
scrollWasPerformed: this._scrollWasPerformed,
|
||
|
offsetX: currentOffset.x,
|
||
|
offsetY: currentOffset.y,
|
||
|
maxScrollMargin: this._maxScrollMargin,
|
||
|
};
|
||
|
if (!sendRequestToFrame)
|
||
|
return scrollParentsPromise.then(function () { return state; });
|
||
|
return scrollParentsPromise
|
||
|
.then(function () {
|
||
|
if (_this._skipParentFrames || !isIframeWindow(window))
|
||
|
return;
|
||
|
state.cmd = ScrollAutomation.SCROLL_REQUEST_CMD;
|
||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, consistent-return
|
||
|
return sendRequestToFrame(state, ScrollAutomation.SCROLL_RESPONSE_CMD, window.parent);
|
||
|
})
|
||
|
.then(function () { return _this._scrollWasPerformed; });
|
||
|
};
|
||
|
ScrollAutomation._getFixedAncestorOrSelf = function (element) {
|
||
|
return findParent(element, true, isFixedElement);
|
||
|
};
|
||
|
ScrollAutomation.prototype._isTargetElementObscuredInPoint = function (point) {
|
||
|
var elementInPoint = getElementFromPoint(point);
|
||
|
if (!elementInPoint)
|
||
|
return false;
|
||
|
var fixedElement = ScrollAutomation._getFixedAncestorOrSelf(elementInPoint);
|
||
|
return !!fixedElement && !fixedElement.contains(this._element);
|
||
|
};
|
||
|
ScrollAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
return this._scrollElement()
|
||
|
.then(function () { return _this._scrollParents(); });
|
||
|
};
|
||
|
ScrollAutomation.SCROLL_REQUEST_CMD = 'automation|scroll|request';
|
||
|
ScrollAutomation.SCROLL_RESPONSE_CMD = 'automation|scroll|response';
|
||
|
return ScrollAutomation;
|
||
|
}());
|
||
|
|
||
|
var browserUtils$2 = hammerhead__default.utils.browser;
|
||
|
var MoveEventSequenceBase = /** @class */ (function () {
|
||
|
function MoveEventSequenceBase(_a) {
|
||
|
var moveEvent = _a.moveEvent;
|
||
|
this.dragAndDropMode = false;
|
||
|
this.dropAllowed = false;
|
||
|
this.moveEvent = moveEvent;
|
||
|
}
|
||
|
MoveEventSequenceBase.prototype.setup = function () {
|
||
|
this.dragAndDropMode = false;
|
||
|
this.dropAllowed = false;
|
||
|
};
|
||
|
MoveEventSequenceBase.prototype.leaveElement = function ( /* currentElement, prevElement, commonAncestor, options */) {
|
||
|
};
|
||
|
MoveEventSequenceBase.prototype.move = function ( /* element, options */) {
|
||
|
};
|
||
|
MoveEventSequenceBase.prototype.enterElement = function ( /* currentElement, prevElement, commonAncestor, options */) {
|
||
|
};
|
||
|
MoveEventSequenceBase.prototype.dragAndDrop = function ( /* dragElement, currentElement, prevElement, options, dragDataStore */) {
|
||
|
};
|
||
|
MoveEventSequenceBase.prototype.teardown = function ( /* currentElement, eventOptions, prevElement */) {
|
||
|
};
|
||
|
MoveEventSequenceBase.prototype.run = function (currentElement, prevElement, options, dragElement, dragDataStore) {
|
||
|
// NOTE: if last hovered element was in an iframe that has been removed, IE
|
||
|
// raises an exception when we try to compare it with the current element
|
||
|
var prevElementInDocument = prevElement && testCafeCore.domUtils.isElementInDocument(prevElement);
|
||
|
var prevElementInRemovedIframe = prevElement && testCafeCore.domUtils.isElementInIframe(prevElement) &&
|
||
|
!testCafeCore.domUtils.getIframeByElement(prevElement);
|
||
|
if (!prevElementInDocument || prevElementInRemovedIframe)
|
||
|
prevElement = null;
|
||
|
var elementChanged = currentElement !== prevElement;
|
||
|
var commonAncestor = elementChanged ? testCafeCore.domUtils.getCommonAncestor(currentElement, prevElement) : null;
|
||
|
this.setup();
|
||
|
if (elementChanged && !!prevElement)
|
||
|
this.leaveElement(currentElement, prevElement, commonAncestor, options);
|
||
|
if (browserUtils$2.isIE)
|
||
|
this.move(currentElement, options);
|
||
|
if (elementChanged && testCafeCore.domUtils.isElementInDocument(currentElement))
|
||
|
this.enterElement(currentElement, prevElement, commonAncestor, options);
|
||
|
if (!browserUtils$2.isIE)
|
||
|
this.move(currentElement, options);
|
||
|
this.dragAndDrop(dragElement, currentElement, prevElement, options, dragDataStore);
|
||
|
this.teardown(currentElement, options, prevElement);
|
||
|
var dragAndDropMode = this.dragAndDropMode;
|
||
|
var dropAllowed = this.dropAllowed;
|
||
|
this.dragAndDropMode = false;
|
||
|
this.dropAllowed = false;
|
||
|
return { dragAndDropMode: dragAndDropMode, dropAllowed: dropAllowed };
|
||
|
};
|
||
|
return MoveEventSequenceBase;
|
||
|
}());
|
||
|
|
||
|
var eventSimulator = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var extend = hammerhead__default.utils.extend;
|
||
|
var nativeMethods$6 = hammerhead__default.nativeMethods;
|
||
|
var MoveBehaviour = /** @class */ (function () {
|
||
|
function MoveBehaviour() {
|
||
|
}
|
||
|
MoveBehaviour.leaveElement = function (currentElement, prevElement, commonAncestor, options) {
|
||
|
eventSimulator.mouseout(prevElement, extend({ relatedTarget: currentElement }, options));
|
||
|
var currentParent = prevElement;
|
||
|
while (currentParent && currentParent !== commonAncestor) {
|
||
|
eventSimulator.mouseleave(currentParent, extend({ relatedTarget: currentElement }, options));
|
||
|
currentParent = nativeMethods$6.nodeParentNodeGetter.call(currentParent);
|
||
|
}
|
||
|
};
|
||
|
MoveBehaviour.enterElement = function (currentElement, prevElement, commonAncestor, options) {
|
||
|
eventSimulator.mouseover(currentElement, extend({ relatedTarget: prevElement }, options));
|
||
|
var currentParent = currentElement;
|
||
|
var mouseenterElements = [];
|
||
|
while (currentParent && currentParent !== commonAncestor) {
|
||
|
mouseenterElements.push(currentParent);
|
||
|
currentParent = testCafeCore.domUtils.getParentExceptShadowRoot(currentParent);
|
||
|
}
|
||
|
for (var i = mouseenterElements.length - 1; i > -1; i--)
|
||
|
eventSimulator.mouseenter(mouseenterElements[i], extend({ relatedTarget: prevElement }, options));
|
||
|
};
|
||
|
MoveBehaviour.move = function (moveEvent, element, options) {
|
||
|
eventSimulator[moveEvent](element, options);
|
||
|
};
|
||
|
return MoveBehaviour;
|
||
|
}());
|
||
|
var DragAndDropBehavior = /** @class */ (function () {
|
||
|
function DragAndDropBehavior() {
|
||
|
}
|
||
|
DragAndDropBehavior.dragAndDrop = function (dragElement, currentElement, prevElement, options) {
|
||
|
eventSimulator.drag(dragElement, options);
|
||
|
var currentElementChanged = currentElement !== prevElement;
|
||
|
if (currentElementChanged) {
|
||
|
if (testCafeCore.domUtils.isElementInDocument(currentElement)) {
|
||
|
options.relatedTarget = prevElement;
|
||
|
eventSimulator.dragenter(currentElement, options);
|
||
|
}
|
||
|
if (prevElement) {
|
||
|
options.relatedTarget = currentElement;
|
||
|
eventSimulator.dragleave(prevElement, options);
|
||
|
}
|
||
|
}
|
||
|
return !eventSimulator.dragover(currentElement, options);
|
||
|
};
|
||
|
return DragAndDropBehavior;
|
||
|
}());
|
||
|
|
||
|
var eventSimulator$1 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var TOUCH_MOVE_EVENT_NAME = 'touchmove';
|
||
|
var MoveEventSequence = /** @class */ (function (_super) {
|
||
|
__extends(MoveEventSequence, _super);
|
||
|
function MoveEventSequence(options) {
|
||
|
var _this = _super.call(this, options) || this;
|
||
|
_this.holdLeftButton = options.holdLeftButton;
|
||
|
return _this;
|
||
|
}
|
||
|
MoveEventSequence.prototype.leaveElement = function (currentElement, prevElement, commonAncestor, options) {
|
||
|
MoveBehaviour.leaveElement(currentElement, prevElement, commonAncestor, options);
|
||
|
};
|
||
|
MoveEventSequence.prototype.enterElement = function (currentElement, prevElement, commonAncestor, options) {
|
||
|
MoveBehaviour.enterElement(currentElement, prevElement, commonAncestor, options);
|
||
|
};
|
||
|
MoveEventSequence.prototype.move = function (element, options) {
|
||
|
if (this._needEmulateMoveEvent())
|
||
|
MoveBehaviour.move(this.moveEvent, element, options);
|
||
|
};
|
||
|
MoveEventSequence.prototype.teardown = function (currentElement, eventOptions, prevElement) {
|
||
|
// NOTE: we need to add an extra 'mousemove' if the element was changed because sometimes
|
||
|
// the client script requires several 'mousemove' events for an element (T246904)
|
||
|
if (this._needEmulateMoveEvent() && testCafeCore.domUtils.isElementInDocument(currentElement) && currentElement !== prevElement)
|
||
|
eventSimulator$1[this.moveEvent](currentElement, eventOptions);
|
||
|
};
|
||
|
MoveEventSequence.prototype._needEmulateMoveEvent = function () {
|
||
|
return this.moveEvent !== TOUCH_MOVE_EVENT_NAME || this.holdLeftButton;
|
||
|
};
|
||
|
return MoveEventSequence;
|
||
|
}(MoveEventSequenceBase));
|
||
|
|
||
|
var DragAndDropMoveEventSequence = /** @class */ (function (_super) {
|
||
|
__extends(DragAndDropMoveEventSequence, _super);
|
||
|
function DragAndDropMoveEventSequence() {
|
||
|
return _super !== null && _super.apply(this, arguments) || this;
|
||
|
}
|
||
|
DragAndDropMoveEventSequence.prototype.setup = function () {
|
||
|
_super.prototype.setup.call(this);
|
||
|
this.dragAndDropMode = true;
|
||
|
};
|
||
|
DragAndDropMoveEventSequence.prototype.dragAndDrop = function (dragElement, currentElement, prevElement, options) {
|
||
|
this.dropAllowed = DragAndDropBehavior.dragAndDrop(dragElement, currentElement, prevElement, options);
|
||
|
};
|
||
|
return DragAndDropMoveEventSequence;
|
||
|
}(MoveEventSequenceBase));
|
||
|
|
||
|
var eventSimulator$2 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var DragAndDropFirstMoveEventSequence = /** @class */ (function (_super) {
|
||
|
__extends(DragAndDropFirstMoveEventSequence, _super);
|
||
|
function DragAndDropFirstMoveEventSequence() {
|
||
|
return _super !== null && _super.apply(this, arguments) || this;
|
||
|
}
|
||
|
DragAndDropFirstMoveEventSequence.prototype.setup = function () {
|
||
|
_super.prototype.setup.call(this);
|
||
|
this.dragAndDropMode = true;
|
||
|
};
|
||
|
DragAndDropFirstMoveEventSequence.prototype.leaveElement = function (currentElement, prevElement, commonAncestor, options) {
|
||
|
MoveBehaviour.leaveElement(currentElement, prevElement, commonAncestor, options);
|
||
|
};
|
||
|
DragAndDropFirstMoveEventSequence.prototype.move = function (element, option) {
|
||
|
MoveBehaviour.move(this.moveEvent, element, option);
|
||
|
};
|
||
|
DragAndDropFirstMoveEventSequence.prototype.enterElement = function (currentElement, prevElement, commonAncestor, options) {
|
||
|
MoveBehaviour.enterElement(currentElement, prevElement, commonAncestor, options);
|
||
|
};
|
||
|
DragAndDropFirstMoveEventSequence.prototype.dragAndDrop = function (dragElement, currentElement, prevElement, options, dragDataStore) {
|
||
|
var dragAllowed = eventSimulator$2.dragstart(dragElement, options);
|
||
|
dragDataStore.setReadOnlyMode();
|
||
|
if (!dragAllowed) {
|
||
|
this.dragAndDropMode = false;
|
||
|
return;
|
||
|
}
|
||
|
this.dropAllowed = DragAndDropBehavior.dragAndDrop(dragElement, currentElement, prevElement, options);
|
||
|
};
|
||
|
DragAndDropFirstMoveEventSequence.prototype.run = function (currentElement, prevElement, options, dragElement, dragDataStore) {
|
||
|
return _super.prototype.run.call(this, currentElement, null, options, dragElement, dragDataStore);
|
||
|
};
|
||
|
return DragAndDropFirstMoveEventSequence;
|
||
|
}(MoveEventSequenceBase));
|
||
|
|
||
|
function createEventSequence(dragAndDropEnabled, firstMovingStepOccured, options) {
|
||
|
if (!dragAndDropEnabled)
|
||
|
return new MoveEventSequence(options);
|
||
|
if (firstMovingStepOccured)
|
||
|
return new DragAndDropMoveEventSequence(options);
|
||
|
return new DragAndDropFirstMoveEventSequence(options);
|
||
|
}
|
||
|
|
||
|
var MOVE_REQUEST_CMD = 'automation|move|request';
|
||
|
var MOVE_RESPONSE_CMD = 'automation|move|response';
|
||
|
var MoveAutomation = /** @class */ (function () {
|
||
|
function MoveAutomation(el, offset, moveOptions, win, cursor) {
|
||
|
this.touchMode = hammerhead.utils.featureDetection.isTouchDevice;
|
||
|
this.moveEvent = this.touchMode ? 'touchmove' : 'mousemove';
|
||
|
this.automationSettings = new AutomationSettings(moveOptions.speed);
|
||
|
this.cursorSpeed = this._getCursorSpeed();
|
||
|
this.element = el;
|
||
|
this.window = win;
|
||
|
this.offset = offset;
|
||
|
this.cursor = cursor;
|
||
|
this.minMovingTime = moveOptions.minMovingTime || 0;
|
||
|
this.modifiers = moveOptions.modifiers || {};
|
||
|
this.skipScrolling = moveOptions.skipScrolling;
|
||
|
this.skipDefaultDragBehavior = moveOptions.skipDefaultDragBehavior;
|
||
|
this.speed = moveOptions.speed;
|
||
|
this.firstMovingStepOccured = false;
|
||
|
}
|
||
|
MoveAutomation.create = function (el, moveOptions, win, cursor) {
|
||
|
return __awaiter(this, void 0, hammerhead.Promise, function () {
|
||
|
var _a, element, offset;
|
||
|
return __generator(this, function (_b) {
|
||
|
switch (_b.label) {
|
||
|
case 0: return [4 /*yield*/, MoveAutomation.getTarget(el, win, new AxisValues(moveOptions.offsetX, moveOptions.offsetY))];
|
||
|
case 1:
|
||
|
_a = _b.sent(), element = _a.element, offset = _a.offset;
|
||
|
return [2 /*return*/, new MoveAutomation(element, offset, moveOptions, win, cursor)];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
MoveAutomation.getTarget = function (element, window, offset) {
|
||
|
// NOTE: if the target point (considering offsets) is out of
|
||
|
// the element change the target element to the document element
|
||
|
return hammerhead.Promise.resolve(containsOffset(element, offset.x, offset.y))
|
||
|
.then(function (containsOffset) {
|
||
|
if (!containsOffset) {
|
||
|
return hammerhead.Promise.all([
|
||
|
getAutomationPoint(element, offset),
|
||
|
getDocumentElement(window),
|
||
|
])
|
||
|
.then(function (_a) {
|
||
|
var point = _a[0], docEl = _a[1];
|
||
|
return ({ element: docEl, offset: point });
|
||
|
});
|
||
|
}
|
||
|
return { element: element, offset: offset };
|
||
|
});
|
||
|
};
|
||
|
MoveAutomation.prototype._getCursorSpeed = function () {
|
||
|
return this.automationSettings.cursorSpeed;
|
||
|
};
|
||
|
MoveAutomation.prototype._getTargetClientPoint = function () {
|
||
|
var _this = this;
|
||
|
return hammerhead.Promise.resolve(getElementScroll(this.element))
|
||
|
.then(function (scroll) {
|
||
|
if (isHtmlElement(_this.element)) {
|
||
|
return AxisValues.create(_this.offset)
|
||
|
.sub(AxisValues.create(scroll))
|
||
|
.round(Math.round);
|
||
|
}
|
||
|
return hammerhead.Promise.resolve(getClientPosition(_this.element))
|
||
|
.then(function (clientPosition) {
|
||
|
var isDocumentBody = isBodyElement(_this.element);
|
||
|
// @ts-ignore
|
||
|
var clientPoint = AxisValues.create(clientPosition).add(_this.offset);
|
||
|
if (!isDocumentBody)
|
||
|
clientPoint.sub(AxisValues.create(scroll));
|
||
|
return clientPoint.round(Math.floor);
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
MoveAutomation.prototype._getEventSequenceOptions = function (currPosition) {
|
||
|
var button = BUTTONS_PARAMETER.noButton;
|
||
|
var devicePoint = getDevicePoint(currPosition);
|
||
|
var eventOptions = {
|
||
|
clientX: currPosition.x,
|
||
|
clientY: currPosition.y,
|
||
|
screenX: devicePoint === null || devicePoint === void 0 ? void 0 : devicePoint.x,
|
||
|
screenY: devicePoint === null || devicePoint === void 0 ? void 0 : devicePoint.y,
|
||
|
buttons: button,
|
||
|
ctrl: this.modifiers.ctrl,
|
||
|
alt: this.modifiers.alt,
|
||
|
shift: this.modifiers.shift,
|
||
|
meta: this.modifiers.meta,
|
||
|
};
|
||
|
return { eventOptions: eventOptions, eventSequenceOptions: { moveEvent: this.moveEvent } };
|
||
|
};
|
||
|
MoveAutomation.prototype._runEventSequence = function (currentElement, _a) {
|
||
|
var eventOptions = _a.eventOptions, eventSequenceOptions = _a.eventSequenceOptions;
|
||
|
var eventSequence = createEventSequence(false, this.firstMovingStepOccured, eventSequenceOptions);
|
||
|
return eventSequence.run(currentElement, lastHoveredElementHolder.get(), eventOptions, null, null);
|
||
|
};
|
||
|
MoveAutomation.prototype._emulateEvents = function (currentElement, currPosition) {
|
||
|
var options = this._getEventSequenceOptions(currPosition);
|
||
|
this._runEventSequence(currentElement, options);
|
||
|
this.firstMovingStepOccured = true;
|
||
|
lastHoveredElementHolder.set(currentElement);
|
||
|
};
|
||
|
MoveAutomation.prototype._movingStep = function (currPosition) {
|
||
|
var _this = this;
|
||
|
return this.cursor.move(currPosition)
|
||
|
.then(function () { return getElementFromPoint$1(_this.cursor.getPosition()); })
|
||
|
// NOTE: in touch mode, events are simulated for the element for which mousedown was simulated (GH-372)
|
||
|
.then(function (topElement) {
|
||
|
var currentElement = _this._getCorrectedTopElement(topElement);
|
||
|
// NOTE: it can be null in IE
|
||
|
if (!currentElement)
|
||
|
return null;
|
||
|
return _this._emulateEvents(currentElement, currPosition);
|
||
|
})
|
||
|
.then(nextTick);
|
||
|
};
|
||
|
MoveAutomation.prototype._getCorrectedTopElement = function (topElement) {
|
||
|
return topElement;
|
||
|
};
|
||
|
MoveAutomation.prototype._move = function (endPoint) {
|
||
|
var _this = this;
|
||
|
var startPoint = this.cursor.getPosition();
|
||
|
var distance = AxisValues.create(endPoint).sub(startPoint);
|
||
|
var startTime = hammerhead.nativeMethods.dateNow();
|
||
|
var movingTime = Math.max(Math.max(Math.abs(distance.x), Math.abs(distance.y)) / this.cursorSpeed, this.minMovingTime);
|
||
|
var currPosition = AxisValues.create(startPoint);
|
||
|
var isFirstStep = true;
|
||
|
return whilst(function () { return !currPosition.eql(endPoint); }, function () {
|
||
|
if (_this._needMoveCursorImmediately())
|
||
|
currPosition = AxisValues.create(endPoint);
|
||
|
else if (isFirstStep) {
|
||
|
isFirstStep = false;
|
||
|
// NOTE: the mousemove event can't be simulated at the point where the cursor
|
||
|
// was located at the start. Therefore, we add a minimal distance 1 px.
|
||
|
currPosition.add({
|
||
|
x: distance.x > 0 ? 1 : -1,
|
||
|
y: distance.y > 0 ? 1 : -1,
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
var progress = Math.min((hammerhead.nativeMethods.dateNow() - startTime) / movingTime, 1);
|
||
|
currPosition = AxisValues.create(distance).mul(progress).add(startPoint).round(Math.floor);
|
||
|
}
|
||
|
return _this._movingStep(currPosition);
|
||
|
});
|
||
|
};
|
||
|
//
|
||
|
MoveAutomation.prototype._needMoveCursorImmediately = function () {
|
||
|
return this.touchMode;
|
||
|
};
|
||
|
MoveAutomation.prototype._scroll = function () {
|
||
|
if (this.skipScrolling)
|
||
|
return hammerhead.Promise.resolve(false);
|
||
|
var scrollOptions = new ScrollOptions({ offsetX: this.offset.x, offsetY: this.offset.y }, false);
|
||
|
var scrollAutomation = new ScrollAutomation(this.element, scrollOptions);
|
||
|
return scrollAutomation.run();
|
||
|
};
|
||
|
MoveAutomation.prototype._moveToCurrentFrame = function (endPoint) {
|
||
|
var _this = this;
|
||
|
if (this.cursor.isActive(this.window))
|
||
|
return hammerhead.Promise.resolve();
|
||
|
var _a = this.cursor.getPosition(), x = _a.x, y = _a.y;
|
||
|
var activeWindow = this.cursor.getActiveWindow(this.window);
|
||
|
var iframe = null;
|
||
|
var iframeUnderCursor = null;
|
||
|
var msg = {
|
||
|
cmd: MOVE_REQUEST_CMD,
|
||
|
startX: x,
|
||
|
startY: y,
|
||
|
endX: endPoint.x,
|
||
|
endY: endPoint.y,
|
||
|
modifiers: this.modifiers,
|
||
|
speed: this.speed,
|
||
|
shouldRender: this.cursor.shouldRender,
|
||
|
};
|
||
|
return hammerhead.Promise.resolve()
|
||
|
.then(function () {
|
||
|
if (activeWindow.parent === _this.window) {
|
||
|
return hammerhead.Promise.resolve(findIframeByWindow(activeWindow))
|
||
|
.then(function (frame) {
|
||
|
iframe = frame;
|
||
|
return hammerhead.Promise.resolve(getIframeClientCoordinates(frame))
|
||
|
.then(function (rect) {
|
||
|
msg.left = rect.left;
|
||
|
msg.top = rect.top;
|
||
|
msg.right = rect.right;
|
||
|
msg.bottom = rect.bottom;
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
return void 0;
|
||
|
})
|
||
|
.then(function () {
|
||
|
return getElementFromPoint$1(_this.cursor.getPosition());
|
||
|
})
|
||
|
.then(function (topElement) {
|
||
|
iframeUnderCursor = topElement === iframe;
|
||
|
if (activeWindow.parent === _this.window)
|
||
|
msg.iframeUnderCursor = iframeUnderCursor;
|
||
|
return sendRequestToFrame(msg, MOVE_RESPONSE_CMD, activeWindow);
|
||
|
})
|
||
|
.then(function (message) {
|
||
|
_this.cursor.setActiveWindow(_this.window);
|
||
|
if (iframeUnderCursor || hammerhead.utils.dom.isIframeWindow(_this.window))
|
||
|
return _this.cursor.move(message);
|
||
|
return void 0;
|
||
|
});
|
||
|
};
|
||
|
MoveAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
return this._scroll()
|
||
|
.then(function () { return hammerhead.Promise.all([
|
||
|
_this._getTargetClientPoint(),
|
||
|
getWindowDimensions(_this.window),
|
||
|
]); })
|
||
|
.then(function (_a) {
|
||
|
var endPoint = _a[0], boundary = _a[1];
|
||
|
if (!boundary.contains(endPoint))
|
||
|
return void 0;
|
||
|
return _this._moveToCurrentFrame(endPoint)
|
||
|
.then(function () { return _this._move(endPoint); });
|
||
|
});
|
||
|
};
|
||
|
return MoveAutomation;
|
||
|
}());
|
||
|
|
||
|
var Cursor = /** @class */ (function () {
|
||
|
function Cursor(activeWin, ui) {
|
||
|
this._ui = ui;
|
||
|
// NOTE: the default position should be outside the page (GH-794)
|
||
|
this._x = -1;
|
||
|
this._y = -1;
|
||
|
this._activeWindow = activeWin;
|
||
|
}
|
||
|
Cursor.prototype._ensureActiveWindow = function (win) {
|
||
|
if (this._activeWindow === win || this._activeWindow === win.parent)
|
||
|
return;
|
||
|
if (this._activeWindow.parent !== win)
|
||
|
this._activeWindow = win;
|
||
|
};
|
||
|
Cursor.prototype.isActive = function (currWin) {
|
||
|
this._ensureActiveWindow(currWin);
|
||
|
return this._activeWindow === currWin;
|
||
|
};
|
||
|
Cursor.prototype.setActiveWindow = function (win) {
|
||
|
this._activeWindow = win;
|
||
|
};
|
||
|
Cursor.prototype.getActiveWindow = function (currWin) {
|
||
|
this._ensureActiveWindow(currWin);
|
||
|
return this._activeWindow;
|
||
|
};
|
||
|
Cursor.prototype.getPosition = function () {
|
||
|
return new AxisValues(this._x, this._y);
|
||
|
};
|
||
|
Object.defineProperty(Cursor.prototype, "shouldRender", {
|
||
|
get: function () {
|
||
|
return this._ui.shouldRender;
|
||
|
},
|
||
|
set: function (val) {
|
||
|
this._ui.shouldRender = val;
|
||
|
},
|
||
|
enumerable: false,
|
||
|
configurable: true
|
||
|
});
|
||
|
Cursor.prototype.move = function (point) {
|
||
|
this._x = point.x;
|
||
|
this._y = point.y;
|
||
|
return this._ui.move(point);
|
||
|
};
|
||
|
Cursor.prototype.hide = function () {
|
||
|
if (this._ui.hide)
|
||
|
return this._ui.hide();
|
||
|
return hammerhead.Promise.resolve();
|
||
|
};
|
||
|
Cursor.prototype.show = function () {
|
||
|
if (this._ui.show)
|
||
|
return this._ui.show();
|
||
|
return hammerhead.Promise.resolve();
|
||
|
};
|
||
|
Cursor.prototype.leftButtonDown = function () {
|
||
|
return this._ui.leftButtonDown();
|
||
|
};
|
||
|
Cursor.prototype.rightButtonDown = function () {
|
||
|
return this._ui.rightButtonDown();
|
||
|
};
|
||
|
Cursor.prototype.buttonUp = function () {
|
||
|
return this._ui.buttonUp();
|
||
|
};
|
||
|
return Cursor;
|
||
|
}());
|
||
|
|
||
|
var cursorUI = !isIframeWindow(window) ? testCafeUI.cursorUI : testCafeUI.iframeCursorUI;
|
||
|
var cursor = new Cursor(window.top, cursorUI);
|
||
|
|
||
|
var positionUtils$1 = testCafeCore__default.positionUtils, domUtils = testCafeCore__default.domUtils, eventUtils = testCafeCore__default.eventUtils;
|
||
|
function ensureMouseEventAfterScroll(currentElement, element, wasScrolled) {
|
||
|
return __awaiter(this, void 0, hammerhead__default.Promise, function () {
|
||
|
var elementUnderCursorContainsTarget, prevElement, commonAncestor, clientPosition, devicePoint, options;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
elementUnderCursorContainsTarget = !!currentElement && domUtils.contains(element, currentElement);
|
||
|
if (!elementUnderCursorContainsTarget || !wasScrolled)
|
||
|
return [2 /*return*/];
|
||
|
prevElement = lastHoveredElementHolder.get();
|
||
|
commonAncestor = domUtils.getCommonAncestor(currentElement, prevElement);
|
||
|
return [4 /*yield*/, positionUtils$1.getClientPosition(currentElement)];
|
||
|
case 1:
|
||
|
clientPosition = _a.sent();
|
||
|
return [4 /*yield*/, getDevicePoint(clientPosition)];
|
||
|
case 2:
|
||
|
devicePoint = _a.sent();
|
||
|
if (!devicePoint)
|
||
|
return [2 /*return*/];
|
||
|
options = {
|
||
|
clientX: clientPosition.x,
|
||
|
clientY: clientPosition.y,
|
||
|
screenX: devicePoint.x,
|
||
|
screenY: devicePoint.y,
|
||
|
ctrl: false,
|
||
|
alt: false,
|
||
|
shift: false,
|
||
|
meta: false,
|
||
|
buttons: eventUtils.BUTTONS_PARAMETER.leftButton,
|
||
|
};
|
||
|
MoveBehaviour.leaveElement(currentElement, prevElement, commonAncestor, options);
|
||
|
MoveBehaviour.enterElement(currentElement, prevElement, commonAncestor, options);
|
||
|
lastHoveredElementHolder.set(currentElement);
|
||
|
return [2 /*return*/];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var WARNING_TYPES = {
|
||
|
elementOverlapped: 'elementOverlapped',
|
||
|
};
|
||
|
|
||
|
var EventType;
|
||
|
(function (EventType) {
|
||
|
EventType[EventType["Mouse"] = 0] = "Mouse";
|
||
|
EventType[EventType["Key"] = 1] = "Key";
|
||
|
EventType[EventType["Touch"] = 2] = "Touch";
|
||
|
})(EventType || (EventType = {}));
|
||
|
|
||
|
var KeyModifierValues;
|
||
|
(function (KeyModifierValues) {
|
||
|
KeyModifierValues[KeyModifierValues["alt"] = 1] = "alt";
|
||
|
KeyModifierValues[KeyModifierValues["ctrl"] = 2] = "ctrl";
|
||
|
KeyModifierValues[KeyModifierValues["meta"] = 4] = "meta";
|
||
|
KeyModifierValues[KeyModifierValues["shift"] = 8] = "shift";
|
||
|
})(KeyModifierValues || (KeyModifierValues = {}));
|
||
|
|
||
|
function calculateKeyModifiersValue(modifiers) {
|
||
|
var result = 0;
|
||
|
if (modifiers.ctrl)
|
||
|
result |= KeyModifierValues.ctrl;
|
||
|
if (modifiers.alt)
|
||
|
result |= KeyModifierValues.alt;
|
||
|
if (modifiers.shift)
|
||
|
result |= KeyModifierValues.shift;
|
||
|
if (modifiers.meta)
|
||
|
result |= KeyModifierValues.meta;
|
||
|
return result;
|
||
|
}
|
||
|
function calculateMouseButtonValue(options) {
|
||
|
if (!options.button)
|
||
|
return 'left';
|
||
|
return 'right';
|
||
|
}
|
||
|
|
||
|
var MOUSE_EVENT_OPTIONS = {
|
||
|
clickCount: 1,
|
||
|
button: 'left',
|
||
|
};
|
||
|
var ProxylessEventSimulator = /** @class */ (function () {
|
||
|
function ProxylessEventSimulator(dispatchEventFn, leftTopPoint) {
|
||
|
this._dispatchEventFn = dispatchEventFn;
|
||
|
this._leftTopPoint = leftTopPoint || new AxisValues(0, 0);
|
||
|
}
|
||
|
ProxylessEventSimulator.prototype._createMouseEventOptions = function (type, options) {
|
||
|
return hammerhead.utils.extend({
|
||
|
x: options.options.clientX + this._leftTopPoint.x,
|
||
|
y: options.options.clientY + this._leftTopPoint.y,
|
||
|
modifiers: calculateKeyModifiersValue(options.options),
|
||
|
button: calculateMouseButtonValue(options.options),
|
||
|
type: type,
|
||
|
}, MOUSE_EVENT_OPTIONS);
|
||
|
};
|
||
|
ProxylessEventSimulator.prototype.mouseDown = function (options) {
|
||
|
var eventOptions = this._createMouseEventOptions('mousePressed', options);
|
||
|
return this._dispatchEventFn(EventType.Mouse, eventOptions);
|
||
|
};
|
||
|
ProxylessEventSimulator.prototype.mouseUp = function (options) {
|
||
|
var eventOptions = this._createMouseEventOptions('mouseReleased', options);
|
||
|
return this._dispatchEventFn(EventType.Mouse, eventOptions);
|
||
|
};
|
||
|
return ProxylessEventSimulator;
|
||
|
}());
|
||
|
|
||
|
var AVAILABLE_OFFSET_DEEP = 2;
|
||
|
var ElementState = /** @class */ (function () {
|
||
|
function ElementState(_a) {
|
||
|
var _b = _a.element, element = _b === void 0 ? null : _b, _c = _a.clientPoint, clientPoint = _c === void 0 ? null : _c, _d = _a.screenPoint, screenPoint = _d === void 0 ? null : _d, _e = _a.isTarget, isTarget = _e === void 0 ? false : _e, _f = _a.inMoving, inMoving = _f === void 0 ? false : _f, _g = _a.devicePoint, devicePoint = _g === void 0 ? null : _g;
|
||
|
this.element = element;
|
||
|
this.clientPoint = clientPoint;
|
||
|
this.screenPoint = screenPoint;
|
||
|
this.devicePoint = devicePoint;
|
||
|
this.isTarget = isTarget;
|
||
|
this.inMoving = inMoving;
|
||
|
}
|
||
|
ElementState.create = function (_a) {
|
||
|
var element = _a.element, clientPoint = _a.clientPoint, screenPoint = _a.screenPoint, isTarget = _a.isTarget, inMoving = _a.inMoving;
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var devicePoint, state;
|
||
|
return __generator(this, function (_b) {
|
||
|
switch (_b.label) {
|
||
|
case 0:
|
||
|
devicePoint = null;
|
||
|
if (!clientPoint) return [3 /*break*/, 2];
|
||
|
return [4 /*yield*/, getDevicePoint(clientPoint)];
|
||
|
case 1:
|
||
|
devicePoint = _b.sent();
|
||
|
_b.label = 2;
|
||
|
case 2:
|
||
|
state = new ElementState({ element: element, clientPoint: clientPoint, screenPoint: screenPoint, isTarget: isTarget, inMoving: inMoving, devicePoint: devicePoint });
|
||
|
return [2 /*return*/, state];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
return ElementState;
|
||
|
}());
|
||
|
var VisibleElementAutomation = /** @class */ (function (_super) {
|
||
|
__extends(VisibleElementAutomation, _super);
|
||
|
function VisibleElementAutomation(element, offsetOptions, win, cursor, dispatchProxylessEventFn, topLeftPoint) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.TARGET_ELEMENT_FOUND_EVENT = 'automation|target-element-found-event';
|
||
|
_this.WARNING_EVENT = 'automation|warning-event';
|
||
|
_this.element = element;
|
||
|
_this.options = offsetOptions;
|
||
|
_this.automationSettings = new AutomationSettings(offsetOptions.speed || 1);
|
||
|
_this.window = win;
|
||
|
_this.cursor = cursor;
|
||
|
_this.proxylessEventSimulator = dispatchProxylessEventFn ? new ProxylessEventSimulator(dispatchProxylessEventFn, topLeftPoint) : null;
|
||
|
// NOTE: only for legacy API
|
||
|
_this._ensureWindowAndCursorForLegacyTests(_this);
|
||
|
return _this;
|
||
|
}
|
||
|
VisibleElementAutomation.prototype._ensureWindowAndCursorForLegacyTests = function (automation) {
|
||
|
automation.window = automation.window || window; // eslint-disable-line no-undef
|
||
|
automation.cursor = cursor;
|
||
|
};
|
||
|
VisibleElementAutomation.prototype.canUseProxylessEventSimulator = function (element) {
|
||
|
return !!this.proxylessEventSimulator
|
||
|
&& !!element
|
||
|
&& getTagName(element) !== 'select';
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._getElementForEvent = function (eventArgs) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var expectedElement;
|
||
|
return __generator(this, function (_a) {
|
||
|
expectedElement = containsOffset(this.element, this.options.offsetX, this.options.offsetY) ? this.element : null;
|
||
|
return [2 /*return*/, getElementFromPoint$2(eventArgs.point, this.window, expectedElement)];
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._moveToElement = function () {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var moveOptions, moveAutomation;
|
||
|
var _this = this;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
moveOptions = new MoveOptions(hammerhead.utils.extend({ skipScrolling: true }, this.options), false);
|
||
|
return [4 /*yield*/, MoveAutomation.create(this.element, moveOptions, this.window, this.cursor)];
|
||
|
case 1:
|
||
|
moveAutomation = _a.sent();
|
||
|
return [2 /*return*/, moveAutomation // eslint-disable-line consistent-return
|
||
|
.run()
|
||
|
.then(function () { return delay(_this.automationSettings.mouseActionStepDelay); })];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._scrollToElement = function () {
|
||
|
var _this = this;
|
||
|
var wasScrolled = false;
|
||
|
var scrollOptions = new ScrollOptions(this.options, false);
|
||
|
var scrollAutomation = new ScrollAutomation(this.element, scrollOptions);
|
||
|
return scrollAutomation.run()
|
||
|
.then(function (scrollWasPerformed) {
|
||
|
wasScrolled = !!scrollWasPerformed;
|
||
|
return delay(_this.automationSettings.mouseActionStepDelay);
|
||
|
})
|
||
|
.then(function () { return getElementFromPoint$2(_this.cursor.getPosition(), _this.window); })
|
||
|
.then(function (currentElement) {
|
||
|
return ensureMouseEventAfterScroll(currentElement, _this.element, wasScrolled);
|
||
|
})
|
||
|
.then(function () {
|
||
|
return wasScrolled;
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._getElementOffset = function () {
|
||
|
var defaultOffsets = getOffsetOptions(this.element);
|
||
|
var _a = this.options, offsetX = _a.offsetX, offsetY = _a.offsetY;
|
||
|
var y = offsetY || offsetY === 0 ? offsetY : defaultOffsets.offsetY;
|
||
|
var x = offsetX || offsetX === 0 ? offsetX : defaultOffsets.offsetX;
|
||
|
return AxisValues.create({ x: x, y: y });
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._isTargetElement = function (element, expectedElement) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var isTarget;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
isTarget = !expectedElement || element === expectedElement || element === this.element;
|
||
|
if (!(!isTarget && element)) return [3 /*break*/, 2];
|
||
|
return [4 /*yield*/, this._contains(this.element, element)];
|
||
|
case 1:
|
||
|
// NOTE: perform an operation with searching in dom only if necessary
|
||
|
isTarget = _a.sent();
|
||
|
_a.label = 2;
|
||
|
case 2: return [2 /*return*/, isTarget];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._getCheckedPoints = function (centerPoint) {
|
||
|
var points = [centerPoint];
|
||
|
var stepX = centerPoint.x / AVAILABLE_OFFSET_DEEP;
|
||
|
var stepY = centerPoint.y / AVAILABLE_OFFSET_DEEP;
|
||
|
var maxX = centerPoint.x * 2;
|
||
|
var maxY = centerPoint.y * 2;
|
||
|
for (var y = stepY; y < maxY; y += stepY) {
|
||
|
for (var x = stepX; x < maxX; x += stepX)
|
||
|
points.push(AxisValues.create({ x: x, y: y }));
|
||
|
}
|
||
|
return points;
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._getAvailableOffset = function (expectedElement, centerPoint) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var checkedPoints, screenPoint, clientPoint, element, i;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
checkedPoints = this._getCheckedPoints(centerPoint);
|
||
|
screenPoint = null;
|
||
|
clientPoint = null;
|
||
|
element = null;
|
||
|
i = 0;
|
||
|
_a.label = 1;
|
||
|
case 1:
|
||
|
if (!(i < checkedPoints.length)) return [3 /*break*/, 7];
|
||
|
return [4 /*yield*/, getAutomationPoint(this.element, checkedPoints[i])];
|
||
|
case 2:
|
||
|
screenPoint = _a.sent();
|
||
|
return [4 /*yield*/, convertToClient(this.element, screenPoint)];
|
||
|
case 3:
|
||
|
clientPoint = _a.sent();
|
||
|
return [4 /*yield*/, getElementFromPoint$2(clientPoint, this.window, expectedElement)];
|
||
|
case 4:
|
||
|
element = _a.sent();
|
||
|
return [4 /*yield*/, this._isTargetElement(element, expectedElement)];
|
||
|
case 5:
|
||
|
if (_a.sent())
|
||
|
return [2 /*return*/, checkedPoints[i]];
|
||
|
_a.label = 6;
|
||
|
case 6:
|
||
|
i++;
|
||
|
return [3 /*break*/, 1];
|
||
|
case 7: return [2 /*return*/, null];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._wrapAction = function (action) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var elementOffset, expectedElement, screenPointBeforeAction, clientPositionBeforeAction, availableOffset, screenPointAfterAction, clientPositionAfterAction, clientPoint, element, isTarget, offsetPositionChanged, clientPositionChanged, targetElementIsMoving;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
elementOffset = this._getElementOffset();
|
||
|
return [4 /*yield*/, containsOffset(this.element, elementOffset.x, elementOffset.y)];
|
||
|
case 1:
|
||
|
expectedElement = (_a.sent()) ? this.element : null;
|
||
|
return [4 /*yield*/, getAutomationPoint(this.element, elementOffset)];
|
||
|
case 2:
|
||
|
screenPointBeforeAction = _a.sent();
|
||
|
return [4 /*yield*/, getClientPosition(this.element)];
|
||
|
case 3:
|
||
|
clientPositionBeforeAction = _a.sent();
|
||
|
return [4 /*yield*/, action()];
|
||
|
case 4:
|
||
|
_a.sent();
|
||
|
if (!this.options.isDefaultOffset) return [3 /*break*/, 6];
|
||
|
return [4 /*yield*/, this._getAvailableOffset(expectedElement, elementOffset)];
|
||
|
case 5:
|
||
|
availableOffset = _a.sent();
|
||
|
elementOffset.x = (availableOffset === null || availableOffset === void 0 ? void 0 : availableOffset.x) || elementOffset.x;
|
||
|
elementOffset.y = (availableOffset === null || availableOffset === void 0 ? void 0 : availableOffset.y) || elementOffset.y;
|
||
|
this.options.offsetX = elementOffset.x;
|
||
|
this.options.offsetY = elementOffset.y;
|
||
|
_a.label = 6;
|
||
|
case 6: return [4 /*yield*/, getAutomationPoint(this.element, elementOffset)];
|
||
|
case 7:
|
||
|
screenPointAfterAction = _a.sent();
|
||
|
return [4 /*yield*/, getClientPosition(this.element)];
|
||
|
case 8:
|
||
|
clientPositionAfterAction = _a.sent();
|
||
|
return [4 /*yield*/, convertToClient(this.element, screenPointAfterAction)];
|
||
|
case 9:
|
||
|
clientPoint = _a.sent();
|
||
|
return [4 /*yield*/, getElementFromPoint$2(clientPoint, this.window, expectedElement)];
|
||
|
case 10:
|
||
|
element = _a.sent();
|
||
|
if (!element) {
|
||
|
return [2 /*return*/, ElementState.create({
|
||
|
element: null,
|
||
|
clientPoint: null,
|
||
|
screenPoint: null,
|
||
|
isTarget: false,
|
||
|
inMoving: false,
|
||
|
})];
|
||
|
}
|
||
|
return [4 /*yield*/, this._isTargetElement(element, expectedElement)];
|
||
|
case 11:
|
||
|
isTarget = _a.sent();
|
||
|
offsetPositionChanged = screenPointBeforeAction.x !== screenPointAfterAction.x ||
|
||
|
screenPointBeforeAction.y !== screenPointAfterAction.y;
|
||
|
clientPositionChanged = clientPositionBeforeAction.x !== clientPositionAfterAction.x ||
|
||
|
clientPositionBeforeAction.y !== clientPositionAfterAction.y;
|
||
|
targetElementIsMoving = offsetPositionChanged && clientPositionChanged;
|
||
|
return [2 /*return*/, ElementState.create({
|
||
|
element: element,
|
||
|
clientPoint: clientPoint,
|
||
|
screenPoint: screenPointAfterAction,
|
||
|
isTarget: isTarget,
|
||
|
inMoving: targetElementIsMoving,
|
||
|
})];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._checkElementState = function (state, useStrictElementCheck) {
|
||
|
if (!state.element) {
|
||
|
throw new ActionElementIsInvisibleError(null, {
|
||
|
reason: getElOutsideBoundsReason(this.element),
|
||
|
});
|
||
|
}
|
||
|
if (useStrictElementCheck && (!state.isTarget || state.inMoving))
|
||
|
throw new ActionElementIsNotTargetError();
|
||
|
return state;
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._ensureElement = function (useStrictElementCheck, skipCheckAfterMoving, skipMoving) {
|
||
|
var _this = this;
|
||
|
if (skipCheckAfterMoving === void 0) { skipCheckAfterMoving = false; }
|
||
|
if (skipMoving === void 0) { skipMoving = false; }
|
||
|
return this
|
||
|
._wrapAction(function () { return _this._scrollToElement(); })
|
||
|
.then(function (state) { return _this._checkElementState(state, useStrictElementCheck); })
|
||
|
.then(function (state) {
|
||
|
return skipMoving ? state : _this._wrapAction(function () { return _this._moveToElement(); });
|
||
|
})
|
||
|
.then(function (state) {
|
||
|
if (!skipCheckAfterMoving)
|
||
|
_this._checkElementState(state, useStrictElementCheck);
|
||
|
return state;
|
||
|
})
|
||
|
.then(function (state) {
|
||
|
var element = state === null || state === void 0 ? void 0 : state.element;
|
||
|
_this.emit(_this.TARGET_ELEMENT_FOUND_EVENT, { element: element || null });
|
||
|
if (!useStrictElementCheck && element && !state.isTarget) {
|
||
|
var expectedElementStr = stringifyElement(_this.element);
|
||
|
var actualElementStr = stringifyElement(element);
|
||
|
_this.emit(_this.WARNING_EVENT, {
|
||
|
type: WARNING_TYPES.elementOverlapped,
|
||
|
args: [expectedElementStr, actualElementStr],
|
||
|
});
|
||
|
}
|
||
|
return {
|
||
|
element: (state === null || state === void 0 ? void 0 : state.element) || null,
|
||
|
clientPoint: (state === null || state === void 0 ? void 0 : state.clientPoint) || null,
|
||
|
screenPoint: (state === null || state === void 0 ? void 0 : state.screenPoint) || null,
|
||
|
devicePoint: (state === null || state === void 0 ? void 0 : state.devicePoint) || null,
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
VisibleElementAutomation.prototype._contains = function (parent, child) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var parents, _i, parents_1, el;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0: return [4 /*yield*/, getParents(child)];
|
||
|
case 1:
|
||
|
parents = _a.sent();
|
||
|
for (_i = 0, parents_1 = parents; _i < parents_1.length; _i++) {
|
||
|
el = parents_1[_i];
|
||
|
if (el === parent)
|
||
|
return [2 /*return*/, true];
|
||
|
}
|
||
|
return [2 /*return*/, false];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
return VisibleElementAutomation;
|
||
|
}(EventEmitter));
|
||
|
|
||
|
var Promise$3 = hammerhead__default.Promise;
|
||
|
function calculatePosition(el, position) {
|
||
|
var centerX = Math.floor(el.scrollWidth / 2 - el.clientWidth / 2);
|
||
|
var centerY = Math.floor(el.scrollHeight / 2 - el.clientHeight / 2);
|
||
|
var positions = {
|
||
|
'top': [centerX, 0],
|
||
|
'right': [el.scrollWidth, centerY],
|
||
|
'bottom': [centerX, el.scrollHeight],
|
||
|
'left': [0, centerY],
|
||
|
'topRight': [el.scrollWidth, 0],
|
||
|
'topLeft': [0, 0],
|
||
|
'bottomRight': [el.scrollWidth, el.scrollHeight],
|
||
|
'bottomLeft': [0, el.scrollHeight],
|
||
|
'center': [centerX, centerY],
|
||
|
};
|
||
|
return positions[position];
|
||
|
}
|
||
|
var SetScrollAutomation = /** @class */ (function (_super) {
|
||
|
__extends(SetScrollAutomation, _super);
|
||
|
function SetScrollAutomation(element, _a, offsetOptions) {
|
||
|
var _b;
|
||
|
var x = _a.x, y = _a.y, position = _a.position, byX = _a.byX, byY = _a.byY;
|
||
|
var _this = _super.call(this, element, offsetOptions, window, cursor) || this;
|
||
|
if (position)
|
||
|
_b = calculatePosition(element, position), x = _b[0], y = _b[1];
|
||
|
_this.scrollLeft = typeof x === 'number' ? x : element.scrollLeft;
|
||
|
_this.scrollTop = typeof y === 'number' ? y : element.scrollTop;
|
||
|
if (byX)
|
||
|
_this.scrollLeft += byX;
|
||
|
if (byY)
|
||
|
_this.scrollTop += byY;
|
||
|
return _this;
|
||
|
}
|
||
|
SetScrollAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
var promise = Promise$3.resolve();
|
||
|
if (this.element !== document.scrollingElement && this.element !== document.documentElement)
|
||
|
promise = this._ensureElement(useStrictElementCheck, true, true);
|
||
|
return promise
|
||
|
.then(function () {
|
||
|
_this.element.scrollLeft = _this.scrollLeft;
|
||
|
_this.element.scrollTop = _this.scrollTop;
|
||
|
});
|
||
|
};
|
||
|
return SetScrollAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var ScrollIntoViewAutomation = /** @class */ (function (_super) {
|
||
|
__extends(ScrollIntoViewAutomation, _super);
|
||
|
function ScrollIntoViewAutomation(element, offsetOptions) {
|
||
|
return _super.call(this, element, offsetOptions, window, cursor) || this;
|
||
|
}
|
||
|
ScrollIntoViewAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
return this._ensureElement(useStrictElementCheck, true, true);
|
||
|
};
|
||
|
return ScrollIntoViewAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var Promise$4 = hammerhead__default.Promise;
|
||
|
var nativeMethods$7 = hammerhead__default.nativeMethods;
|
||
|
var browserUtils$3 = hammerhead__default.utils.browser;
|
||
|
var focusBlurSandbox = hammerhead__default.eventSandbox.focusBlur;
|
||
|
var contentEditable = testCafeCore__default.contentEditable;
|
||
|
var textSelection = testCafeCore__default.textSelection;
|
||
|
var domUtils$1 = testCafeCore__default.domUtils;
|
||
|
var styleUtils$1 = testCafeCore__default.styleUtils;
|
||
|
var messageSandbox$1 = hammerhead__default.eventSandbox.message;
|
||
|
var GET_IFRAME_REQUEST_CMD = 'automation|iframe|request';
|
||
|
var GET_IFRAME_RESPONSE_CMD = 'automation|iframe|response';
|
||
|
messageSandbox$1.on(messageSandbox$1.SERVICE_MSG_RECEIVED_EVENT, function (e) {
|
||
|
if (e.message.cmd === GET_IFRAME_REQUEST_CMD) {
|
||
|
var iframeElement = domUtils$1.findIframeByWindow(e.source);
|
||
|
focusBlurSandbox.focus(iframeElement, function () {
|
||
|
messageSandbox$1.sendServiceMsg({ cmd: GET_IFRAME_RESPONSE_CMD }, e.source);
|
||
|
}, false);
|
||
|
}
|
||
|
});
|
||
|
function setCaretPosition(element, caretPos) {
|
||
|
var isTextEditable = domUtils$1.isTextEditableElement(element);
|
||
|
var isContentEditable = domUtils$1.isContentEditableElement(element);
|
||
|
if (isTextEditable || isContentEditable) {
|
||
|
if (isContentEditable && isNaN(parseInt(caretPos, 10)))
|
||
|
textSelection.setCursorToLastVisiblePosition(element);
|
||
|
else {
|
||
|
var position = isNaN(parseInt(caretPos, 10)) ? domUtils$1.getElementValue(element).length : caretPos;
|
||
|
textSelection.select(element, position, position);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// NOTE: if focus is called for a non-contentEditable element (like 'img' or 'button') inside
|
||
|
// a contentEditable parent, we should try to set the right window selection. Generally, we can't
|
||
|
// set the right window selection object because after the selection setup, the window.getSelection
|
||
|
// method returns a different object, which depends on the browser.
|
||
|
var contentEditableParent = contentEditable.findContentEditableParent(element);
|
||
|
if (contentEditableParent)
|
||
|
textSelection.setCursorToLastVisiblePosition(contentEditable.findContentEditableParent(contentEditableParent));
|
||
|
}
|
||
|
}
|
||
|
function focusAndSetSelection(element, simulateFocus, caretPos) {
|
||
|
var _this = this;
|
||
|
return new Promise$4(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
|
||
|
var activeElement, isTextEditable, labelWithForAttr, isElementFocusable, shouldFocusByRelatedElement, isContentEditable, elementForFocus, focusWithSilentMode, focusForMouseEvent, preventScrolling, curDocument, curActiveElement, isActiveElementBody, focusableParent, elementChildOfActiveElement;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0:
|
||
|
if (!isIframeWindow(window)) return [3 /*break*/, 2];
|
||
|
return [4 /*yield*/, sendRequestToFrame({ cmd: GET_IFRAME_REQUEST_CMD }, GET_IFRAME_RESPONSE_CMD, window.parent)];
|
||
|
case 1:
|
||
|
_a.sent();
|
||
|
_a.label = 2;
|
||
|
case 2:
|
||
|
activeElement = domUtils$1.getActiveElement();
|
||
|
isTextEditable = domUtils$1.isTextEditableElement(element);
|
||
|
labelWithForAttr = domUtils$1.closest(element, 'label[for]');
|
||
|
isElementFocusable = domUtils$1.isElementFocusable(element);
|
||
|
shouldFocusByRelatedElement = !isElementFocusable && labelWithForAttr;
|
||
|
isContentEditable = domUtils$1.isContentEditableElement(element);
|
||
|
elementForFocus = isContentEditable ? contentEditable.findContentEditableParent(element) : element;
|
||
|
// NOTE: in WebKit, if selection was never set in an input element, the focus method selects all the
|
||
|
// text in this element. So, we should call select before focus to set the caret to the first symbol.
|
||
|
if (simulateFocus && browserUtils$3.isWebKit && isTextEditable)
|
||
|
textSelection.select(element, 0, 0);
|
||
|
// NOTE: we should call focus for the element related with a 'label' that has the 'for' attribute
|
||
|
if (shouldFocusByRelatedElement) {
|
||
|
if (simulateFocus)
|
||
|
focusByLabel(labelWithForAttr);
|
||
|
resolve();
|
||
|
return [2 /*return*/];
|
||
|
}
|
||
|
focusWithSilentMode = !simulateFocus;
|
||
|
focusForMouseEvent = true;
|
||
|
preventScrolling = false;
|
||
|
if (!isElementFocusable && !isContentEditable) {
|
||
|
curDocument = domUtils$1.findDocument(elementForFocus);
|
||
|
curActiveElement = nativeMethods$7.documentActiveElementGetter.call(curDocument);
|
||
|
isActiveElementBody = domUtils$1.isBodyElement(curActiveElement);
|
||
|
focusableParent = domUtils$1.isBodyElement(elementForFocus) ?
|
||
|
elementForFocus : domUtils$1.getFocusableParent(elementForFocus);
|
||
|
elementChildOfActiveElement = curActiveElement && !isActiveElementBody &&
|
||
|
domUtils$1.containsElement(curActiveElement, elementForFocus);
|
||
|
if (elementChildOfActiveElement || isActiveElementBody && domUtils$1.isBodyElement(focusableParent)) {
|
||
|
resolve();
|
||
|
return [2 /*return*/];
|
||
|
}
|
||
|
elementForFocus = focusableParent || curDocument.body;
|
||
|
preventScrolling = true;
|
||
|
}
|
||
|
focusBlurSandbox.focus(elementForFocus, function () {
|
||
|
// NOTE: if a different element was focused in the focus event handler, we should not set selection
|
||
|
if (simulateFocus && !isContentEditable && element !== domUtils$1.getActiveElement()) {
|
||
|
resolve();
|
||
|
return;
|
||
|
}
|
||
|
setCaretPosition(element, caretPos);
|
||
|
// NOTE: we can't avoid the element being focused because the setSelection method leads to focusing.
|
||
|
// So, we just focus the previous active element without handlers if we don't need focus here
|
||
|
if (!simulateFocus && domUtils$1.getActiveElement() !== activeElement)
|
||
|
focusBlurSandbox.focus(activeElement, resolve, true, true);
|
||
|
else
|
||
|
resolve();
|
||
|
}, focusWithSilentMode, focusForMouseEvent, false, preventScrolling);
|
||
|
return [2 /*return*/];
|
||
|
}
|
||
|
});
|
||
|
}); });
|
||
|
}
|
||
|
function getElementBoundToLabel(element) {
|
||
|
var labelWithForAttr = domUtils$1.closest(element, 'label[for]');
|
||
|
var control = labelWithForAttr && (labelWithForAttr.control || document.getElementById(labelWithForAttr.htmlFor));
|
||
|
var isControlVisible = control && styleUtils$1.isElementVisible(control);
|
||
|
return isControlVisible ? control : null;
|
||
|
}
|
||
|
function focusByLabel(label) {
|
||
|
if (domUtils$1.isElementFocusable(label))
|
||
|
focusBlurSandbox.focus(label, testCafeCore__default.noop, false, true);
|
||
|
else
|
||
|
focusByRelatedElement(label);
|
||
|
}
|
||
|
function focusByRelatedElement(element) {
|
||
|
var elementForFocus = getElementBoundToLabel(element);
|
||
|
if (!elementForFocus || domUtils$1.getActiveElement() === elementForFocus)
|
||
|
return;
|
||
|
focusBlurSandbox.focus(elementForFocus, testCafeCore__default.noop, false, true);
|
||
|
}
|
||
|
|
||
|
var browserUtils$4 = hammerhead__default.utils.browser;
|
||
|
var eventSimulator$3 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var listeners$2 = hammerhead__default.eventSandbox.listeners;
|
||
|
var nativeMethods$8 = hammerhead__default.nativeMethods;
|
||
|
var domUtils$2 = testCafeCore__default.domUtils;
|
||
|
var styleUtils$2 = testCafeCore__default.styleUtils;
|
||
|
var selectController = testCafeCore__default.selectController;
|
||
|
var selectElementUI = testCafeUI.selectElement;
|
||
|
var ElementClickCommand = /** @class */ (function () {
|
||
|
function ElementClickCommand(eventState, eventArgs) {
|
||
|
this.eventState = eventState;
|
||
|
this.eventArgs = eventArgs;
|
||
|
}
|
||
|
ElementClickCommand.prototype.run = function () {
|
||
|
if (this.eventState.clickElement)
|
||
|
eventSimulator$3.click(this.eventState.clickElement, this.eventArgs.options);
|
||
|
if (!domUtils$2.isElementFocusable(this.eventArgs.element))
|
||
|
focusByRelatedElement(this.eventArgs.element);
|
||
|
};
|
||
|
return ElementClickCommand;
|
||
|
}());
|
||
|
var LabelElementClickCommand = /** @class */ (function (_super) {
|
||
|
__extends(LabelElementClickCommand, _super);
|
||
|
function LabelElementClickCommand(eventState, eventArgs) {
|
||
|
var _this = _super.call(this, eventState, eventArgs) || this;
|
||
|
_this.targetElement = _this.eventArgs.element;
|
||
|
_this.input = getElementBoundToLabel(_this.eventArgs.element);
|
||
|
return _this;
|
||
|
}
|
||
|
LabelElementClickCommand.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
var focusRaised = false;
|
||
|
var ensureFocusRaised = function (e) {
|
||
|
focusRaised = nativeMethods$8.eventTargetGetter.call(e) === _this.input;
|
||
|
};
|
||
|
listeners$2.addInternalEventBeforeListener(window, ['focus'], ensureFocusRaised);
|
||
|
_super.prototype.run.call(this);
|
||
|
listeners$2.removeInternalEventBeforeListener(window, ['focus'], ensureFocusRaised);
|
||
|
if (domUtils$2.isElementFocusable(this.targetElement) && !focusRaised)
|
||
|
this._ensureBoundElementFocusRaised();
|
||
|
};
|
||
|
LabelElementClickCommand.prototype._ensureBoundElementFocusRaised = function () {
|
||
|
eventSimulator$3.focus(this.input);
|
||
|
};
|
||
|
return LabelElementClickCommand;
|
||
|
}(ElementClickCommand));
|
||
|
var SelectElementClickCommand = /** @class */ (function (_super) {
|
||
|
__extends(SelectElementClickCommand, _super);
|
||
|
function SelectElementClickCommand(eventState, eventArgs) {
|
||
|
return _super.call(this, eventState, eventArgs) || this;
|
||
|
}
|
||
|
SelectElementClickCommand.prototype.run = function () {
|
||
|
_super.prototype.run.call(this);
|
||
|
this._toggleSelectOptionList();
|
||
|
};
|
||
|
SelectElementClickCommand.prototype._toggleSelectOptionList = function () {
|
||
|
// NOTE: Emulating the click event on the 'select' element doesn't expand the
|
||
|
// dropdown with options (except chrome), therefore we should emulate it.
|
||
|
var element = this.eventArgs.element;
|
||
|
var isSelectWithDropDown = styleUtils$2.getSelectElementSize(element) === 1;
|
||
|
if (isSelectWithDropDown && this.eventState.simulateDefaultBehavior !== false) {
|
||
|
if (selectController.isOptionListExpanded(element))
|
||
|
selectElementUI.collapseOptionList();
|
||
|
else
|
||
|
selectElementUI.expandOptionList(element);
|
||
|
}
|
||
|
};
|
||
|
return SelectElementClickCommand;
|
||
|
}(ElementClickCommand));
|
||
|
var OptionElementClickCommand = /** @class */ (function (_super) {
|
||
|
__extends(OptionElementClickCommand, _super);
|
||
|
function OptionElementClickCommand(eventState, eventArgs) {
|
||
|
return _super.call(this, eventState, eventArgs) || this;
|
||
|
}
|
||
|
OptionElementClickCommand.prototype.run = function () {
|
||
|
return this.eventArgs.element;
|
||
|
};
|
||
|
return OptionElementClickCommand;
|
||
|
}(ElementClickCommand));
|
||
|
var LabelledCheckboxElementClickCommand = /** @class */ (function (_super) {
|
||
|
__extends(LabelledCheckboxElementClickCommand, _super);
|
||
|
function LabelledCheckboxElementClickCommand(eventState, eventArgs) {
|
||
|
var _this = _super.call(this, eventState, eventArgs) || this;
|
||
|
_this.checkbox = _this.input;
|
||
|
return _this;
|
||
|
}
|
||
|
LabelledCheckboxElementClickCommand.prototype.run = function () {
|
||
|
var changed = false;
|
||
|
var onChange = function () {
|
||
|
changed = true;
|
||
|
};
|
||
|
listeners$2.addInternalEventBeforeListener(window, ['change'], onChange);
|
||
|
_super.prototype.run.call(this);
|
||
|
listeners$2.removeInternalEventBeforeListener(window, ['change'], onChange);
|
||
|
// NOTE: Two overlapping issues: https://github.com/DevExpress/testcafe/issues/3348 and https://github.com/DevExpress/testcafe/issues/6949
|
||
|
// When label contains <a href=any> or <button> element, clicking these elements should prevent checkbox from changing checked state.
|
||
|
// Also, checkbox state should not be changed if it is disabled.
|
||
|
// We should to leave the code for fixing .focus issue and add additional check for the clickable elements inside the label:
|
||
|
if (browserUtils$4.isChrome && !changed && !this.checkbox.disabled && !this._isClickableElementInsideLabel(this.targetElement))
|
||
|
this._ensureCheckboxStateChanged();
|
||
|
};
|
||
|
LabelledCheckboxElementClickCommand.prototype._ensureCheckboxStateChanged = function () {
|
||
|
this.checkbox.checked = !this.checkbox.checked;
|
||
|
eventSimulator$3.change(this.checkbox);
|
||
|
};
|
||
|
LabelledCheckboxElementClickCommand.prototype._isClickableElementInsideLabel = function (element) {
|
||
|
var isClickableLink = domUtils$2.isAnchorElement(element) && element.getAttribute('href');
|
||
|
var isButton = domUtils$2.isButtonElement(element);
|
||
|
return isClickableLink || isButton;
|
||
|
};
|
||
|
return LabelledCheckboxElementClickCommand;
|
||
|
}(LabelElementClickCommand));
|
||
|
function createClickCommand (eventState, eventArgs) {
|
||
|
var elementBoundToLabel = getElementBoundToLabel(eventArgs.element);
|
||
|
var isSelectElement = domUtils$2.isSelectElement(eventArgs.element);
|
||
|
var isOptionElement = domUtils$2.isOptionElement(eventArgs.element);
|
||
|
var isLabelElement = domUtils$2.isLabelElement(eventArgs.element) && elementBoundToLabel;
|
||
|
var isLabelledCheckbox = elementBoundToLabel && domUtils$2.isCheckboxElement(elementBoundToLabel);
|
||
|
if (isSelectElement)
|
||
|
return new SelectElementClickCommand(eventState, eventArgs);
|
||
|
if (isOptionElement)
|
||
|
return new OptionElementClickCommand(eventState, eventArgs);
|
||
|
if (isLabelledCheckbox)
|
||
|
return new LabelledCheckboxElementClickCommand(eventState, eventArgs);
|
||
|
if (isLabelElement)
|
||
|
return new LabelElementClickCommand(eventState, eventArgs);
|
||
|
return new ElementClickCommand(eventState, eventArgs);
|
||
|
}
|
||
|
|
||
|
// @ts-ignore
|
||
|
var Promise$5 = hammerhead__default.Promise;
|
||
|
var browserUtils$5 = hammerhead__default.utils.browser;
|
||
|
var featureDetection = hammerhead__default.utils.featureDetection;
|
||
|
var eventSimulator$4 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var listeners$3 = hammerhead__default.eventSandbox.listeners;
|
||
|
var domUtils$3 = testCafeCore__default.domUtils;
|
||
|
var eventUtils$1 = testCafeCore__default.eventUtils;
|
||
|
var arrayUtils = testCafeCore__default.arrayUtils;
|
||
|
function _getElementForClick(mouseDownElement, topElement, mouseDownElementParentNodes) {
|
||
|
var topElementParentNodes = domUtils$3.getParents(topElement);
|
||
|
var areElementsSame = domUtils$3.isTheSameNode(topElement, mouseDownElement);
|
||
|
// NOTE: Mozilla Firefox always skips click, if an element under cursor has been changed after mousedown.
|
||
|
if (browserUtils$5.isFirefox)
|
||
|
return areElementsSame ? mouseDownElement : null;
|
||
|
if (!areElementsSame) {
|
||
|
// @ts-ignore
|
||
|
if (mouseDownElement.contains(topElement) && !domUtils$3.isEditableFormElement(topElement))
|
||
|
return mouseDownElement;
|
||
|
// @ts-ignore
|
||
|
if (topElement.contains(mouseDownElement))
|
||
|
return topElement;
|
||
|
// NOTE: If elements are not in the parent-child relationships,
|
||
|
// non-ff browsers raise the `click` event for their common parent.
|
||
|
return arrayUtils.getCommonElement(topElementParentNodes, mouseDownElementParentNodes);
|
||
|
}
|
||
|
// NOTE: In case the target element and the top element are the same,
|
||
|
// non-FF browsers are dispatching the `click` event if the target
|
||
|
// element hasn't changed its position in the DOM after mousedown.
|
||
|
return arrayUtils.equals(mouseDownElementParentNodes, topElementParentNodes) ? mouseDownElement : null;
|
||
|
}
|
||
|
var MouseClickStrategy = /** @class */ (function () {
|
||
|
function MouseClickStrategy(element, caretPos) {
|
||
|
this.element = element;
|
||
|
this.caretPos = caretPos;
|
||
|
this.targetElementParentNodes = [];
|
||
|
this.activeElementBeforeMouseDown = null;
|
||
|
this.mouseDownElement = null;
|
||
|
this.eventState = {
|
||
|
mousedownPrevented: false,
|
||
|
blurRaised: false,
|
||
|
simulateDefaultBehavior: true,
|
||
|
clickElement: null,
|
||
|
touchStartCancelled: false,
|
||
|
touchEndCancelled: false,
|
||
|
};
|
||
|
}
|
||
|
MouseClickStrategy.prototype.mousedown = function (eventArgs) {
|
||
|
var _this = this;
|
||
|
this.targetElementParentNodes = domUtils$3.getParents(eventArgs.element);
|
||
|
this.mouseDownElement = eventArgs.element;
|
||
|
this._raiseTouchEvents(eventArgs);
|
||
|
var activeElement = domUtils$3.getActiveElement();
|
||
|
this.activeElementBeforeMouseDown = activeElement;
|
||
|
// NOTE: In WebKit and IE, the mousedown event opens the select element's dropdown;
|
||
|
// therefore, we should prevent mousedown and hide the dropdown (B236416).
|
||
|
var needCloseSelectDropDown = (browserUtils$5.isWebKit || browserUtils$5.isIE) &&
|
||
|
domUtils$3.isSelectElement(this.mouseDownElement);
|
||
|
if (needCloseSelectDropDown)
|
||
|
this._bindMousedownHandler();
|
||
|
this._bindBlurHandler(activeElement);
|
||
|
if (!this._isTouchEventWasCancelled())
|
||
|
this.eventState.simulateDefaultBehavior = eventSimulator$4.mousedown(eventArgs.element, eventArgs.options);
|
||
|
if (this.eventState.simulateDefaultBehavior === false)
|
||
|
this.eventState.simulateDefaultBehavior = needCloseSelectDropDown && !this.eventState.mousedownPrevented;
|
||
|
return this._ensureActiveElementBlur(activeElement)
|
||
|
.then(function () { return _this._focus(eventArgs); });
|
||
|
};
|
||
|
MouseClickStrategy.prototype.mouseup = function (element, eventArgs) {
|
||
|
eventArgs.element = element;
|
||
|
this.eventState.clickElement = _getElementForClick(this.mouseDownElement, element, this.targetElementParentNodes);
|
||
|
var timeStamp = {};
|
||
|
var getTimeStamp = function (e) {
|
||
|
timeStamp = e.timeStamp;
|
||
|
listeners$3.removeInternalEventBeforeListener(window, ['mouseup'], getTimeStamp);
|
||
|
};
|
||
|
if (!browserUtils$5.isIE)
|
||
|
listeners$3.addInternalEventBeforeListener(window, ['mouseup'], getTimeStamp);
|
||
|
if (!this._isTouchEventWasCancelled())
|
||
|
eventSimulator$4.mouseup(element, eventArgs.options);
|
||
|
if (eventArgs.options)
|
||
|
eventArgs.options.timeStamp = timeStamp;
|
||
|
return this._click(eventArgs);
|
||
|
};
|
||
|
MouseClickStrategy.prototype._click = function (eventArgs) {
|
||
|
return __awaiter(this, void 0, hammerhead__default.Promise, function () {
|
||
|
var clickCommand;
|
||
|
return __generator(this, function (_a) {
|
||
|
clickCommand = createClickCommand(this.eventState, eventArgs);
|
||
|
if (!this._isTouchEventWasCancelled())
|
||
|
clickCommand.run();
|
||
|
return [2 /*return*/, eventArgs];
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
// NOTE:
|
||
|
// If `touchstart`, `touchmove`, or `touchend` are canceled, we should not dispatch any mouse event
|
||
|
// that would be a consequential result of the prevented touch event
|
||
|
MouseClickStrategy.prototype._isTouchEventWasCancelled = function () {
|
||
|
return this.eventState.touchStartCancelled || this.eventState.touchEndCancelled;
|
||
|
};
|
||
|
MouseClickStrategy.prototype._bindMousedownHandler = function () {
|
||
|
var _this = this;
|
||
|
var onmousedown = function (e) {
|
||
|
_this.eventState.mousedownPrevented = e.defaultPrevented;
|
||
|
eventUtils$1.preventDefault(e);
|
||
|
eventUtils$1.unbind(_this.element, 'mousedown', onmousedown);
|
||
|
};
|
||
|
eventUtils$1.bind(this.element, 'mousedown', onmousedown);
|
||
|
};
|
||
|
MouseClickStrategy.prototype._bindBlurHandler = function (element) {
|
||
|
var _this = this;
|
||
|
var onblur = function () {
|
||
|
_this.eventState.blurRaised = true;
|
||
|
eventUtils$1.unbind(element, 'blur', onblur, true);
|
||
|
};
|
||
|
eventUtils$1.bind(element, 'blur', onblur, true);
|
||
|
};
|
||
|
MouseClickStrategy.prototype._ensureActiveElementBlur = function (element) {
|
||
|
var _this = this;
|
||
|
// NOTE: In some cases, mousedown may lead to active element change (browsers raise blur).
|
||
|
// We simulate the blur event if the active element was changed after the mousedown, and
|
||
|
// the blur event does not get raised automatically (B239273, B253520)
|
||
|
return new Promise$5(function (resolve) {
|
||
|
var simulateBlur = domUtils$3.getActiveElement() !== element && !_this.eventState.blurRaised;
|
||
|
if (!simulateBlur) {
|
||
|
resolve();
|
||
|
return;
|
||
|
}
|
||
|
if (browserUtils$5.isIE && browserUtils$5.version < 12) {
|
||
|
// NOTE: In whatever way an element is blurred from the client script, the
|
||
|
// blur event is raised asynchronously in IE (in MSEdge focus/blur is sync)
|
||
|
nextTick()
|
||
|
.then(function () {
|
||
|
if (!_this.eventState.blurRaised)
|
||
|
eventSimulator$4.blur(element);
|
||
|
resolve();
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
eventSimulator$4.blur(element);
|
||
|
resolve();
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
MouseClickStrategy.prototype._focus = function (eventArgs) {
|
||
|
if (this.eventState.simulateDefaultBehavior === false)
|
||
|
return Promise$5.resolve();
|
||
|
// NOTE: If a target element is a contentEditable element, we need to call focusAndSetSelection directly for
|
||
|
// this element. Otherwise, if the element obtained by elementFromPoint is a child of the contentEditable
|
||
|
// element, a selection position may be calculated incorrectly (by using the caretPos option).
|
||
|
var elementForFocus = domUtils$3.isContentEditableElement(this.element) ? this.element : eventArgs.element;
|
||
|
// NOTE: IE doesn't perform focus if active element has been changed while executing mousedown
|
||
|
var simulateFocus = !browserUtils$5.isIE || this.activeElementBeforeMouseDown === domUtils$3.getActiveElement();
|
||
|
return focusAndSetSelection(elementForFocus, simulateFocus, this.caretPos);
|
||
|
};
|
||
|
MouseClickStrategy.prototype._raiseTouchEvents = function (eventArgs) {
|
||
|
if (featureDetection.isTouchDevice) {
|
||
|
this.eventState.touchStartCancelled = !eventSimulator$4.touchstart(eventArgs.element, eventArgs.options);
|
||
|
this.eventState.touchEndCancelled = !eventSimulator$4.touchend(eventArgs.element, eventArgs.options);
|
||
|
}
|
||
|
};
|
||
|
return MouseClickStrategy;
|
||
|
}());
|
||
|
function createMouseClickStrategy(element, caretPos) {
|
||
|
return new MouseClickStrategy(element, caretPos);
|
||
|
}
|
||
|
|
||
|
var ClickAutomation = /** @class */ (function (_super) {
|
||
|
__extends(ClickAutomation, _super);
|
||
|
function ClickAutomation(element, clickOptions, win, cursor, dispatchProxylessEventFn, leftTopPoint) {
|
||
|
var _this = _super.call(this, element, clickOptions, win, cursor, dispatchProxylessEventFn, leftTopPoint) || this;
|
||
|
_this.modifiers = clickOptions.modifiers;
|
||
|
_this.strategy = createMouseClickStrategy(_this.element, clickOptions.caretPos);
|
||
|
return _this;
|
||
|
}
|
||
|
ClickAutomation.prototype._mousedown = function (eventArgs) {
|
||
|
if (this.canUseProxylessEventSimulator(eventArgs.element))
|
||
|
return this.proxylessEventSimulator.mouseDown(eventArgs);
|
||
|
return this.strategy.mousedown(eventArgs);
|
||
|
};
|
||
|
ClickAutomation.prototype._mouseup = function (element, eventArgs) {
|
||
|
if (this.canUseProxylessEventSimulator(eventArgs.element))
|
||
|
return this.proxylessEventSimulator.mouseUp(eventArgs);
|
||
|
return this.strategy.mouseup(element, eventArgs);
|
||
|
};
|
||
|
ClickAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
var eventArgs;
|
||
|
return this
|
||
|
._ensureElement(useStrictElementCheck)
|
||
|
.then(function (_a) {
|
||
|
var element = _a.element, clientPoint = _a.clientPoint, screenPoint = _a.screenPoint, devicePoint = _a.devicePoint;
|
||
|
eventArgs = {
|
||
|
point: clientPoint,
|
||
|
screenPoint: screenPoint,
|
||
|
element: element,
|
||
|
options: hammerhead.utils.extend({
|
||
|
clientX: clientPoint === null || clientPoint === void 0 ? void 0 : clientPoint.x,
|
||
|
clientY: clientPoint === null || clientPoint === void 0 ? void 0 : clientPoint.y,
|
||
|
screenX: devicePoint === null || devicePoint === void 0 ? void 0 : devicePoint.x,
|
||
|
screenY: devicePoint === null || devicePoint === void 0 ? void 0 : devicePoint.y,
|
||
|
}, _this.modifiers),
|
||
|
};
|
||
|
// NOTE: we should raise mouseup event with 'mouseActionStepDelay' after we trigger
|
||
|
// mousedown event regardless of how long mousedown event handlers were executing
|
||
|
return hammerhead.Promise.all([delay(_this.automationSettings.mouseActionStepDelay), _this.cursor
|
||
|
.leftButtonDown()
|
||
|
.then(function () { return _this._mousedown(eventArgs); }),
|
||
|
]);
|
||
|
})
|
||
|
.then(function () { return _this.cursor.buttonUp(); })
|
||
|
.then(function () { return _this._getElementForEvent(eventArgs); })
|
||
|
.then(function (element) {
|
||
|
return element ? _this._mouseup(element, eventArgs) : null;
|
||
|
});
|
||
|
};
|
||
|
return ClickAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
function getLineYByXCoord(startLine, endLine, x) {
|
||
|
if (endLine.x === startLine.x)
|
||
|
return 0;
|
||
|
var equationSlope = (endLine.y - startLine.y) / (endLine.x - startLine.x);
|
||
|
var equationYIntercept = startLine.x * (startLine.y - endLine.y) / (endLine.x - startLine.x) + startLine.y;
|
||
|
return Math.round(equationSlope * x + equationYIntercept);
|
||
|
}
|
||
|
function getLineXByYCoord(startLine, endLine, y) {
|
||
|
if (endLine.y - startLine.y === 0)
|
||
|
return 0;
|
||
|
var equationSlope = (endLine.x - startLine.x) / (endLine.y - startLine.y);
|
||
|
var equationXIntercept = startLine.y * (startLine.x - endLine.x) / (endLine.y - startLine.y) + startLine.x;
|
||
|
return Math.round(equationSlope * y + equationXIntercept);
|
||
|
}
|
||
|
|
||
|
function findIntersectionHorizontal(startLinePoint, endLinePoint, rectSide) {
|
||
|
var intersectionX = getLineXByYCoord(startLinePoint, endLinePoint, rectSide.top);
|
||
|
var haveIntersectionInBounds = intersectionX && intersectionX >= rectSide.left && intersectionX <= rectSide.right;
|
||
|
return haveIntersectionInBounds ? new AxisValues(intersectionX, rectSide.top) : null;
|
||
|
}
|
||
|
function findIntersectionVertical(startLinePoint, endLinePoint, rectSide) {
|
||
|
var intersectionY = getLineYByXCoord(startLinePoint, endLinePoint, rectSide.left);
|
||
|
var haveIntersectionInBounds = intersectionY && intersectionY >= rectSide.top && intersectionY <= rectSide.bottom;
|
||
|
return haveIntersectionInBounds ? new AxisValues(rectSide.left, intersectionY) : null;
|
||
|
}
|
||
|
function getLineRectIntersection (startLine, endLine, rect) {
|
||
|
var res = [];
|
||
|
var rectLines = [
|
||
|
{ left: rect.left, top: rect.top, right: rect.left, bottom: rect.bottom, isHorizontal: false },
|
||
|
{ left: rect.right, top: rect.top, right: rect.right, bottom: rect.bottom, isHorizontal: false },
|
||
|
{ left: rect.left, top: rect.top, right: rect.right, bottom: rect.top, isHorizontal: true },
|
||
|
{ left: rect.left, top: rect.bottom, right: rect.right, bottom: rect.bottom, isHorizontal: true }, // bottom-side
|
||
|
];
|
||
|
for (var _i = 0, rectLines_1 = rectLines; _i < rectLines_1.length; _i++) {
|
||
|
var rectLine = rectLines_1[_i];
|
||
|
var intersection = rectLine.isHorizontal
|
||
|
? findIntersectionHorizontal(startLine, endLine, rectLine)
|
||
|
: findIntersectionVertical(startLine, endLine, rectLine);
|
||
|
if (intersection)
|
||
|
res.push(intersection);
|
||
|
}
|
||
|
if (!res.length)
|
||
|
return null;
|
||
|
if (res.length === 1)
|
||
|
return res[0];
|
||
|
// NOTE: if a line and rect have two intersection points, we return the nearest to startLinePoint
|
||
|
return res[0].distance(startLine) < res[1].distance(startLine) ? res[0] : res[1];
|
||
|
}
|
||
|
|
||
|
var eventSimulator$5 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var messageSandbox$2 = hammerhead__default.eventSandbox.message;
|
||
|
var positionUtils$2 = testCafeCore__default.positionUtils;
|
||
|
var domUtils$4 = testCafeCore__default.domUtils;
|
||
|
var styleUtils$3 = testCafeCore__default.styleUtils;
|
||
|
var MOVE_REQUEST_CMD$1 = 'automation|move|request';
|
||
|
var MOVE_RESPONSE_CMD$1 = 'automation|move|response';
|
||
|
function onMoveToIframeRequest(e) {
|
||
|
var iframePoint = new AxisValues(e.message.endX, e.message.endY);
|
||
|
var iframeWin = e.source;
|
||
|
var iframe = domUtils$4.findIframeByWindow(iframeWin);
|
||
|
var iframeBorders = styleUtils$3.getBordersWidth(iframe);
|
||
|
var iframePadding = styleUtils$3.getElementPadding(iframe);
|
||
|
var iframeRectangle = positionUtils$2.getIframeClientCoordinates(iframe);
|
||
|
var iframePointRelativeToParent = positionUtils$2.getIframePointRelativeToParentFrame(iframePoint, iframeWin);
|
||
|
var cursorPosition = cursor.getPosition();
|
||
|
cursor.shouldRender = e.message.shouldRender;
|
||
|
var intersectionPoint = positionUtils$2.isInRectangle(cursorPosition, iframeRectangle) ? cursorPosition :
|
||
|
getLineRectIntersection(cursorPosition, iframePointRelativeToParent, iframeRectangle);
|
||
|
var intersectionRelatedToIframe = {
|
||
|
x: intersectionPoint.x - iframeRectangle.left,
|
||
|
y: intersectionPoint.y - iframeRectangle.top,
|
||
|
};
|
||
|
var moveOptions = new MoveOptions({
|
||
|
modifiers: e.message.modifiers,
|
||
|
offsetX: intersectionRelatedToIframe.x + iframeBorders.left + iframePadding.left,
|
||
|
offsetY: intersectionRelatedToIframe.y + iframeBorders.top + iframePadding.top,
|
||
|
speed: e.message.speed,
|
||
|
// NOTE: we should not perform scrolling because the active window was
|
||
|
// already scrolled to the target element before the request (GH-847)
|
||
|
skipScrolling: true,
|
||
|
}, false);
|
||
|
var responseMsg = {
|
||
|
cmd: MOVE_RESPONSE_CMD$1,
|
||
|
x: intersectionRelatedToIframe.x,
|
||
|
y: intersectionRelatedToIframe.y,
|
||
|
};
|
||
|
if (cursor.getActiveWindow(window) !== iframeWin) {
|
||
|
// const moveAutomation = new MoveAutomation(iframe, moveOptions);
|
||
|
MoveAutomation.create(iframe, moveOptions, window, cursor)
|
||
|
.then(function (moveAutomation) {
|
||
|
return moveAutomation.run();
|
||
|
})
|
||
|
.then(function () {
|
||
|
cursor.setActiveWindow(iframeWin);
|
||
|
messageSandbox$2.sendServiceMsg(responseMsg, iframeWin);
|
||
|
});
|
||
|
}
|
||
|
else
|
||
|
messageSandbox$2.sendServiceMsg(responseMsg, iframeWin);
|
||
|
}
|
||
|
function onMoveOutRequest(e) {
|
||
|
var parentWin = e.source;
|
||
|
var iframeRectangle = {
|
||
|
left: e.message.left,
|
||
|
right: e.message.right,
|
||
|
top: e.message.top,
|
||
|
bottom: e.message.bottom,
|
||
|
};
|
||
|
if (!e.message.iframeUnderCursor) {
|
||
|
var _a = e.message, startX = _a.startX, startY = _a.startY;
|
||
|
var clientX = startX - iframeRectangle.left;
|
||
|
var clientY = startY - iframeRectangle.top;
|
||
|
// NOTE: We should not emulate mouseout and mouseleave if iframe was reloaded.
|
||
|
var element = lastHoveredElementHolder.get();
|
||
|
if (element) {
|
||
|
eventSimulator$5.mouseout(element, { clientX: clientX, clientY: clientY, relatedTarget: null });
|
||
|
eventSimulator$5.mouseleave(element, { clientX: clientX, clientY: clientY, relatedTarget: null });
|
||
|
}
|
||
|
messageSandbox$2.sendServiceMsg({ cmd: MOVE_RESPONSE_CMD$1 }, parentWin);
|
||
|
return;
|
||
|
}
|
||
|
var cursorPosition = cursor.getPosition();
|
||
|
var startPoint = AxisValues.create(iframeRectangle).add(cursorPosition);
|
||
|
var endPoint = new AxisValues(e.message.endX, e.message.endY);
|
||
|
var intersectionPoint = getLineRectIntersection(startPoint, endPoint, iframeRectangle);
|
||
|
// NOTE: We should not move the cursor out of the iframe if
|
||
|
// the cursor path does not intersect with the iframe borders.
|
||
|
if (!intersectionPoint) {
|
||
|
messageSandbox$2.sendServiceMsg({
|
||
|
cmd: MOVE_RESPONSE_CMD$1,
|
||
|
x: iframeRectangle.left,
|
||
|
y: iframeRectangle.top,
|
||
|
}, parentWin);
|
||
|
return;
|
||
|
}
|
||
|
var moveOptions = new MoveOptions({
|
||
|
modifiers: e.message.modifiers,
|
||
|
offsetX: intersectionPoint.x - iframeRectangle.left,
|
||
|
offsetY: intersectionPoint.y - iframeRectangle.top,
|
||
|
speed: e.message.speed,
|
||
|
// NOTE: we should not perform scrolling because the active window was
|
||
|
// already scrolled to the target element before the request (GH-847)
|
||
|
skipScrolling: true,
|
||
|
}, false);
|
||
|
MoveAutomation.create(document.documentElement, moveOptions, window, cursor)
|
||
|
.then(function (moveAutomation) {
|
||
|
return moveAutomation.run();
|
||
|
})
|
||
|
.then(function () {
|
||
|
var responseMsg = {
|
||
|
cmd: MOVE_RESPONSE_CMD$1,
|
||
|
x: intersectionPoint.x,
|
||
|
y: intersectionPoint.y,
|
||
|
};
|
||
|
cursor.setActiveWindow(parentWin);
|
||
|
messageSandbox$2.sendServiceMsg(responseMsg, parentWin);
|
||
|
});
|
||
|
}
|
||
|
// Setup cross-iframe interaction
|
||
|
messageSandbox$2.on(messageSandbox$2.SERVICE_MSG_RECEIVED_EVENT, function (e) {
|
||
|
if (e.message.cmd === MOVE_REQUEST_CMD$1) {
|
||
|
if (e.source.parent === window)
|
||
|
onMoveToIframeRequest(e);
|
||
|
else {
|
||
|
hammerhead__default.on(hammerhead__default.EVENTS.beforeUnload, function () { return messageSandbox$2.sendServiceMsg({ cmd: MOVE_RESPONSE_CMD$1 }, e.source); });
|
||
|
onMoveOutRequest(e);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
var Promise$6 = hammerhead__default.Promise;
|
||
|
var browserUtils$6 = hammerhead__default.utils.browser;
|
||
|
var featureDetection$1 = hammerhead__default.utils.featureDetection;
|
||
|
var eventSimulator$6 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var focusBlurSandbox$1 = hammerhead__default.eventSandbox.focusBlur;
|
||
|
var nativeMethods$9 = hammerhead__default.nativeMethods;
|
||
|
var domUtils$5 = testCafeCore__default.domUtils;
|
||
|
var styleUtils$4 = testCafeCore__default.styleUtils;
|
||
|
var delay$1 = testCafeCore__default.delay;
|
||
|
var selectController$1 = testCafeCore__default.selectController;
|
||
|
var selectElementUI$1 = testCafeUI.selectElement;
|
||
|
var FOCUS_DELAY = featureDetection$1.isTouchDevice ? 0 : 160;
|
||
|
var SelectChildClickAutomation = /** @class */ (function () {
|
||
|
function SelectChildClickAutomation(element, clickOptions) {
|
||
|
this.element = element;
|
||
|
this.modifiers = clickOptions.modifiers;
|
||
|
this.caretPos = clickOptions.caretPos;
|
||
|
this.offsetX = clickOptions.offsetX;
|
||
|
this.offsetY = clickOptions.offsetY;
|
||
|
this.speed = clickOptions.speed;
|
||
|
this.automationSettings = new AutomationSettings(clickOptions.speed);
|
||
|
this.parentSelect = domUtils$5.getSelectParent(this.element);
|
||
|
this.optionListExpanded = this.parentSelect ? selectController$1.isOptionListExpanded(this.parentSelect) : false;
|
||
|
this.childIndex = null;
|
||
|
this.clickCausesChange = false;
|
||
|
if (this.parentSelect) {
|
||
|
var isOption = domUtils$5.isOptionElement(this.element);
|
||
|
var selectedIndex = this.parentSelect.selectedIndex;
|
||
|
this.childIndex = isOption ? domUtils$5.getElementIndexInParent(this.parentSelect, this.element) :
|
||
|
domUtils$5.getElementIndexInParent(this.parentSelect, this.element);
|
||
|
var parent_1 = nativeMethods$9.nodeParentNodeGetter.call(this.element);
|
||
|
var parentOptGroup = domUtils$5.isOptionGroupElement(parent_1) ? parent_1 : null;
|
||
|
var isDisabled = this.element.disabled || parentOptGroup && parentOptGroup.disabled;
|
||
|
this.clickCausesChange = isOption && !isDisabled && this.childIndex !== selectedIndex;
|
||
|
}
|
||
|
this.eventsArgs = {
|
||
|
options: this.modifiers,
|
||
|
element: this.element,
|
||
|
};
|
||
|
}
|
||
|
SelectChildClickAutomation.prototype._calculateEventArguments = function () {
|
||
|
var childElement = this.optionListExpanded ? selectController$1.getEmulatedChildElement(this.element) : this.element;
|
||
|
var parentSelectSize = styleUtils$4.getSelectElementSize(this.parentSelect) > 1;
|
||
|
return {
|
||
|
options: this.modifiers,
|
||
|
element: browserUtils$6.isIE && parentSelectSize ? this.parentSelect : childElement,
|
||
|
};
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype._getMoveArguments = function () {
|
||
|
var element = null;
|
||
|
var offsetX = null;
|
||
|
var offsetY = null;
|
||
|
if (this.optionListExpanded) {
|
||
|
element = selectController$1.getEmulatedChildElement(this.element);
|
||
|
var moveActionOffsets = getDefaultAutomationOffsets(element);
|
||
|
offsetX = moveActionOffsets.offsetX;
|
||
|
offsetY = moveActionOffsets.offsetY;
|
||
|
}
|
||
|
else {
|
||
|
element = document.documentElement;
|
||
|
var elementCenter = selectElementUI$1.getSelectChildCenter(this.element);
|
||
|
offsetX = elementCenter.x;
|
||
|
offsetY = elementCenter.y;
|
||
|
}
|
||
|
return { element: element, offsetX: offsetX, offsetY: offsetY, speed: this.speed };
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype._move = function (_a) {
|
||
|
var _this = this;
|
||
|
var element = _a.element, offsetX = _a.offsetX, offsetY = _a.offsetY, speed = _a.speed;
|
||
|
var moveOptions = new MoveOptions({
|
||
|
offsetX: offsetX,
|
||
|
offsetY: offsetY,
|
||
|
speed: speed,
|
||
|
modifiers: this.modifiers,
|
||
|
}, false);
|
||
|
return MoveAutomation.create(element, moveOptions, window, cursor)
|
||
|
.then(function (moveAutomation) {
|
||
|
return moveAutomation.run();
|
||
|
})
|
||
|
.then(function () { return delay$1(_this.automationSettings.mouseActionStepDelay); });
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype._mousedown = function () {
|
||
|
var _this = this;
|
||
|
if (browserUtils$6.isFirefox) {
|
||
|
eventSimulator$6.mousedown(this.eventsArgs.element, this.eventsArgs.options);
|
||
|
if (this.clickCausesChange)
|
||
|
this.parentSelect.selectedIndex = this.childIndex;
|
||
|
return this._focus();
|
||
|
}
|
||
|
if (browserUtils$6.isIE) {
|
||
|
eventSimulator$6.mousedown(this.eventsArgs.element, this.eventsArgs.options);
|
||
|
return this._focus();
|
||
|
}
|
||
|
// NOTE: In Chrome, document.activeElement is 'select' after mousedown. But we need to
|
||
|
// raise blur and change the event for a previously active element during focus raising.
|
||
|
// That's why we should change the event order and raise focus before mousedown.
|
||
|
return this
|
||
|
._focus()
|
||
|
.then(function () { return delay$1(FOCUS_DELAY); })
|
||
|
.then(function () {
|
||
|
eventSimulator$6.mousedown(_this.eventsArgs.element, _this.eventsArgs.options);
|
||
|
if (_this.clickCausesChange)
|
||
|
_this.parentSelect.selectedIndex = _this.childIndex;
|
||
|
});
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype._focus = function () {
|
||
|
var _this = this;
|
||
|
return new Promise$6(function (resolve) {
|
||
|
focusBlurSandbox$1.focus(_this.parentSelect, resolve, false, true);
|
||
|
});
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype._mouseup = function () {
|
||
|
var elementForMouseupEvent = browserUtils$6.isIE ? this.parentSelect : this.eventsArgs.element;
|
||
|
eventSimulator$6.mouseup(elementForMouseupEvent, this.eventsArgs.options);
|
||
|
if (browserUtils$6.isIE && this.clickCausesChange)
|
||
|
this.parentSelect.selectedIndex = this.childIndex;
|
||
|
var simulateInputEventOnValueChange = browserUtils$6.isFirefox || browserUtils$6.isSafari ||
|
||
|
browserUtils$6.isChrome && browserUtils$6.version >= 53;
|
||
|
var simulateChangeEventOnValueChange = simulateInputEventOnValueChange || browserUtils$6.isIE;
|
||
|
if (simulateInputEventOnValueChange && this.clickCausesChange)
|
||
|
eventSimulator$6.input(this.parentSelect);
|
||
|
if (simulateChangeEventOnValueChange && this.clickCausesChange)
|
||
|
eventSimulator$6.change(this.parentSelect);
|
||
|
return Promise$6.resolve();
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype._click = function () {
|
||
|
eventSimulator$6.click(this.eventsArgs.element, this.eventsArgs.options);
|
||
|
};
|
||
|
SelectChildClickAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
if (!this.parentSelect) {
|
||
|
eventSimulator$6.click(this.eventsArgs.element, this.eventsArgs.options);
|
||
|
return Promise$6.resolve();
|
||
|
}
|
||
|
if (!this.optionListExpanded)
|
||
|
selectElementUI$1.scrollOptionListByChild(this.element);
|
||
|
var moveArguments = this._getMoveArguments();
|
||
|
this.eventsArgs = this._calculateEventArguments();
|
||
|
if (styleUtils$4.getSelectElementSize(this.parentSelect) <= 1) {
|
||
|
return this
|
||
|
._move(moveArguments)
|
||
|
.then(function () { return _this._click(); });
|
||
|
}
|
||
|
return this
|
||
|
._move(moveArguments)
|
||
|
.then(function () { return _this._mousedown(); })
|
||
|
.then(function () { return _this._mouseup(); })
|
||
|
.then(function () { return _this._click(); });
|
||
|
};
|
||
|
return SelectChildClickAutomation;
|
||
|
}());
|
||
|
|
||
|
var featureDetection$2 = hammerhead__default.utils.featureDetection;
|
||
|
var browserUtils$7 = hammerhead__default.utils.browser;
|
||
|
var eventSimulator$7 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var eventUtils$2 = testCafeCore__default.eventUtils;
|
||
|
var delay$2 = testCafeCore__default.delay;
|
||
|
var FIRST_CLICK_DELAY = featureDetection$2.isTouchDevice ? 0 : 160;
|
||
|
var DblClickAutomation = /** @class */ (function (_super) {
|
||
|
__extends(DblClickAutomation, _super);
|
||
|
function DblClickAutomation(element, clickOptions) {
|
||
|
var _this = _super.call(this, element, clickOptions, window, cursor) || this;
|
||
|
_this.modifiers = clickOptions.modifiers;
|
||
|
_this.caretPos = clickOptions.caretPos;
|
||
|
_this.speed = clickOptions.speed;
|
||
|
_this.automationSettings = new AutomationSettings(_this.speed);
|
||
|
_this.offsetX = clickOptions.offsetX;
|
||
|
_this.offsetY = clickOptions.offsetY;
|
||
|
_this.eventArgs = null;
|
||
|
_this.eventState = {
|
||
|
dblClickElement: null,
|
||
|
};
|
||
|
return _this;
|
||
|
}
|
||
|
DblClickAutomation.prototype._firstClick = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
// NOTE: we should always perform click with the highest speed
|
||
|
var clickOptions = new ClickOptions(this.options);
|
||
|
clickOptions.speed = 1;
|
||
|
var clickAutomation = new ClickAutomation(this.element, clickOptions, window, cursor);
|
||
|
clickAutomation.on(clickAutomation.TARGET_ELEMENT_FOUND_EVENT, function (e) { return _this.emit(_this.TARGET_ELEMENT_FOUND_EVENT, e); });
|
||
|
return clickAutomation.run(useStrictElementCheck)
|
||
|
.then(function (clickEventArgs) {
|
||
|
return delay$2(FIRST_CLICK_DELAY).then(function () { return clickEventArgs; });
|
||
|
});
|
||
|
};
|
||
|
DblClickAutomation.prototype._secondClick = function (eventArgs) {
|
||
|
var _this = this;
|
||
|
//NOTE: we should not call focus after the second mousedown (except in IE) because of the native browser behavior
|
||
|
if (browserUtils$7.isIE)
|
||
|
eventUtils$2.bind(document, 'focus', eventUtils$2.preventDefault, true);
|
||
|
var clickOptions = new ClickOptions({
|
||
|
offsetX: eventArgs.screenPoint.x,
|
||
|
offsetY: eventArgs.screenPoint.y,
|
||
|
caretPos: this.caretPos,
|
||
|
modifiers: this.modifiers,
|
||
|
speed: 1,
|
||
|
});
|
||
|
var clickAutomation = new ClickAutomation(document.documentElement, clickOptions, window, cursor);
|
||
|
return clickAutomation.run()
|
||
|
.then(function (clickEventArgs) {
|
||
|
// NOTE: We should raise the `dblclick` event on an element that
|
||
|
// has been actually clicked during the second click automation.
|
||
|
_this.eventState.dblClickElement = clickAutomation.strategy.eventState.clickElement;
|
||
|
if (browserUtils$7.isIE)
|
||
|
eventUtils$2.unbind(document, 'focus', eventUtils$2.preventDefault, true);
|
||
|
return clickEventArgs;
|
||
|
});
|
||
|
};
|
||
|
DblClickAutomation.prototype._dblClick = function (eventArgs) {
|
||
|
if (this.eventState.dblClickElement)
|
||
|
eventSimulator$7.dblclick(this.eventState.dblClickElement, eventArgs.options);
|
||
|
};
|
||
|
DblClickAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
// NOTE: If the target element is out of viewport the firstClick sub-automation raises an error
|
||
|
return this
|
||
|
._firstClick(useStrictElementCheck)
|
||
|
.then(function (eventArgs) { return _this._secondClick(eventArgs); })
|
||
|
.then(function (eventArgs) { return _this._dblClick(eventArgs); });
|
||
|
};
|
||
|
return DblClickAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var DragAndDropState = /** @class */ (function () {
|
||
|
function DragAndDropState() {
|
||
|
this.enabled = false;
|
||
|
this.dropAllowed = false;
|
||
|
this.element = null;
|
||
|
this.dataTransfer = null;
|
||
|
this.dataStore = null;
|
||
|
}
|
||
|
return DragAndDropState;
|
||
|
}());
|
||
|
|
||
|
var nativeMethods$a = hammerhead__default.nativeMethods;
|
||
|
var featureDetection$3 = hammerhead__default.utils.featureDetection;
|
||
|
var htmlUtils$1 = hammerhead__default.utils.html;
|
||
|
var urlUtils = hammerhead__default.utils.url;
|
||
|
var DataTransfer = hammerhead__default.eventSandbox.DataTransfer;
|
||
|
var DragDataStore = hammerhead__default.eventSandbox.DragDataStore;
|
||
|
var eventUtils$3 = testCafeCore__default.eventUtils;
|
||
|
var domUtils$6 = testCafeCore__default.domUtils;
|
||
|
// Utils
|
||
|
function findDraggableElement(element) {
|
||
|
var parentNode = element;
|
||
|
while (parentNode) {
|
||
|
if (parentNode.draggable)
|
||
|
return parentNode;
|
||
|
parentNode = nativeMethods$a.nodeParentNodeGetter.call(parentNode);
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
var DragMoveAutomation = /** @class */ (function (_super) {
|
||
|
__extends(DragMoveAutomation, _super);
|
||
|
function DragMoveAutomation(element, offset, moveOptions, win, cursor) {
|
||
|
var _this = _super.call(this, element, offset, moveOptions, win, cursor) || this;
|
||
|
_this.dragElement = null;
|
||
|
_this.dragAndDropState = new DragAndDropState();
|
||
|
return _this;
|
||
|
}
|
||
|
DragMoveAutomation.create = function (el, moveOptions, win, cursor) {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var _a, element, offset;
|
||
|
return __generator(this, function (_b) {
|
||
|
switch (_b.label) {
|
||
|
case 0: return [4 /*yield*/, MoveAutomation.getTarget(el, win, new AxisValues(moveOptions.offsetX, moveOptions.offsetY))];
|
||
|
case 1:
|
||
|
_a = _b.sent(), element = _a.element, offset = _a.offset;
|
||
|
return [2 /*return*/, new DragMoveAutomation(element, offset, moveOptions, win, cursor)];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
DragMoveAutomation.prototype._getCursorSpeed = function () {
|
||
|
return this.automationSettings.draggingSpeed;
|
||
|
};
|
||
|
DragMoveAutomation.prototype._getEventSequenceOptions = function (currPosition) {
|
||
|
var _a = _super.prototype._getEventSequenceOptions.call(this, currPosition), eventOptions = _a.eventOptions, eventSequenceOptions = _a.eventSequenceOptions;
|
||
|
eventOptions.dataTransfer = this.dragAndDropState.dataTransfer;
|
||
|
eventOptions.buttons = eventUtils$3.BUTTONS_PARAMETER.leftButton;
|
||
|
eventSequenceOptions.holdLeftButton = true;
|
||
|
return { eventOptions: eventOptions, eventSequenceOptions: eventSequenceOptions };
|
||
|
};
|
||
|
DragMoveAutomation.prototype._getCorrectedTopElement = function (topElement) {
|
||
|
return this.touchMode ? this.dragElement : topElement;
|
||
|
};
|
||
|
DragMoveAutomation.prototype._runEventSequence = function (currentElement, _a) {
|
||
|
var eventOptions = _a.eventOptions, eventSequenceOptions = _a.eventSequenceOptions;
|
||
|
var eventSequence = createEventSequence(this.dragAndDropState.enabled, this.firstMovingStepOccured, eventSequenceOptions);
|
||
|
var _b = eventSequence.run(currentElement, lastHoveredElementHolder.get(), eventOptions, this.dragElement, this.dragAndDropState.dataStore), dragAndDropMode = _b.dragAndDropMode, dropAllowed = _b.dropAllowed;
|
||
|
this.dragAndDropState.enabled = dragAndDropMode;
|
||
|
this.dragAndDropState.dropAllowed = dropAllowed;
|
||
|
};
|
||
|
DragMoveAutomation.prototype._needMoveCursorImmediately = function () {
|
||
|
return false;
|
||
|
};
|
||
|
DragMoveAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
return getElementFromPoint$2(this.cursor.getPosition())
|
||
|
.then(function (topElement) {
|
||
|
_this.dragElement = topElement;
|
||
|
var draggable = findDraggableElement(_this.dragElement);
|
||
|
// NOTE: we should skip simulating drag&drop's native behavior if the mousedown event was prevented (GH - 2529)
|
||
|
if (draggable && featureDetection$3.hasDataTransfer && !_this.skipDefaultDragBehavior) {
|
||
|
_this.dragAndDropState.enabled = true;
|
||
|
_this.dragElement = draggable;
|
||
|
_this.dragAndDropState.element = _this.dragElement;
|
||
|
_this.dragAndDropState.dataStore = new DragDataStore();
|
||
|
_this.dragAndDropState.dataTransfer = new DataTransfer(_this.dragAndDropState.dataStore);
|
||
|
var isLink = domUtils$6.isAnchorElement(_this.dragElement);
|
||
|
if (isLink || domUtils$6.isImgElement(_this.dragElement)) {
|
||
|
var srcAttr = isLink ? 'href' : 'src';
|
||
|
var parsedUrl = urlUtils.parseProxyUrl(_this.dragElement[srcAttr]);
|
||
|
var src = parsedUrl ? parsedUrl.destUrl : _this.dragElement[srcAttr];
|
||
|
var outerHTML = htmlUtils$1.cleanUpHtml(nativeMethods$a.elementOuterHTMLGetter.call(_this.dragElement));
|
||
|
_this.dragAndDropState.dataTransfer.setData('text/plain', src);
|
||
|
_this.dragAndDropState.dataTransfer.setData('text/uri-list', src);
|
||
|
_this.dragAndDropState.dataTransfer.setData('text/html', outerHTML);
|
||
|
}
|
||
|
}
|
||
|
return _super.prototype.run.call(_this)
|
||
|
.then(function () { return _this.dragAndDropState; });
|
||
|
});
|
||
|
};
|
||
|
return DragMoveAutomation;
|
||
|
}(MoveAutomation));
|
||
|
|
||
|
var MIN_MOVING_TIME = 25;
|
||
|
var Promise$7 = hammerhead__default.Promise;
|
||
|
var extend$1 = hammerhead__default.utils.extend;
|
||
|
var featureDetection$4 = hammerhead__default.utils.featureDetection;
|
||
|
var eventSimulator$8 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var focusBlurSandbox$2 = hammerhead__default.eventSandbox.focusBlur;
|
||
|
var DragAutomationBase = /** @class */ (function (_super) {
|
||
|
__extends(DragAutomationBase, _super);
|
||
|
function DragAutomationBase(element, mouseOptions) {
|
||
|
var _this = _super.call(this, element, mouseOptions, window, cursor) || this;
|
||
|
_this.modifiers = mouseOptions.modifiers;
|
||
|
_this.speed = mouseOptions.speed;
|
||
|
_this.offsetX = mouseOptions.offsetX;
|
||
|
_this.offsetY = mouseOptions.offsetY;
|
||
|
_this.endPoint = null;
|
||
|
_this.simulateDefaultBehavior = true;
|
||
|
_this.downEvent = featureDetection$4.isTouchDevice ? 'touchstart' : 'mousedown';
|
||
|
_this.upEvent = featureDetection$4.isTouchDevice ? 'touchend' : 'mouseup';
|
||
|
_this.dragAndDropState = null;
|
||
|
return _this;
|
||
|
}
|
||
|
DragAutomationBase.prototype._getEndPoint = function () {
|
||
|
throw new Error('Not implemented');
|
||
|
};
|
||
|
DragAutomationBase.prototype._mousedown = function (eventArgs) {
|
||
|
var _this = this;
|
||
|
return cursor
|
||
|
.leftButtonDown()
|
||
|
.then(function () {
|
||
|
_this.simulateDefaultBehavior = eventSimulator$8[_this.downEvent](eventArgs.element, eventArgs.options);
|
||
|
return _this._focus(eventArgs);
|
||
|
});
|
||
|
};
|
||
|
DragAutomationBase.prototype._focus = function (eventArgs) {
|
||
|
var _this = this;
|
||
|
return new Promise$7(function (resolve) {
|
||
|
// NOTE: If the target element is a child of a contentEditable element, we need to call focus for its parent
|
||
|
var elementForFocus = testCafeCore.domUtils.isContentEditableElement(_this.element) ?
|
||
|
testCafeCore.contentEditable.findContentEditableParent(_this.element) : eventArgs.element;
|
||
|
focusBlurSandbox$2.focus(elementForFocus, resolve, false, true);
|
||
|
});
|
||
|
};
|
||
|
DragAutomationBase.prototype._getDestination = function () {
|
||
|
throw new Error('Not implemented');
|
||
|
};
|
||
|
DragAutomationBase.prototype._drag = function () {
|
||
|
var _this = this;
|
||
|
return this._getDestination()
|
||
|
.then(function (_a) {
|
||
|
var element = _a.element, offsets = _a.offsets, endPoint = _a.endPoint;
|
||
|
_this.endPoint = endPoint;
|
||
|
var dragOptions = new MoveOptions({
|
||
|
offsetX: offsets.offsetX,
|
||
|
offsetY: offsets.offsetY,
|
||
|
modifiers: _this.modifiers,
|
||
|
speed: _this.speed,
|
||
|
minMovingTime: MIN_MOVING_TIME,
|
||
|
skipDefaultDragBehavior: _this.simulateDefaultBehavior === false,
|
||
|
}, false);
|
||
|
return DragMoveAutomation.create(element, dragOptions, window, cursor);
|
||
|
})
|
||
|
.then(function (moveAutomation) {
|
||
|
return moveAutomation.run();
|
||
|
})
|
||
|
.then(function (dragAndDropState) {
|
||
|
_this.dragAndDropState = dragAndDropState;
|
||
|
return testCafeCore.delay(_this.automationSettings.mouseActionStepDelay);
|
||
|
});
|
||
|
};
|
||
|
DragAutomationBase.prototype._mouseup = function () {
|
||
|
var _this = this;
|
||
|
return cursor
|
||
|
.buttonUp()
|
||
|
.then(function () {
|
||
|
var point = testCafeCore.positionUtils.offsetToClientCoords(_this.endPoint);
|
||
|
var topElement = null;
|
||
|
var options = extend$1({
|
||
|
clientX: point.x,
|
||
|
clientY: point.y,
|
||
|
}, _this.modifiers);
|
||
|
return getElementFromPoint$2(point)
|
||
|
.then(function (element) {
|
||
|
topElement = element;
|
||
|
if (!topElement)
|
||
|
return topElement;
|
||
|
if (_this.dragAndDropState.enabled) {
|
||
|
options.dataTransfer = _this.dragAndDropState.dataTransfer;
|
||
|
if (_this.dragAndDropState.dropAllowed)
|
||
|
eventSimulator$8.drop(topElement, options);
|
||
|
eventSimulator$8.dragend(_this.dragAndDropState.element, options);
|
||
|
_this.dragAndDropState.dataStore.setProtectedMode();
|
||
|
}
|
||
|
else
|
||
|
eventSimulator$8[_this.upEvent](topElement, options);
|
||
|
return getElementFromPoint$2(point);
|
||
|
})
|
||
|
.then(function (element) {
|
||
|
//B231323
|
||
|
if (topElement && element === topElement && !_this.dragAndDropState.enabled)
|
||
|
eventSimulator$8.click(topElement, options);
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
DragAutomationBase.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
var eventArgs = null;
|
||
|
return this
|
||
|
._ensureElement(useStrictElementCheck)
|
||
|
.then(function (_a) {
|
||
|
var element = _a.element, clientPoint = _a.clientPoint;
|
||
|
eventArgs = {
|
||
|
point: clientPoint,
|
||
|
element: element,
|
||
|
options: extend$1({
|
||
|
clientX: clientPoint.x,
|
||
|
clientY: clientPoint.y,
|
||
|
}, _this.modifiers),
|
||
|
};
|
||
|
// NOTE: we should raise start drag with 'mouseActionStepDelay' after we trigger
|
||
|
// mousedown event regardless of how long mousedown event handlers were executing
|
||
|
return Promise$7.all([testCafeCore.delay(_this.automationSettings.mouseActionStepDelay), _this._mousedown(eventArgs)]);
|
||
|
})
|
||
|
.then(function () { return _this._drag(); })
|
||
|
.then(function () { return _this._mouseup(); });
|
||
|
};
|
||
|
return DragAutomationBase;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var styleUtils$5 = testCafeCore__default.styleUtils;
|
||
|
var DragToOffsetAutomation = /** @class */ (function (_super) {
|
||
|
__extends(DragToOffsetAutomation, _super);
|
||
|
function DragToOffsetAutomation(element, offsetX, offsetY, mouseOptions) {
|
||
|
var _this = _super.call(this, element, mouseOptions) || this;
|
||
|
_this.dragOffsetX = offsetX;
|
||
|
_this.dragOffsetY = offsetY;
|
||
|
return _this;
|
||
|
}
|
||
|
DragToOffsetAutomation.prototype._getDestination = function () {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var startPoint, maxX, maxY, endPoint, element, offsets;
|
||
|
return __generator(this, function (_a) {
|
||
|
switch (_a.label) {
|
||
|
case 0: return [4 /*yield*/, getAutomationPoint(this.element, { x: this.offsetX, y: this.offsetY })];
|
||
|
case 1:
|
||
|
startPoint = _a.sent();
|
||
|
maxX = styleUtils$5.getWidth(document);
|
||
|
maxY = styleUtils$5.getHeight(document);
|
||
|
endPoint = {
|
||
|
x: startPoint.x + this.dragOffsetX,
|
||
|
y: startPoint.y + this.dragOffsetY,
|
||
|
};
|
||
|
endPoint = {
|
||
|
x: Math.min(Math.max(0, endPoint.x), maxX),
|
||
|
y: Math.min(Math.max(0, endPoint.y), maxY),
|
||
|
};
|
||
|
element = document.documentElement;
|
||
|
offsets = {
|
||
|
offsetX: endPoint.x,
|
||
|
offsetY: endPoint.y,
|
||
|
};
|
||
|
return [2 /*return*/, { element: element, offsets: offsets, endPoint: endPoint }];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
return DragToOffsetAutomation;
|
||
|
}(DragAutomationBase));
|
||
|
|
||
|
var positionUtils$3 = testCafeCore__default.positionUtils;
|
||
|
var DragToElementAutomation = /** @class */ (function (_super) {
|
||
|
__extends(DragToElementAutomation, _super);
|
||
|
function DragToElementAutomation(element, destinationElement, dragToElementOptions) {
|
||
|
var _this = _super.call(this, element, dragToElementOptions) || this;
|
||
|
_this.destinationElement = destinationElement;
|
||
|
_this.destinationOffsetX = dragToElementOptions.destinationOffsetX;
|
||
|
_this.destinationOffsetY = dragToElementOptions.destinationOffsetY;
|
||
|
return _this;
|
||
|
}
|
||
|
DragToElementAutomation.prototype._getDestination = function () {
|
||
|
return __awaiter(this, void 0, void 0, function () {
|
||
|
var element, elementRect, offsets, endPoint;
|
||
|
return __generator(this, function (_a) {
|
||
|
element = this.destinationElement;
|
||
|
elementRect = positionUtils$3.getElementRectangle(element);
|
||
|
offsets = getOffsetOptions(element, this.destinationOffsetX, this.destinationOffsetY);
|
||
|
endPoint = {
|
||
|
x: elementRect.left + offsets.offsetX,
|
||
|
y: elementRect.top + offsets.offsetY,
|
||
|
};
|
||
|
return [2 /*return*/, { element: element, offsets: offsets, endPoint: endPoint }];
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
return DragToElementAutomation;
|
||
|
}(DragAutomationBase));
|
||
|
|
||
|
var HoverAutomation = /** @class */ (function (_super) {
|
||
|
__extends(HoverAutomation, _super);
|
||
|
function HoverAutomation(element, hoverOptions) {
|
||
|
return _super.call(this, element, hoverOptions, window, cursor) || this;
|
||
|
}
|
||
|
HoverAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
return this._ensureElement(useStrictElementCheck, true);
|
||
|
};
|
||
|
return HoverAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var browserUtils$8 = hammerhead__default.utils.browser;
|
||
|
var eventSandbox = hammerhead__default.sandbox.event;
|
||
|
var eventSimulator$9 = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var listeners$4 = hammerhead__default.eventSandbox.listeners;
|
||
|
var nativeMethods$b = hammerhead__default.nativeMethods;
|
||
|
var domUtils$7 = testCafeCore__default.domUtils;
|
||
|
var contentEditable$1 = testCafeCore__default.contentEditable;
|
||
|
var textSelection$1 = testCafeCore__default.textSelection;
|
||
|
var WHITE_SPACES_RE = / /g;
|
||
|
function _getSelectionInElement(element) {
|
||
|
var currentSelection = textSelection$1.getSelectionByElement(element);
|
||
|
var isInverseSelection = textSelection$1.hasInverseSelectionContentEditable(element);
|
||
|
if (textSelection$1.hasElementContainsSelection(element))
|
||
|
return contentEditable$1.getSelection(element, currentSelection, isInverseSelection);
|
||
|
// NOTE: if we type text to an element that doesn't contain selection we
|
||
|
// assume the selectionStart and selectionEnd positions are null in this
|
||
|
// element. So we calculate the necessary start and end nodes and offsets
|
||
|
return {
|
||
|
startPos: contentEditable$1.calculateNodeAndOffsetByPosition(element, 0),
|
||
|
endPos: contentEditable$1.calculateNodeAndOffsetByPosition(element, 0),
|
||
|
};
|
||
|
}
|
||
|
function _updateSelectionAfterDeletionContent(element, selection) {
|
||
|
var startNode = selection.startPos.node;
|
||
|
var startParent = nativeMethods$b.nodeParentNodeGetter.call(startNode);
|
||
|
var hasStartParent = startParent && startNode.parentElement;
|
||
|
var browserRequiresSelectionUpdating = browserUtils$8.isChrome && browserUtils$8.version < 58 || browserUtils$8.isSafari;
|
||
|
if (browserRequiresSelectionUpdating || !hasStartParent || !domUtils$7.isElementContainsNode(element, startNode)) {
|
||
|
selection = _getSelectionInElement(element);
|
||
|
if (textSelection$1.hasInverseSelectionContentEditable(element)) {
|
||
|
selection = {
|
||
|
startPos: selection.endPos,
|
||
|
endPos: selection.startPos,
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
selection.endPos.offset = selection.startPos.offset;
|
||
|
return selection;
|
||
|
}
|
||
|
function _typeTextInElementNode(elementNode, text, offset) {
|
||
|
var nodeForTyping = document.createTextNode(text);
|
||
|
var textLength = text.length;
|
||
|
var selectPosition = { node: nodeForTyping, offset: textLength };
|
||
|
var parent = nativeMethods$b.nodeParentNodeGetter.call(elementNode);
|
||
|
if (domUtils$7.getTagName(elementNode) === 'br')
|
||
|
parent.insertBefore(nodeForTyping, elementNode);
|
||
|
else if (offset > 0) {
|
||
|
var childNodes = nativeMethods$b.nodeChildNodesGetter.call(elementNode);
|
||
|
elementNode.insertBefore(nodeForTyping, childNodes[offset]);
|
||
|
}
|
||
|
else
|
||
|
elementNode.appendChild(nodeForTyping);
|
||
|
textSelection$1.selectByNodesAndOffsets(selectPosition, selectPosition);
|
||
|
}
|
||
|
function _typeTextInChildTextNode(element, selection, text) {
|
||
|
var startNode = selection.startPos.node;
|
||
|
// NOTE: startNode could be moved or deleted on textInput event. Need ensure startNode.
|
||
|
if (!domUtils$7.isElementContainsNode(element, startNode)) {
|
||
|
selection = _excludeInvisibleSymbolsFromSelection(_getSelectionInElement(element));
|
||
|
startNode = selection.startPos.node;
|
||
|
}
|
||
|
var startOffset = selection.startPos.offset;
|
||
|
var endOffset = selection.endPos.offset;
|
||
|
var nodeValue = startNode.nodeValue;
|
||
|
var selectPosition = { node: startNode, offset: startOffset + text.length };
|
||
|
startNode.nodeValue = nodeValue.substring(0, startOffset) + text +
|
||
|
nodeValue.substring(endOffset, nodeValue.length);
|
||
|
textSelection$1.selectByNodesAndOffsets(selectPosition, selectPosition);
|
||
|
}
|
||
|
function _excludeInvisibleSymbolsFromSelection(selection) {
|
||
|
var startNode = selection.startPos.node;
|
||
|
var startOffset = selection.startPos.offset;
|
||
|
var endOffset = selection.endPos.offset;
|
||
|
var firstNonWhitespaceSymbolIndex = contentEditable$1.getFirstNonWhitespaceSymbolIndex(startNode.nodeValue);
|
||
|
var lastNonWhitespaceSymbolIndex = contentEditable$1.getLastNonWhitespaceSymbolIndex(startNode.nodeValue);
|
||
|
if (startOffset < firstNonWhitespaceSymbolIndex && startOffset !== 0) {
|
||
|
selection.startPos.offset = firstNonWhitespaceSymbolIndex;
|
||
|
selection.endPos.offset = endOffset + firstNonWhitespaceSymbolIndex - startOffset;
|
||
|
}
|
||
|
else if (endOffset > lastNonWhitespaceSymbolIndex && endOffset !== startNode.nodeValue.length) {
|
||
|
selection.startPos.offset = startNode.nodeValue.length;
|
||
|
selection.endPos.offset = endOffset + startNode.nodeValue.length - startOffset;
|
||
|
}
|
||
|
return selection;
|
||
|
}
|
||
|
// NOTE: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event
|
||
|
// The `beforeInput` event is supported only in Chrome-based browsers and Safari
|
||
|
// The order of events differs in Chrome and Safari:
|
||
|
// In Chrome: `beforeinput` occurs before `textInput`
|
||
|
// In Safari: `beforeinput` occurs after `textInput`
|
||
|
function simulateBeforeInput(element, text, needSimulate) {
|
||
|
if (needSimulate)
|
||
|
return eventSimulator$9.beforeInput(element, text);
|
||
|
return true;
|
||
|
}
|
||
|
// NOTE: Typing can be prevented in Chrome/Edge but can not be prevented in IE11 or Firefox
|
||
|
// Firefox does not support TextInput event
|
||
|
// Safari supports the TextInput event but has a bug: e.data is added to the node value.
|
||
|
// So in Safari we need to call preventDefault in the last textInput handler but not prevent the Input event
|
||
|
function simulateTextInput(element, text) {
|
||
|
var forceInputInSafari;
|
||
|
function onSafariTextInput(e) {
|
||
|
e.preventDefault();
|
||
|
forceInputInSafari = true;
|
||
|
}
|
||
|
function onSafariPreventTextInput(e) {
|
||
|
if (e.type === 'textInput')
|
||
|
forceInputInSafari = false;
|
||
|
}
|
||
|
if (browserUtils$8.isSafari) {
|
||
|
listeners$4.addInternalEventBeforeListener(window, ['textInput'], onSafariTextInput);
|
||
|
eventSandbox.on(eventSandbox.EVENT_PREVENTED_EVENT, onSafariPreventTextInput);
|
||
|
}
|
||
|
var isInputEventRequired = browserUtils$8.isFirefox || eventSimulator$9.textInput(element, text) || forceInputInSafari;
|
||
|
if (browserUtils$8.isSafari) {
|
||
|
listeners$4.removeInternalEventBeforeListener(window, ['textInput'], onSafariTextInput);
|
||
|
eventSandbox.off(eventSandbox.EVENT_PREVENTED_EVENT, onSafariPreventTextInput);
|
||
|
}
|
||
|
return isInputEventRequired || browserUtils$8.isIE11;
|
||
|
}
|
||
|
function _typeTextToContentEditable(element, text) {
|
||
|
var currentSelection = _getSelectionInElement(element);
|
||
|
var startNode = currentSelection.startPos.node;
|
||
|
var endNode = currentSelection.endPos.node;
|
||
|
var needProcessInput = true;
|
||
|
var needRaiseInputEvent = true;
|
||
|
var textInputData = text;
|
||
|
text = text.replace(WHITE_SPACES_RE, String.fromCharCode(160));
|
||
|
// NOTE: some browsers raise the 'input' event after the element
|
||
|
// content is changed, but in others we should do it manually.
|
||
|
var onInput = function () {
|
||
|
needRaiseInputEvent = false;
|
||
|
};
|
||
|
// NOTE: IE11 raises the 'textinput' event many times after the element changed.
|
||
|
// The 'textinput' should be called only once
|
||
|
function onTextInput(event, dispatched, preventEvent) {
|
||
|
preventEvent();
|
||
|
}
|
||
|
// NOTE: IE11 does not raise input event when type to contenteditable
|
||
|
var beforeContentChanged = function () {
|
||
|
needProcessInput = simulateTextInput(element, textInputData);
|
||
|
needRaiseInputEvent = needProcessInput && !browserUtils$8.isIE11;
|
||
|
listeners$4.addInternalEventBeforeListener(window, ['input'], onInput);
|
||
|
listeners$4.addInternalEventBeforeListener(window, ['textinput'], onTextInput);
|
||
|
};
|
||
|
var afterContentChanged = function () {
|
||
|
nextTick()
|
||
|
.then(function () {
|
||
|
if (needRaiseInputEvent)
|
||
|
eventSimulator$9.input(element, text);
|
||
|
listeners$4.removeInternalEventBeforeListener(window, ['input'], onInput);
|
||
|
listeners$4.removeInternalEventBeforeListener(window, ['textinput'], onTextInput);
|
||
|
});
|
||
|
};
|
||
|
if (!startNode || !endNode || !domUtils$7.isContentEditableElement(startNode) ||
|
||
|
!domUtils$7.isContentEditableElement(endNode))
|
||
|
return;
|
||
|
if (!domUtils$7.isTheSameNode(startNode, endNode)) {
|
||
|
textSelection$1.deleteSelectionContents(element);
|
||
|
// NOTE: after deleting the selection contents we should refresh the stored startNode because
|
||
|
// contentEditable element's content could change and we can no longer find parent elements
|
||
|
// of the nodes. In MSEdge, 'parentElement' for the deleted element isn't undefined
|
||
|
currentSelection = _updateSelectionAfterDeletionContent(element, currentSelection);
|
||
|
startNode = currentSelection.startPos.node;
|
||
|
}
|
||
|
if (!startNode || !domUtils$7.isContentEditableElement(startNode) || !domUtils$7.isRenderedNode(startNode))
|
||
|
return;
|
||
|
if (!simulateBeforeInput(element, text, browserUtils$8.isChrome || browserUtils$8.isFirefox))
|
||
|
return;
|
||
|
beforeContentChanged();
|
||
|
if (needProcessInput)
|
||
|
needProcessInput = simulateBeforeInput(element, text, browserUtils$8.isSafari);
|
||
|
if (needProcessInput) {
|
||
|
// NOTE: we can type only to the text nodes; for nodes with the 'element-node' type, we use a special behavior
|
||
|
if (domUtils$7.isElementNode(startNode))
|
||
|
_typeTextInElementNode(startNode, text);
|
||
|
else
|
||
|
_typeTextInChildTextNode(element, _excludeInvisibleSymbolsFromSelection(currentSelection), text);
|
||
|
}
|
||
|
afterContentChanged();
|
||
|
}
|
||
|
function _typeTextToTextEditable(element, text) {
|
||
|
var elementValue = domUtils$7.getElementValue(element);
|
||
|
var textLength = text.length;
|
||
|
var startSelection = textSelection$1.getSelectionStart(element);
|
||
|
var endSelection = textSelection$1.getSelectionEnd(element);
|
||
|
var isInputTypeNumber = domUtils$7.isInputElement(element) && element.type === 'number';
|
||
|
if (!simulateBeforeInput(element, text, browserUtils$8.isChrome || browserUtils$8.isFirefox))
|
||
|
return;
|
||
|
var needProcessInput = simulateTextInput(element, text);
|
||
|
if (needProcessInput)
|
||
|
needProcessInput = simulateBeforeInput(element, text, browserUtils$8.isSafari);
|
||
|
if (!needProcessInput)
|
||
|
return;
|
||
|
// NOTE: the 'maxlength' attribute doesn't work in all browsers. IE still doesn't support input with the 'number' type
|
||
|
var elementMaxLength = !browserUtils$8.isIE && isInputTypeNumber ? null : parseInt(element.maxLength, 10);
|
||
|
if (elementMaxLength < 0)
|
||
|
elementMaxLength = browserUtils$8.isIE && browserUtils$8.version < 17 ? 0 : null;
|
||
|
var newElementValue = elementValue.substring(0, startSelection) + text + elementValue.substring(endSelection, elementValue.length);
|
||
|
if (elementMaxLength === null || isNaN(elementMaxLength) || elementMaxLength >= newElementValue.length) {
|
||
|
// NOTE: B254013
|
||
|
if (isInputTypeNumber && browserUtils$8.isIOS && elementValue[elementValue.length - 1] === '.') {
|
||
|
startSelection += 1;
|
||
|
endSelection += 1;
|
||
|
}
|
||
|
domUtils$7.setElementValue(element, newElementValue);
|
||
|
textSelection$1.select(element, startSelection + textLength, startSelection + textLength);
|
||
|
}
|
||
|
// NOTE: We should simulate the 'input' event after typing a char (B253410, T138385)
|
||
|
eventSimulator$9.input(element, text);
|
||
|
}
|
||
|
function _typeTextToNonTextEditable(element, text, caretPos) {
|
||
|
if (caretPos !== null) {
|
||
|
var elementValue = domUtils$7.getElementValue(element);
|
||
|
domUtils$7.setElementValue(element, elementValue.substr(0, caretPos) + text + elementValue.substr(caretPos + text.length));
|
||
|
}
|
||
|
else
|
||
|
domUtils$7.setElementValue(element, text);
|
||
|
eventSimulator$9.change(element);
|
||
|
eventSimulator$9.input(element, text);
|
||
|
}
|
||
|
function typeText (element, text, caretPos) {
|
||
|
if (domUtils$7.isContentEditableElement(element))
|
||
|
_typeTextToContentEditable(element, text);
|
||
|
if (!domUtils$7.isElementReadOnly(element)) {
|
||
|
if (domUtils$7.isTextEditableElement(element))
|
||
|
_typeTextToTextEditable(element, text);
|
||
|
else if (domUtils$7.isInputElement(element))
|
||
|
_typeTextToNonTextEditable(element, text, caretPos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function isLetterKey (key) {
|
||
|
return key.length === 1 && (key >= 'a' && key <= 'z' || key >= 'A' && key <= 'Z');
|
||
|
}
|
||
|
|
||
|
var nativeMethods$c = hammerhead__default.nativeMethods;
|
||
|
var browserUtils$9 = hammerhead__default.utils.browser;
|
||
|
var focusBlurSandbox$3 = hammerhead__default.eventSandbox.focusBlur;
|
||
|
var Promise$8 = hammerhead__default.Promise;
|
||
|
var isRadioButtonElement$1 = testCafeCore.domUtils.isRadioButtonElement, getActiveElement$1 = testCafeCore.domUtils.getActiveElement, getTabIndexAttributeIntValue = testCafeCore.domUtils.getTabIndexAttributeIntValue;
|
||
|
function changeLetterCase(letter) {
|
||
|
var isLowCase = letter === letter.toLowerCase();
|
||
|
return isLowCase ? letter.toUpperCase() : letter.toLowerCase();
|
||
|
}
|
||
|
function getActualKeysAndEventKeyProperties(keyArray) {
|
||
|
var eventKeyProperties = keyArray.slice();
|
||
|
//NOTE: check 'shift' modifier in keys
|
||
|
for (var i = 0; i < keyArray.length; i++) {
|
||
|
var key = keyArray[i];
|
||
|
if (key.toLowerCase() === 'shift') {
|
||
|
var nextKey = keyArray[i + 1];
|
||
|
if (!nextKey)
|
||
|
continue;
|
||
|
if (testCafeCore.KEY_MAPS.shiftMap[nextKey])
|
||
|
keyArray[i + 1] = testCafeCore.KEY_MAPS.shiftMap[nextKey];
|
||
|
else if (testCafeCore.KEY_MAPS.reversedShiftMap[nextKey])
|
||
|
eventKeyProperties[i + 1] = testCafeCore.KEY_MAPS.reversedShiftMap[nextKey];
|
||
|
}
|
||
|
if (testCafeCore.KEY_MAPS.shiftMap[key] && (!keyArray[i - 1] || keyArray[i - 1].toLowerCase() !== 'shift')) {
|
||
|
keyArray[i] = testCafeCore.KEY_MAPS.shiftMap[key];
|
||
|
keyArray.splice(i, 0, 'shift');
|
||
|
eventKeyProperties.splice(i, 0, 'shift');
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
return { actualKeys: keyArray, eventKeyProperties: eventKeyProperties };
|
||
|
}
|
||
|
function getChar(key, shiftModified) {
|
||
|
if (key === 'space')
|
||
|
return ' ';
|
||
|
if (shiftModified) {
|
||
|
if (isLetterKey(key))
|
||
|
return changeLetterCase(key);
|
||
|
if (testCafeCore.KEY_MAPS.reversedShiftMap[key])
|
||
|
return testCafeCore.KEY_MAPS.reversedShiftMap[key];
|
||
|
}
|
||
|
return key;
|
||
|
}
|
||
|
function getDeepActiveElement(currentDocument) {
|
||
|
var doc = currentDocument || document;
|
||
|
var activeElement = getActiveElement$1(doc);
|
||
|
var activeElementInIframe = null;
|
||
|
if (activeElement && testCafeCore.domUtils.isIframeElement(activeElement) &&
|
||
|
nativeMethods$c.contentDocumentGetter.call(activeElement)) {
|
||
|
try {
|
||
|
activeElementInIframe = getDeepActiveElement(nativeMethods$c.contentDocumentGetter.call(activeElement));
|
||
|
}
|
||
|
catch (e) { // eslint-disable-line no-empty
|
||
|
}
|
||
|
}
|
||
|
return activeElementInIframe || activeElement;
|
||
|
}
|
||
|
function focusNextElement(element, reverse, skipRadioGroups) {
|
||
|
return new Promise$8(function (resolve) {
|
||
|
var nextElement = getNextFocusableElement(element, reverse, skipRadioGroups);
|
||
|
if (nextElement)
|
||
|
focusBlurSandbox$3.focus(nextElement, function () { return resolve(nextElement); });
|
||
|
else
|
||
|
resolve();
|
||
|
});
|
||
|
}
|
||
|
function getFocusableElementsFilter(sourceElement, skipRadioGroups) {
|
||
|
var filter = null;
|
||
|
if (skipRadioGroups) {
|
||
|
// NOTE: in all browsers except Mozilla and Opera focus sets on one radio set from group only.
|
||
|
// in Mozilla and Opera focus sets on any radio set.
|
||
|
if (sourceElement.name !== '' && !browserUtils$9.isFirefox)
|
||
|
filter = function (item) { return !item.name || item === sourceElement || item.name !== sourceElement.name; };
|
||
|
}
|
||
|
// NOTE arrow navigations works with radio buttons in all browsers only between radio buttons with same names
|
||
|
// Navigation between radio buttons without name just moves focus between radio buttons in Chrome
|
||
|
// In other browsers navigation between radio buttons without name does not work
|
||
|
else if (sourceElement.name !== '')
|
||
|
filter = function (item) { return isRadioButtonElement$1(item) && item.name === sourceElement.name; };
|
||
|
else if (browserUtils$9.isChrome)
|
||
|
filter = function (item) { return isRadioButtonElement$1(item) && !item.name; };
|
||
|
return filter;
|
||
|
}
|
||
|
function filterFocusableElements(elements, sourceElement, skipRadioGroups) {
|
||
|
if (!isRadioButtonElement$1(sourceElement))
|
||
|
return elements;
|
||
|
if (!skipRadioGroups && !sourceElement.name && !browserUtils$9.isChrome)
|
||
|
return [sourceElement];
|
||
|
var filterFn = getFocusableElementsFilter(sourceElement, skipRadioGroups);
|
||
|
if (filterFn)
|
||
|
elements = testCafeCore.arrayUtils.filter(elements, filterFn);
|
||
|
return elements;
|
||
|
}
|
||
|
function correctFocusableElement(elements, element, skipRadioGroups) {
|
||
|
var isNotCheckedRadioButtonElement = isRadioButtonElement$1(element) && element.name && !element.checked;
|
||
|
var checkedRadioButtonElementWithSameName = null;
|
||
|
if (skipRadioGroups && isNotCheckedRadioButtonElement) {
|
||
|
checkedRadioButtonElementWithSameName = testCafeCore.arrayUtils.find(elements, function (el) {
|
||
|
return isRadioButtonElement$1(el) && el.name === element.name && el.checked;
|
||
|
});
|
||
|
}
|
||
|
return checkedRadioButtonElementWithSameName || element;
|
||
|
}
|
||
|
function activeElementHasNegativeTabIndex(doc) {
|
||
|
var activeElement = nativeMethods$c.documentActiveElementGetter.call(doc);
|
||
|
var activeElementTabIndex = activeElement && getTabIndexAttributeIntValue(activeElement);
|
||
|
return activeElement && activeElementTabIndex < 0;
|
||
|
}
|
||
|
function getNextFocusableElement(element, reverse, skipRadioGroups) {
|
||
|
var offset = reverse ? -1 : 1;
|
||
|
var doc = testCafeCore.domUtils.getTopSameDomainWindow(window).document;
|
||
|
var sort = !activeElementHasNegativeTabIndex(doc);
|
||
|
var allFocusable = testCafeCore.domUtils.getFocusableElements(doc, sort);
|
||
|
allFocusable = filterFocusableElements(allFocusable, element, skipRadioGroups);
|
||
|
var isRadioInput = isRadioButtonElement$1(element);
|
||
|
var currentIndex = testCafeCore.arrayUtils.indexOf(allFocusable, element);
|
||
|
var isLastElementFocused = reverse ? currentIndex === 0 : currentIndex === allFocusable.length - 1;
|
||
|
if (isLastElementFocused) {
|
||
|
if (!reverse && element.tabIndex < 0)
|
||
|
return testCafeCore.arrayUtils.find(allFocusable, function (el) { return el.tabIndex === 0; });
|
||
|
return skipRadioGroups || !isRadioInput ? document.body : allFocusable[allFocusable.length - 1 - currentIndex];
|
||
|
}
|
||
|
if (reverse && currentIndex === -1)
|
||
|
return allFocusable[allFocusable.length - 1];
|
||
|
return correctFocusableElement(allFocusable, allFocusable[currentIndex + offset], skipRadioGroups);
|
||
|
}
|
||
|
|
||
|
function getKeyCode (char) {
|
||
|
if (isLetterKey(char))
|
||
|
return char.toUpperCase().charCodeAt(0);
|
||
|
var res = testCafeCore.KEY_MAPS.shiftMap[char] ? testCafeCore.KEY_MAPS.shiftMap[char].charCodeAt(0) : char.charCodeAt(0);
|
||
|
return testCafeCore.KEY_MAPS.symbolCharCodeToKeyCode[res] || res;
|
||
|
}
|
||
|
|
||
|
var KEY_IDENTIFIER_MAPS = {
|
||
|
SPECIAL_KEYS: {
|
||
|
capslock: 'CapsLock',
|
||
|
delete: 'U+007F',
|
||
|
end: 'End',
|
||
|
enter: 'Enter',
|
||
|
esc: 'U+001B',
|
||
|
home: 'Home',
|
||
|
ins: 'Insert',
|
||
|
pagedown: 'PageDown',
|
||
|
pageup: 'PageUp',
|
||
|
space: 'U+0020',
|
||
|
tab: 'Tab',
|
||
|
alt: 'Alt',
|
||
|
ctrl: 'Control',
|
||
|
meta: 'Meta',
|
||
|
shift: 'Shift',
|
||
|
},
|
||
|
LETTERS: {
|
||
|
a: 'U+0041',
|
||
|
b: 'U+0042',
|
||
|
c: 'U+0043',
|
||
|
d: 'U+0044',
|
||
|
e: 'U+0045',
|
||
|
f: 'U+0046',
|
||
|
g: 'U+0047',
|
||
|
h: 'U+0048',
|
||
|
i: 'U+0049',
|
||
|
j: 'U+004A',
|
||
|
k: 'U+004B',
|
||
|
l: 'U+004C',
|
||
|
m: 'U+004D',
|
||
|
n: 'U+004E',
|
||
|
o: 'U+004F',
|
||
|
p: 'U+0050',
|
||
|
q: 'U+0051',
|
||
|
r: 'U+0052',
|
||
|
s: 'U+0053',
|
||
|
t: 'U+0054',
|
||
|
u: 'U+0055',
|
||
|
v: 'U+0056',
|
||
|
w: 'U+0057',
|
||
|
x: 'U+0058',
|
||
|
y: 'U+0059',
|
||
|
z: 'U+005A',
|
||
|
},
|
||
|
SYMBOLS: {
|
||
|
'0': 'U+0030',
|
||
|
'1': 'U+0031',
|
||
|
'2': 'U+0032',
|
||
|
'3': 'U+0033',
|
||
|
'4': 'U+0034',
|
||
|
'5': 'U+0035',
|
||
|
'6': 'U+0036',
|
||
|
'7': 'U+0037',
|
||
|
'8': 'U+0038',
|
||
|
'9': 'U+0039',
|
||
|
' ': 'U+0020',
|
||
|
'!': 'U+0021',
|
||
|
'@': 'U+0040',
|
||
|
'#': 'U+0023',
|
||
|
'$': 'U+0024',
|
||
|
'%': 'U+0025',
|
||
|
'^': 'U+005E',
|
||
|
'*': 'U+002A',
|
||
|
'(': 'U+0028',
|
||
|
')': 'U+0029',
|
||
|
'_': 'U+005F',
|
||
|
'|': 'U+007C',
|
||
|
'\\': 'U+005C',
|
||
|
'/': 'U+002F',
|
||
|
'?': 'U+003F',
|
||
|
'.': 'U+002E',
|
||
|
',': 'U+002C',
|
||
|
'<': 'U+003C',
|
||
|
'>': 'U+003E',
|
||
|
'[': 'U+005B',
|
||
|
']': 'U+005D',
|
||
|
'{': 'U+007B',
|
||
|
'}': 'U+007D',
|
||
|
'§': 'U+00A7',
|
||
|
'±': 'U+00B1',
|
||
|
'\'': 'U+0027',
|
||
|
'"': 'U+0022',
|
||
|
':': 'U+003A',
|
||
|
';': 'U+003B',
|
||
|
'`': 'U+0060',
|
||
|
'~': 'U+007E',
|
||
|
},
|
||
|
};
|
||
|
|
||
|
function getKeyIdentifier(char) {
|
||
|
if (isLetterKey(char))
|
||
|
return KEY_IDENTIFIER_MAPS.LETTERS[char.toLowerCase()];
|
||
|
return KEY_IDENTIFIER_MAPS.SYMBOLS[char] || KEY_IDENTIFIER_MAPS.SPECIAL_KEYS[char] || char;
|
||
|
}
|
||
|
|
||
|
function getKeyProperties(isKeyPressEvent, key, keyIdentifier) {
|
||
|
var properties = {};
|
||
|
if ('keyIdentifier' in KeyboardEvent.prototype)
|
||
|
properties.keyIdentifier = isKeyPressEvent ? '' : keyIdentifier;
|
||
|
if ('key' in KeyboardEvent.prototype)
|
||
|
properties.key = key;
|
||
|
return properties;
|
||
|
}
|
||
|
|
||
|
var browserUtils$a = hammerhead__default.utils.browser;
|
||
|
var extend$2 = hammerhead__default.utils.extend;
|
||
|
var eventSimulator$a = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var KeyPressSimulator = /** @class */ (function () {
|
||
|
function KeyPressSimulator(key, eventKeyProperty) {
|
||
|
this.isLetter = isLetterKey(key);
|
||
|
this.isChar = key.length === 1 || key === 'space';
|
||
|
this.sanitizedKey = testCafeCore.getSanitizedKey(key);
|
||
|
this.modifierKeyCode = testCafeCore.KEY_MAPS.modifiers[this.sanitizedKey];
|
||
|
this.specialKeyCode = testCafeCore.KEY_MAPS.specialKeys[this.sanitizedKey];
|
||
|
this.keyCode = null;
|
||
|
this.keyIdentifierProperty = getKeyIdentifier(eventKeyProperty);
|
||
|
this.topSameDomainDocument = testCafeCore.domUtils.getTopSameDomainWindow(window).document;
|
||
|
this.keyProperty = testCafeCore.KEY_MAPS.keyProperty[eventKeyProperty] || eventKeyProperty;
|
||
|
if (this.isChar && key !== 'space')
|
||
|
this.keyCode = getKeyCode(this.sanitizedKey);
|
||
|
else if (this.modifierKeyCode)
|
||
|
this.keyCode = this.modifierKeyCode;
|
||
|
else if (this.specialKeyCode)
|
||
|
this.keyCode = this.specialKeyCode;
|
||
|
this.storedActiveElement = null;
|
||
|
}
|
||
|
KeyPressSimulator._isKeyActivatedInputElement = function (el) {
|
||
|
return testCafeCore.domUtils.isInputElement(el) && /button|submit|reset|radio|checkbox/.test(el.type);
|
||
|
};
|
||
|
KeyPressSimulator.prototype._type = function (element, char) {
|
||
|
var elementChanged = element !== this.storedActiveElement;
|
||
|
var shouldType = !elementChanged;
|
||
|
var elementForTyping = element;
|
||
|
var isActiveElementEditable = testCafeCore.domUtils.isEditableElement(element);
|
||
|
var isStoredElementEditable = testCafeCore.domUtils.isEditableElement(this.storedActiveElement);
|
||
|
// Unnecessary typing happens if an element was changed after the keydown/keypress event (T210448)
|
||
|
// In IE, this error may occur when we try to determine if the removed element is in an iframe
|
||
|
try {
|
||
|
if (elementChanged) {
|
||
|
var isActiveElementInIframe = testCafeCore.domUtils.isElementInIframe(element);
|
||
|
var isStoredElementInIframe = testCafeCore.domUtils.isElementInIframe(this.storedActiveElement);
|
||
|
var shouldTypeInWebKit = isActiveElementInIframe === isStoredElementInIframe || isStoredElementEditable;
|
||
|
shouldType = (!browserUtils$a.isFirefox || isStoredElementEditable) &&
|
||
|
(!browserUtils$a.isWebKit || shouldTypeInWebKit);
|
||
|
}
|
||
|
}
|
||
|
/*eslint-disable no-empty */
|
||
|
catch (err) {
|
||
|
}
|
||
|
/*eslint-disable no-empty */
|
||
|
if (shouldType) {
|
||
|
if (!browserUtils$a.isIE && elementChanged && isStoredElementEditable && isActiveElementEditable)
|
||
|
elementForTyping = this.storedActiveElement;
|
||
|
typeText(elementForTyping, char);
|
||
|
}
|
||
|
};
|
||
|
KeyPressSimulator.prototype._addKeyPropertyToEventOptions = function (eventOptions) {
|
||
|
extend$2(eventOptions, getKeyProperties(eventOptions.type === 'keypress', this.keyProperty, this.keyIdentifierProperty));
|
||
|
return eventOptions;
|
||
|
};
|
||
|
KeyPressSimulator.prototype.down = function (modifiersState) {
|
||
|
this.storedActiveElement = getDeepActiveElement(this.topSameDomainDocument);
|
||
|
if (this.modifierKeyCode)
|
||
|
modifiersState[this.sanitizedKey] = true;
|
||
|
if (modifiersState.shift && this.isLetter)
|
||
|
this.keyProperty = changeLetterCase(this.keyProperty);
|
||
|
var eventOptions = { keyCode: this.keyCode, type: 'keydown' };
|
||
|
this._addKeyPropertyToEventOptions(eventOptions);
|
||
|
return eventSimulator$a.keydown(this.storedActiveElement, extend$2(eventOptions, modifiersState));
|
||
|
};
|
||
|
KeyPressSimulator.prototype.press = function (modifiersState) {
|
||
|
if (!(this.isChar || this.specialKeyCode))
|
||
|
return true;
|
||
|
var activeElement = getDeepActiveElement(this.topSameDomainDocument);
|
||
|
var character = this.isChar ? getChar(this.sanitizedKey, modifiersState.shift) : null;
|
||
|
var charCode = this.specialKeyCode || character.charCodeAt(0);
|
||
|
var elementChanged = activeElement !== this.storedActiveElement;
|
||
|
if (browserUtils$a.isWebKit && elementChanged) {
|
||
|
var isActiveElementInIframe = testCafeCore.domUtils.isElementInIframe(activeElement);
|
||
|
var isStoredElementInIframe = testCafeCore.domUtils.isElementInIframe(this.storedActiveElement);
|
||
|
if (isActiveElementInIframe !== isStoredElementInIframe)
|
||
|
return true;
|
||
|
}
|
||
|
this.storedActiveElement = activeElement;
|
||
|
var eventOptions = { keyCode: charCode, charCode: charCode, type: 'keypress' };
|
||
|
this._addKeyPropertyToEventOptions(eventOptions);
|
||
|
var raiseDefault = browserUtils$a.isAndroid || eventSimulator$a.keypress(activeElement, extend$2(eventOptions, modifiersState));
|
||
|
if (!raiseDefault)
|
||
|
return raiseDefault;
|
||
|
activeElement = getDeepActiveElement(this.topSameDomainDocument);
|
||
|
if (character && !(modifiersState.ctrl || modifiersState.alt))
|
||
|
this._type(activeElement, character);
|
||
|
var isKeyActivatedInput = KeyPressSimulator._isKeyActivatedInputElement(activeElement);
|
||
|
var isButton = testCafeCore.domUtils.isButtonElement(activeElement);
|
||
|
var isSafariWithAutoRaisedClick = browserUtils$a.isSafari &&
|
||
|
browserUtils$a.compareVersions([browserUtils$a.webkitVersion, '603.1.30']) >= 0;
|
||
|
var raiseClickOnEnter = !isSafariWithAutoRaisedClick && (isKeyActivatedInput || isButton);
|
||
|
if (raiseClickOnEnter && this.sanitizedKey === 'enter')
|
||
|
activeElement.click();
|
||
|
return raiseDefault;
|
||
|
};
|
||
|
KeyPressSimulator.prototype.up = function (modifiersState) {
|
||
|
if (this.modifierKeyCode)
|
||
|
modifiersState[this.sanitizedKey] = false;
|
||
|
var eventOptions = { keyCode: this.keyCode, type: 'keyup' };
|
||
|
this._addKeyPropertyToEventOptions(eventOptions);
|
||
|
var raiseDefault = eventSimulator$a.keyup(getDeepActiveElement(this.topSameDomainDocument), extend$2(eventOptions, modifiersState));
|
||
|
var activeElement = getDeepActiveElement(this.topSameDomainDocument);
|
||
|
// NOTE: in some browsers we should emulate click on active input element while pressing "space" key
|
||
|
var emulateClick = !browserUtils$a.isFirefox && !browserUtils$a.isSafari &&
|
||
|
(!browserUtils$a.isChrome || browserUtils$a.version >= 53);
|
||
|
if (emulateClick && raiseDefault && this.sanitizedKey === 'space' &&
|
||
|
KeyPressSimulator._isKeyActivatedInputElement(activeElement))
|
||
|
activeElement.click();
|
||
|
return raiseDefault;
|
||
|
};
|
||
|
Object.defineProperty(KeyPressSimulator.prototype, "key", {
|
||
|
get: function () {
|
||
|
return this.sanitizedKey;
|
||
|
},
|
||
|
enumerable: false,
|
||
|
configurable: true
|
||
|
});
|
||
|
return KeyPressSimulator;
|
||
|
}());
|
||
|
|
||
|
var SHORTCUT_TYPE = {
|
||
|
ctrlA: 'ctrl+a',
|
||
|
backspace: 'backspace',
|
||
|
delete: 'delete',
|
||
|
left: 'left',
|
||
|
right: 'right',
|
||
|
up: 'up',
|
||
|
down: 'down',
|
||
|
shiftLeft: 'shift+left',
|
||
|
shiftRight: 'shift+right',
|
||
|
shiftUp: 'shift+up',
|
||
|
shiftDown: 'shift+down',
|
||
|
shiftHome: 'shift+home',
|
||
|
shiftEnd: 'shift+end',
|
||
|
home: 'home',
|
||
|
end: 'end',
|
||
|
enter: 'enter',
|
||
|
tab: 'tab',
|
||
|
shiftTab: 'shift+tab',
|
||
|
esc: 'esc',
|
||
|
};
|
||
|
|
||
|
var _a;
|
||
|
var Promise$9 = hammerhead__default.Promise;
|
||
|
var browserUtils$b = hammerhead__default.utils.browser;
|
||
|
var eventSimulator$b = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var elementEditingWatcher = hammerhead__default.eventSandbox.elementEditingWatcher;
|
||
|
var textSelection$2 = testCafeCore__default.textSelection;
|
||
|
var eventUtils$4 = testCafeCore__default.eventUtils;
|
||
|
var domUtils$8 = testCafeCore__default.domUtils;
|
||
|
var selectElement = testCafeUI.selectElement;
|
||
|
var currentTextarea = null;
|
||
|
var currentTextareaCursorIndent = null;
|
||
|
function onTextAreaBlur() {
|
||
|
currentTextarea = null;
|
||
|
currentTextareaCursorIndent = null;
|
||
|
eventUtils$4.unbind(this, 'blur', onTextAreaBlur, true);
|
||
|
}
|
||
|
function updateTextAreaIndent(element) {
|
||
|
if (domUtils$8.isTextAreaElement(element)) {
|
||
|
if (currentTextarea !== element) {
|
||
|
eventUtils$4.bind(element, 'blur', onTextAreaBlur, true);
|
||
|
currentTextarea = element;
|
||
|
}
|
||
|
currentTextareaCursorIndent = getLineIndentInTextarea(element);
|
||
|
}
|
||
|
}
|
||
|
function getLineIndentInTextarea(textarea) {
|
||
|
var inverseSelection = textSelection$2.hasInverseSelection(textarea);
|
||
|
var textareaValue = domUtils$8.getTextAreaValue(textarea);
|
||
|
var cursorPosition = inverseSelection ?
|
||
|
textSelection$2.getSelectionStart(textarea) :
|
||
|
textSelection$2.getSelectionEnd(textarea);
|
||
|
if (!textareaValue || !cursorPosition)
|
||
|
return 0;
|
||
|
return domUtils$8.getTextareaIndentInLine(textarea, cursorPosition);
|
||
|
}
|
||
|
function moveTextAreaCursorUp(element, withSelection) {
|
||
|
var textareaValue = domUtils$8.getTextAreaValue(element);
|
||
|
if (!textareaValue)
|
||
|
return;
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var hasInverseSelection = textSelection$2.hasInverseSelection(element);
|
||
|
var partBeforeCursor = textareaValue.substring(0, hasInverseSelection ? startPos : endPos);
|
||
|
var lastLineBreakIndex = partBeforeCursor.lastIndexOf('\n');
|
||
|
var partBeforeLastLineBreak = partBeforeCursor.substring(0, lastLineBreakIndex);
|
||
|
if (currentTextareaCursorIndent === null || currentTextarea !== element)
|
||
|
updateTextAreaIndent(element);
|
||
|
lastLineBreakIndex = partBeforeLastLineBreak.lastIndexOf('\n');
|
||
|
var newPosition = Math.min(lastLineBreakIndex + 1 + currentTextareaCursorIndent, partBeforeLastLineBreak.length);
|
||
|
moveTextAreaCursor(element, startPos, endPos, hasInverseSelection, newPosition, withSelection);
|
||
|
}
|
||
|
function moveTextAreaCursorDown(element, withSelection) {
|
||
|
var textareaValue = domUtils$8.getTextAreaValue(element);
|
||
|
if (!textareaValue)
|
||
|
return;
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var hasInverseSelection = textSelection$2.hasInverseSelection(element);
|
||
|
var cursorPosition = hasInverseSelection ? startPos : endPos;
|
||
|
var partAfterCursor = textareaValue.substring(cursorPosition);
|
||
|
var firstLineBreakIndex = partAfterCursor.indexOf('\n');
|
||
|
var nextLineStartIndex = firstLineBreakIndex === -1 ? partAfterCursor.length : firstLineBreakIndex + 1;
|
||
|
var partAfterNewIndent = partAfterCursor.substring(nextLineStartIndex);
|
||
|
var newPosition = cursorPosition + nextLineStartIndex;
|
||
|
firstLineBreakIndex = partAfterNewIndent.indexOf('\n');
|
||
|
var maxIndent = firstLineBreakIndex === -1 ? partAfterNewIndent.length : firstLineBreakIndex;
|
||
|
if (currentTextareaCursorIndent === null || currentTextarea !== element)
|
||
|
updateTextAreaIndent(element);
|
||
|
newPosition = Math.min(newPosition + currentTextareaCursorIndent, newPosition + maxIndent);
|
||
|
moveTextAreaCursor(element, startPos, endPos, hasInverseSelection, newPosition, withSelection);
|
||
|
}
|
||
|
function moveTextAreaCursor(element, startPos, endPos, hasInverseSelection, newPosition, withSelection) {
|
||
|
var newStart = null;
|
||
|
var newEnd = null;
|
||
|
if (withSelection) {
|
||
|
if (startPos === endPos) {
|
||
|
newStart = startPos;
|
||
|
newEnd = newPosition;
|
||
|
}
|
||
|
else if (!hasInverseSelection) {
|
||
|
newStart = startPos;
|
||
|
newEnd = newPosition;
|
||
|
}
|
||
|
else {
|
||
|
newStart = endPos;
|
||
|
newEnd = newPosition;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
newEnd = newStart = newPosition;
|
||
|
textSelection$2.select(element, newStart, newEnd);
|
||
|
}
|
||
|
function setElementValue(element, value, position) {
|
||
|
if (domUtils$8.isInputElement(element) && element.type === 'number') {
|
||
|
if (value.charAt(0) === '-' && value.charAt(1) === '.')
|
||
|
value = value.substring(1);
|
||
|
if (value.charAt(value.length - 1) === '.')
|
||
|
value = value.substring(0, value.length - 1);
|
||
|
}
|
||
|
domUtils$8.setElementValue(element, value);
|
||
|
textSelection$2.select(element, position, position);
|
||
|
eventSimulator$b.input(element);
|
||
|
}
|
||
|
function submitFormOnEnterPressInInput(form, inputElement) {
|
||
|
var buttons = form.querySelectorAll('input, button');
|
||
|
var submitButton = null;
|
||
|
var i = null;
|
||
|
for (i = 0; i < buttons.length; i++) {
|
||
|
if (!submitButton && buttons[i].type === 'submit' && !buttons[i].disabled) {
|
||
|
submitButton = buttons[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (submitButton)
|
||
|
eventSimulator$b.click(submitButton);
|
||
|
else if (domUtils$8.blocksImplicitSubmission(inputElement)) {
|
||
|
var formInputs = form.getElementsByTagName('input');
|
||
|
var textInputs = [];
|
||
|
for (i = 0; i < formInputs.length; i++) {
|
||
|
if (domUtils$8.blocksImplicitSubmission(formInputs[i]))
|
||
|
textInputs.push(formInputs[i]);
|
||
|
}
|
||
|
// NOTE: the form is submitted on enter press if there is only one input of the following types on it
|
||
|
// and this input is focused (http://www.w3.org/TR/html5/forms.html#implicit-submission)
|
||
|
if (textInputs.length === 1 && textInputs[0] === inputElement) {
|
||
|
var isInputValid = inputElement.validity.valid;
|
||
|
if (isInputValid && eventSimulator$b.submit(form))
|
||
|
form.submit();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//shortcuts
|
||
|
function selectAll(element) {
|
||
|
if (domUtils$8.isEditableElement(element))
|
||
|
textSelection$2.select(element);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function backspace(element) {
|
||
|
if (domUtils$8.isTextEditableElementAndEditingAllowed(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var value = domUtils$8.getElementValue(element).replace(/\r\n/g, '\n');
|
||
|
if (endPos === startPos) {
|
||
|
if (startPos > 0) {
|
||
|
setElementValue(element, value.substring(0, startPos - 1) +
|
||
|
value.substring(endPos, value.length), startPos - 1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
setElementValue(element, value.substring(0, startPos) + value.substring(endPos, value.length), startPos);
|
||
|
}
|
||
|
if (domUtils$8.isContentEditableElement(element))
|
||
|
textSelection$2.deleteSelectionContents(element);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function del(element) {
|
||
|
if (domUtils$8.isTextEditableElementAndEditingAllowed(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var value = domUtils$8.getElementValue(element).replace(/\r\n/g, '\n');
|
||
|
if (endPos === startPos) {
|
||
|
if (startPos < value.length) {
|
||
|
setElementValue(element, value.substring(0, startPos) +
|
||
|
value.substring(endPos + 1, value.length), startPos);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
setElementValue(element, value.substring(0, startPos) +
|
||
|
value.substring(endPos, value.length), startPos);
|
||
|
}
|
||
|
}
|
||
|
if (domUtils$8.isContentEditableElement(element))
|
||
|
textSelection$2.deleteSelectionContents(element);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function left(element) {
|
||
|
var startPosition = null;
|
||
|
var endPosition = null;
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.switchOptionsByKeys(element, 'left');
|
||
|
if (isRadioButtonNavigationRequired(element))
|
||
|
return focusAndCheckNextRadioButton(element, true);
|
||
|
if (domUtils$8.isTextEditableElement(element)) {
|
||
|
startPosition = textSelection$2.getSelectionStart(element) || 0;
|
||
|
endPosition = textSelection$2.getSelectionEnd(element);
|
||
|
var newPosition = startPosition === endPosition ? startPosition - 1 : startPosition;
|
||
|
textSelection$2.select(element, newPosition, newPosition);
|
||
|
updateTextAreaIndent(element);
|
||
|
}
|
||
|
if (domUtils$8.isContentEditableElement(element)) {
|
||
|
startPosition = textSelection$2.getSelectionStart(element);
|
||
|
endPosition = textSelection$2.getSelectionEnd(element);
|
||
|
// NOTE: we only remove selection
|
||
|
if (startPosition !== endPosition) {
|
||
|
var selection = textSelection$2.getSelectionByElement(element);
|
||
|
var inverseSelection = textSelection$2.hasInverseSelectionContentEditable(element);
|
||
|
var startNode = inverseSelection ? selection.focusNode : selection.anchorNode;
|
||
|
var startOffset = inverseSelection ? selection.focusOffset : selection.anchorOffset;
|
||
|
var startPos = { node: startNode, offset: startOffset };
|
||
|
textSelection$2.selectByNodesAndOffsets(startPos, startPos, true);
|
||
|
}
|
||
|
}
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function right(element) {
|
||
|
var startPosition = null;
|
||
|
var endPosition = null;
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.switchOptionsByKeys(element, 'right');
|
||
|
if (isRadioButtonNavigationRequired(element))
|
||
|
return focusAndCheckNextRadioButton(element, false);
|
||
|
if (domUtils$8.isTextEditableElement(element)) {
|
||
|
startPosition = textSelection$2.getSelectionStart(element);
|
||
|
endPosition = textSelection$2.getSelectionEnd(element);
|
||
|
var newPosition = startPosition === endPosition ? endPosition + 1 : endPosition;
|
||
|
if (startPosition === domUtils$8.getElementValue(element).length)
|
||
|
newPosition = startPosition;
|
||
|
textSelection$2.select(element, newPosition, newPosition);
|
||
|
updateTextAreaIndent(element);
|
||
|
}
|
||
|
if (domUtils$8.isContentEditableElement(element)) {
|
||
|
startPosition = textSelection$2.getSelectionStart(element);
|
||
|
endPosition = textSelection$2.getSelectionEnd(element);
|
||
|
//NOTE: we only remove selection
|
||
|
if (startPosition !== endPosition) {
|
||
|
var selection = textSelection$2.getSelectionByElement(element);
|
||
|
var inverseSelection = textSelection$2.hasInverseSelectionContentEditable(element);
|
||
|
var endNode = inverseSelection ? selection.anchorNode : selection.focusNode;
|
||
|
var endOffset = inverseSelection ? selection.anchorOffset : selection.focusOffset;
|
||
|
var startPos = { node: endNode, offset: endOffset };
|
||
|
textSelection$2.selectByNodesAndOffsets(startPos, startPos, true);
|
||
|
}
|
||
|
}
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function up(element) {
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.switchOptionsByKeys(element, 'up');
|
||
|
if (isRadioButtonNavigationRequired(element))
|
||
|
return focusAndCheckNextRadioButton(element, true);
|
||
|
if (browserUtils$b.isWebKit && domUtils$8.isInputElement(element))
|
||
|
return home(element);
|
||
|
if (domUtils$8.isTextAreaElement(element))
|
||
|
moveTextAreaCursorUp(element, false);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function down(element) {
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.switchOptionsByKeys(element, 'down');
|
||
|
if (isRadioButtonNavigationRequired(element))
|
||
|
return focusAndCheckNextRadioButton(element, false);
|
||
|
if (browserUtils$b.isWebKit && domUtils$8.isInputElement(element))
|
||
|
return end(element);
|
||
|
if (domUtils$8.isTextAreaElement(element))
|
||
|
moveTextAreaCursorDown(element, false);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function home(element, withSelection) {
|
||
|
if (domUtils$8.isTextEditableElement(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var inverseSelection = textSelection$2.hasInverseSelection(element);
|
||
|
var referencePosition = null;
|
||
|
var isSingleLineSelection = !domUtils$8.isTextAreaElement(element) ? true :
|
||
|
domUtils$8.getTextareaLineNumberByPosition(element, startPos) ===
|
||
|
domUtils$8.getTextareaLineNumberByPosition(element, endPos);
|
||
|
if (isSingleLineSelection)
|
||
|
referencePosition = inverseSelection ? endPos : startPos;
|
||
|
else
|
||
|
referencePosition = inverseSelection ? startPos : endPos;
|
||
|
var valueBeforeCursor = domUtils$8.getElementValue(element).substring(0, referencePosition);
|
||
|
var lastLineBreakIndex = valueBeforeCursor.lastIndexOf('\n');
|
||
|
var newPosition = lastLineBreakIndex === -1 ? 0 : lastLineBreakIndex + 1;
|
||
|
var newStartPos = null;
|
||
|
var newEndPos = null;
|
||
|
if (isSingleLineSelection) {
|
||
|
newStartPos = newPosition;
|
||
|
newEndPos = withSelection ? referencePosition : newPosition;
|
||
|
textSelection$2.select(element, newEndPos, newStartPos);
|
||
|
}
|
||
|
else if (!inverseSelection)
|
||
|
textSelection$2.select(element, startPos, newPosition);
|
||
|
else
|
||
|
textSelection$2.select(element, endPos, newPosition);
|
||
|
}
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function end(element, withSelection) {
|
||
|
if (domUtils$8.isTextEditableElement(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var inverseSelection = textSelection$2.hasInverseSelection(element);
|
||
|
var referencePosition = null;
|
||
|
var isSingleLineSelection = !domUtils$8.isTextAreaElement(element) ? true :
|
||
|
domUtils$8.getTextareaLineNumberByPosition(element, startPos) ===
|
||
|
domUtils$8.getTextareaLineNumberByPosition(element, endPos);
|
||
|
if (isSingleLineSelection)
|
||
|
referencePosition = inverseSelection ? endPos : startPos;
|
||
|
else
|
||
|
referencePosition = inverseSelection ? startPos : endPos;
|
||
|
var valueAsterCursor = domUtils$8.getElementValue(element).substring(referencePosition);
|
||
|
var firstLineBreakIndex = valueAsterCursor.indexOf('\n');
|
||
|
var newPosition = referencePosition;
|
||
|
var newStartPos = null;
|
||
|
var newEndPos = null;
|
||
|
newPosition += firstLineBreakIndex === -1 ? valueAsterCursor.length : firstLineBreakIndex;
|
||
|
if (isSingleLineSelection) {
|
||
|
newStartPos = withSelection ? referencePosition : newPosition;
|
||
|
newEndPos = newPosition;
|
||
|
textSelection$2.select(element, newStartPos, newEndPos);
|
||
|
}
|
||
|
else if (!inverseSelection)
|
||
|
textSelection$2.select(element, startPos, newPosition);
|
||
|
else
|
||
|
textSelection$2.select(element, endPos, newPosition);
|
||
|
}
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function esc(element) {
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.collapseOptionList();
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function shiftUp(element) {
|
||
|
if (browserUtils$b.isWebKit && domUtils$8.isInputElement(element))
|
||
|
return shiftHome(element);
|
||
|
if (domUtils$8.isTextAreaElement(element))
|
||
|
moveTextAreaCursorUp(element, true);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function shiftDown(element) {
|
||
|
if (browserUtils$b.isWebKit && domUtils$8.isInputElement(element))
|
||
|
return shiftEnd(element);
|
||
|
if (domUtils$8.isTextAreaElement(element))
|
||
|
moveTextAreaCursorDown(element, true);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function shiftLeft(element) {
|
||
|
if (domUtils$8.isTextEditableElement(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
if (startPos === endPos || textSelection$2.hasInverseSelection(element))
|
||
|
textSelection$2.select(element, endPos, Math.max(startPos - 1, 0));
|
||
|
else
|
||
|
textSelection$2.select(element, startPos, Math.max(endPos - 1, 0));
|
||
|
updateTextAreaIndent(element);
|
||
|
}
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function shiftRight(element) {
|
||
|
if (domUtils$8.isTextEditableElement(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var endPos = textSelection$2.getSelectionEnd(element);
|
||
|
var valueLength = domUtils$8.getElementValue(element).length;
|
||
|
if (startPos === endPos || !textSelection$2.hasInverseSelection(element))
|
||
|
textSelection$2.select(element, startPos, Math.min(endPos + 1, valueLength));
|
||
|
else
|
||
|
textSelection$2.select(element, endPos, Math.min(startPos + 1, valueLength));
|
||
|
updateTextAreaIndent(element);
|
||
|
}
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function shiftHome(element) {
|
||
|
return home(element, true);
|
||
|
}
|
||
|
function shiftEnd(element) {
|
||
|
return end(element, true);
|
||
|
}
|
||
|
function enter(element) {
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.collapseOptionList();
|
||
|
//submit form on enter pressed
|
||
|
if (domUtils$8.isInputElement(element)) {
|
||
|
if (!browserUtils$b.isIE)
|
||
|
elementEditingWatcher.processElementChanging(element);
|
||
|
var form = domUtils$8.getParents(element, 'form')[0];
|
||
|
// NOTE: if a user presses enter when a form input is focused and the form has
|
||
|
// a submit button, the browser sends the click event to the submit button
|
||
|
if (form)
|
||
|
submitFormOnEnterPressInInput(form, element);
|
||
|
}
|
||
|
else if (domUtils$8.isTextAreaElement(element)) {
|
||
|
var startPos = textSelection$2.getSelectionStart(element);
|
||
|
var value = domUtils$8.getTextAreaValue(element);
|
||
|
var valueBeforeCursor = value.substring(0, startPos);
|
||
|
var valueAfterCursor = value.substring(startPos);
|
||
|
var newPosition = startPos + 1;
|
||
|
setElementValue(element, valueBeforeCursor + String.fromCharCode(10) + valueAfterCursor, newPosition);
|
||
|
}
|
||
|
//S173120
|
||
|
else if (element.tagName && domUtils$8.isAnchorElement(element))
|
||
|
eventSimulator$b.click(element);
|
||
|
return Promise$9.resolve();
|
||
|
}
|
||
|
function isRadioButtonNavigationRequired(element) {
|
||
|
return domUtils$8.isRadioButtonElement(element);
|
||
|
}
|
||
|
function focusAndCheckNextRadioButton(element, reverse) {
|
||
|
return focusNextElementOnNavigationButton(element, reverse, false)
|
||
|
.then(function (focusedElement) {
|
||
|
if (focusedElement)
|
||
|
focusedElement.checked = true;
|
||
|
});
|
||
|
}
|
||
|
function focusNextElementOnNavigationButton(element, reverse, skipRadioGroups) {
|
||
|
if (skipRadioGroups === void 0) { skipRadioGroups = true; }
|
||
|
if (!element)
|
||
|
return Promise$9.resolve();
|
||
|
if (domUtils$8.isSelectElement(element))
|
||
|
selectElement.collapseOptionList();
|
||
|
return focusNextElement(element, reverse, skipRadioGroups)
|
||
|
.then(function (nextElement) {
|
||
|
if (nextElement && domUtils$8.isTextEditableInput(nextElement))
|
||
|
textSelection$2.select(nextElement);
|
||
|
return nextElement;
|
||
|
});
|
||
|
}
|
||
|
var supportedShortcutHandlers = (_a = {},
|
||
|
_a[SHORTCUT_TYPE.ctrlA] = selectAll,
|
||
|
_a[SHORTCUT_TYPE.backspace] = backspace,
|
||
|
_a[SHORTCUT_TYPE.delete] = del,
|
||
|
_a[SHORTCUT_TYPE.left] = left,
|
||
|
_a[SHORTCUT_TYPE.right] = right,
|
||
|
_a[SHORTCUT_TYPE.up] = up,
|
||
|
_a[SHORTCUT_TYPE.down] = down,
|
||
|
_a[SHORTCUT_TYPE.shiftLeft] = shiftLeft,
|
||
|
_a[SHORTCUT_TYPE.shiftRight] = shiftRight,
|
||
|
_a[SHORTCUT_TYPE.shiftUp] = shiftUp,
|
||
|
_a[SHORTCUT_TYPE.shiftDown] = shiftDown,
|
||
|
_a[SHORTCUT_TYPE.shiftHome] = shiftHome,
|
||
|
_a[SHORTCUT_TYPE.shiftEnd] = shiftEnd,
|
||
|
_a[SHORTCUT_TYPE.home] = home,
|
||
|
_a[SHORTCUT_TYPE.end] = end,
|
||
|
_a[SHORTCUT_TYPE.enter] = enter,
|
||
|
_a[SHORTCUT_TYPE.tab] = function (element) { return focusNextElementOnNavigationButton(element, false); },
|
||
|
_a[SHORTCUT_TYPE.shiftTab] = function (element) { return focusNextElementOnNavigationButton(element, true); },
|
||
|
_a[SHORTCUT_TYPE.esc] = esc,
|
||
|
_a);
|
||
|
|
||
|
var Promise$a = hammerhead__default.Promise;
|
||
|
var browserUtils$c = hammerhead__default.utils.browser;
|
||
|
var messageSandbox$3 = hammerhead__default.eventSandbox.message;
|
||
|
var nativeMethods$d = hammerhead__default.nativeMethods;
|
||
|
var PRESS_REQUEST_CMD = 'automation|press|request';
|
||
|
var PRESS_RESPONSE_CMD = 'automation|press|response';
|
||
|
// Setup cross-iframe interaction
|
||
|
messageSandbox$3.on(messageSandbox$3.SERVICE_MSG_RECEIVED_EVENT, function (e) {
|
||
|
if (e.message.cmd === PRESS_REQUEST_CMD) {
|
||
|
hammerhead__default.on(hammerhead__default.EVENTS.beforeUnload, function () { return messageSandbox$3.sendServiceMsg({ cmd: PRESS_RESPONSE_CMD }, e.source); });
|
||
|
var pressAutomation = new PressAutomation(e.message.keyCombinations, e.message.options);
|
||
|
pressAutomation
|
||
|
.run()
|
||
|
.then(function () { return messageSandbox$3.sendServiceMsg({ cmd: PRESS_RESPONSE_CMD }, e.source); });
|
||
|
}
|
||
|
});
|
||
|
var PressAutomation = /** @class */ (function () {
|
||
|
function PressAutomation(keyCombinations, options) {
|
||
|
this.keyCombinations = keyCombinations;
|
||
|
this.isSelectElement = false;
|
||
|
this.pressedKeyString = '';
|
||
|
this.modifiersState = null;
|
||
|
this.shortcutHandlers = null;
|
||
|
this.topSameDomainDocument = testCafeCore.domUtils.getTopSameDomainWindow(window).document;
|
||
|
this.automationSettings = new AutomationSettings(options.speed);
|
||
|
this.options = options;
|
||
|
}
|
||
|
PressAutomation._getKeyPressSimulators = function (keyCombination) {
|
||
|
var keysArray = testCafeCore.getKeyArray(keyCombination);
|
||
|
// NOTE: symbols may have the same keyCode, but their "event.key" will be different, so we
|
||
|
// need to get the "event.key" property for each key, and add the 'shift' key where needed.
|
||
|
var _a = getActualKeysAndEventKeyProperties(keysArray), actualKeys = _a.actualKeys, eventKeyProperties = _a.eventKeyProperties;
|
||
|
return testCafeCore.arrayUtils.map(actualKeys, function (key, index) { return new KeyPressSimulator(key, eventKeyProperties[index]); });
|
||
|
};
|
||
|
PressAutomation._getShortcuts = function (keyCombination) {
|
||
|
var keys = testCafeCore.getKeyArray(keyCombination.toLowerCase());
|
||
|
var shortcuts = [];
|
||
|
var curFullCombination = [];
|
||
|
var curCombination = [];
|
||
|
for (var i = 0; i < keys.length; i++) {
|
||
|
curFullCombination.push(keys[i]);
|
||
|
curCombination = curFullCombination.slice();
|
||
|
while (curCombination.length) {
|
||
|
var keyString = curCombination.join('+');
|
||
|
if (supportedShortcutHandlers[keyString]) {
|
||
|
shortcuts.push(keyString);
|
||
|
curFullCombination = curCombination = [];
|
||
|
}
|
||
|
else
|
||
|
curCombination.shift();
|
||
|
}
|
||
|
}
|
||
|
return shortcuts;
|
||
|
};
|
||
|
PressAutomation._getShortcutHandlers = function (keyCombination) {
|
||
|
var shortcuts = PressAutomation._getShortcuts(keyCombination.toLowerCase());
|
||
|
var shortcutHandlers = {};
|
||
|
var stringWithShortcut = '';
|
||
|
var shortcut = null;
|
||
|
var shortcutPosition = null;
|
||
|
var shortcutLength = null;
|
||
|
for (var i = 0; i < shortcuts.length; i++) {
|
||
|
shortcut = shortcuts[i];
|
||
|
shortcutPosition = keyCombination.indexOf(shortcut);
|
||
|
shortcutLength = shortcut.length;
|
||
|
stringWithShortcut += keyCombination.substring(0, shortcutPosition + shortcutLength);
|
||
|
shortcutHandlers[stringWithShortcut] = supportedShortcutHandlers[shortcut];
|
||
|
keyCombination = keyCombination.substring(shortcutPosition + shortcutLength);
|
||
|
}
|
||
|
return shortcutHandlers;
|
||
|
};
|
||
|
PressAutomation.prototype._down = function (keyPressSimulator) {
|
||
|
this.pressedKeyString += (this.pressedKeyString ? '+' : '') + keyPressSimulator.key;
|
||
|
var keyDownPrevented = !keyPressSimulator.down(this.modifiersState);
|
||
|
return Promise$a.resolve(keyDownPrevented);
|
||
|
};
|
||
|
PressAutomation.prototype._press = function (keyPressSimulator, keyEventPrevented) {
|
||
|
var _this = this;
|
||
|
// NOTE: preventing the 'keydown' and 'keypress' events for the select element does not
|
||
|
// affect the assignment of the new selectedIndex. So, we should execute a shortcut
|
||
|
// for the select element without taking into account that 'key' events are suppressed
|
||
|
if (keyEventPrevented && !this.isSelectElement)
|
||
|
return testCafeCore.delay(this.automationSettings.keyActionStepDelay);
|
||
|
var currentShortcutHandler = this.shortcutHandlers[this.pressedKeyString];
|
||
|
var keyPressPrevented = false;
|
||
|
// NOTE: B254435
|
||
|
if (!currentShortcutHandler || browserUtils$c.isFirefox || keyPressSimulator.key === 'enter')
|
||
|
keyPressPrevented = !keyPressSimulator.press(this.modifiersState);
|
||
|
if ((!keyPressPrevented || this.isSelectElement) && currentShortcutHandler) {
|
||
|
return currentShortcutHandler(getDeepActiveElement(this.topSameDomainDocument))
|
||
|
.then(function () { return testCafeCore.delay(_this.automationSettings.keyActionStepDelay); });
|
||
|
}
|
||
|
return testCafeCore.delay(this.automationSettings.keyActionStepDelay);
|
||
|
};
|
||
|
PressAutomation.prototype._up = function (keyPressSimulator) {
|
||
|
keyPressSimulator.up(this.modifiersState);
|
||
|
return testCafeCore.delay(this.automationSettings.keyActionStepDelay);
|
||
|
};
|
||
|
PressAutomation.prototype._runCombination = function (keyCombination) {
|
||
|
var _this = this;
|
||
|
this.modifiersState = { ctrl: false, alt: false, shift: false, meta: false };
|
||
|
this.isSelectElement = testCafeCore.domUtils.isSelectElement(getDeepActiveElement(this.topSameDomainDocument));
|
||
|
this.pressedKeyString = '';
|
||
|
this.shortcutHandlers = PressAutomation._getShortcutHandlers(keyCombination);
|
||
|
var keyPressSimulators = PressAutomation._getKeyPressSimulators(keyCombination);
|
||
|
return testCafeCore.promiseUtils.each(keyPressSimulators, function (keySimulator) {
|
||
|
return _this
|
||
|
._down(keySimulator)
|
||
|
.then(function (keyEventPrevented) { return _this._press(keySimulator, keyEventPrevented); });
|
||
|
})
|
||
|
.then(function () {
|
||
|
testCafeCore.arrayUtils.reverse(keyPressSimulators);
|
||
|
return testCafeCore.promiseUtils.each(keyPressSimulators, function (keySimulator) { return _this._up(keySimulator); });
|
||
|
});
|
||
|
};
|
||
|
PressAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
var activeElement = testCafeCore.domUtils.getActiveElement();
|
||
|
var activeElementIsIframe = testCafeCore.domUtils.isIframeElement(activeElement);
|
||
|
if (!isIframeWindow(window) && activeElementIsIframe && nativeMethods$d.contentWindowGetter.call(activeElement)) {
|
||
|
var msg = {
|
||
|
cmd: PRESS_REQUEST_CMD,
|
||
|
keyCombinations: this.keyCombinations,
|
||
|
options: this.options,
|
||
|
};
|
||
|
return testCafeCore.sendRequestToFrame(msg, PRESS_RESPONSE_CMD, nativeMethods$d.contentWindowGetter.call(activeElement));
|
||
|
}
|
||
|
return testCafeCore.promiseUtils.each(this.keyCombinations, function (combination) {
|
||
|
return _this
|
||
|
._runCombination(combination)
|
||
|
.then(function () { return testCafeCore.delay(_this.automationSettings.keyActionStepDelay); });
|
||
|
});
|
||
|
};
|
||
|
return PressAutomation;
|
||
|
}());
|
||
|
|
||
|
var Promise$b = hammerhead__default.Promise;
|
||
|
var extend$3 = hammerhead__default.utils.extend;
|
||
|
var browserUtils$d = hammerhead__default.utils.browser;
|
||
|
var eventSimulator$c = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var domUtils$9 = testCafeCore__default.domUtils, eventUtils$5 = testCafeCore__default.eventUtils, delay$3 = testCafeCore__default.delay;
|
||
|
var RClickAutomation = /** @class */ (function (_super) {
|
||
|
__extends(RClickAutomation, _super);
|
||
|
function RClickAutomation(element, clickOptions) {
|
||
|
var _this = _super.call(this, element, clickOptions, window, cursor) || this;
|
||
|
_this.modifiers = clickOptions.modifiers;
|
||
|
_this.caretPos = clickOptions.caretPos;
|
||
|
_this.eventState = {
|
||
|
simulateDefaultBehavior: true,
|
||
|
activeElementBeforeMouseDown: null,
|
||
|
};
|
||
|
return _this;
|
||
|
}
|
||
|
RClickAutomation.prototype._mousedown = function (eventArgs) {
|
||
|
var _this = this;
|
||
|
return cursor
|
||
|
.rightButtonDown()
|
||
|
.then(function () {
|
||
|
_this.eventState.activeElementBeforeMouseDown = domUtils$9.getActiveElement();
|
||
|
_this.eventState.simulateDefaultBehavior = eventSimulator$c.mousedown(eventArgs.element, eventArgs.options);
|
||
|
return _this._focus(eventArgs);
|
||
|
});
|
||
|
};
|
||
|
RClickAutomation.prototype._focus = function (eventArgs) {
|
||
|
if (this.simulateDefaultBehavior === false)
|
||
|
return nextTick();
|
||
|
// NOTE: If a target element is a contentEditable element, we need to call focusAndSetSelection directly for
|
||
|
// this element. Otherwise, if the element obtained by elementFromPoint is a child of the contentEditable
|
||
|
// element, a selection position may be calculated incorrectly (by using the caretPos option).
|
||
|
var elementForFocus = domUtils$9.isContentEditableElement(this.element) ? this.element : eventArgs.element;
|
||
|
// NOTE: IE doesn't perform focus if active element has been changed while executing mousedown
|
||
|
var simulateFocus = !browserUtils$d.isIE || this.eventState.activeElementBeforeMouseDown === domUtils$9.getActiveElement();
|
||
|
return focusAndSetSelection(elementForFocus, simulateFocus, this.caretPos)
|
||
|
.then(function () { return nextTick(); });
|
||
|
};
|
||
|
RClickAutomation.prototype._mouseup = function (eventArgs) {
|
||
|
var _this = this;
|
||
|
return cursor
|
||
|
.buttonUp()
|
||
|
.then(function () { return _this._getElementForEvent(eventArgs); })
|
||
|
.then(function (element) { return eventSimulator$c.mouseup(element, eventArgs.options); });
|
||
|
};
|
||
|
RClickAutomation.prototype._contextmenu = function (eventArgs) {
|
||
|
return this
|
||
|
._getElementForEvent(eventArgs)
|
||
|
.then(function (element) {
|
||
|
eventSimulator$c.contextmenu(element, eventArgs.options);
|
||
|
if (!domUtils$9.isElementFocusable(element))
|
||
|
focusByRelatedElement(element);
|
||
|
});
|
||
|
};
|
||
|
RClickAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
var eventArgs = null;
|
||
|
return this
|
||
|
._ensureElement(useStrictElementCheck)
|
||
|
.then(function (_a) {
|
||
|
var element = _a.element, clientPoint = _a.clientPoint, devicePoint = _a.devicePoint;
|
||
|
eventArgs = {
|
||
|
point: clientPoint,
|
||
|
element: element,
|
||
|
options: extend$3({
|
||
|
clientX: clientPoint.x,
|
||
|
clientY: clientPoint.y,
|
||
|
screenX: devicePoint.x,
|
||
|
screenY: devicePoint.y,
|
||
|
button: eventUtils$5.BUTTON.right,
|
||
|
}, _this.modifiers),
|
||
|
};
|
||
|
// NOTE: we should raise mouseup event with 'mouseActionStepDelay' after we trigger
|
||
|
// mousedown event regardless of how long mousedown event handlers were executing
|
||
|
return Promise$b.all([delay$3(_this.automationSettings.mouseActionStepDelay), _this._mousedown(eventArgs)]);
|
||
|
})
|
||
|
.then(function () { return _this._mouseup(eventArgs); })
|
||
|
.then(function () { return _this._contextmenu(eventArgs); });
|
||
|
};
|
||
|
return RClickAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var browserUtils$e = hammerhead__default.utils.browser;
|
||
|
var domUtils$a = testCafeCore__default.domUtils;
|
||
|
var positionUtils$4 = testCafeCore__default.positionUtils;
|
||
|
var styleUtils$6 = testCafeCore__default.styleUtils;
|
||
|
var contentEditable$2 = testCafeCore__default.contentEditable;
|
||
|
var arrayUtils$1 = testCafeCore__default.arrayUtils;
|
||
|
var MODIFIERS_LIST = ['direction', 'font-family', 'font-size', 'font-size-adjust', 'font-variant', 'font-weight', 'font-style', 'letter-spacing', 'line-height', 'text-align', 'text-indent', 'text-transform', 'word-wrap', 'word-spacing', 'padding-top', 'padding-left', 'padding-right', 'padding-bottom', 'margin-top', 'margin-left', 'margin-right', 'margin-bottom', 'border-top-width', 'border-left-width', 'border-right-width', 'border-bottom-width'];
|
||
|
function ensureRectangleInsideElement(element, rect) {
|
||
|
var elementBorders = styleUtils$6.getBordersWidth(element);
|
||
|
var elementOffset = positionUtils$4.getOffsetPosition(element);
|
||
|
// NOTE: strange behavior in Chrome - for some elements (e.g., for the 'font' element)
|
||
|
// scrollHeight is 0, so we use getBoundingClientRect
|
||
|
var elementHeight = element.scrollHeight || element.getBoundingClientRect().height;
|
||
|
var left = Math.ceil(rect.left);
|
||
|
var top = Math.ceil(rect.top);
|
||
|
var bottom = Math.floor(rect.bottom);
|
||
|
if (!domUtils$a.isTextAreaElement(element)) {
|
||
|
var clientOffset = positionUtils$4.offsetToClientCoords({
|
||
|
x: elementOffset.left,
|
||
|
y: elementOffset.top,
|
||
|
});
|
||
|
var minLeft = clientOffset.x + elementBorders.left + 1;
|
||
|
var minTop = clientOffset.y + elementBorders.top + 1;
|
||
|
var bottomBound = clientOffset.y + elementBorders.top + elementBorders.bottom + elementHeight;
|
||
|
var maxBottom = clientOffset.y + elementBorders.top + elementHeight - 1;
|
||
|
left = Math.ceil(left <= clientOffset.x ? minLeft : rect.left);
|
||
|
top = Math.ceil(top <= clientOffset.y ? minTop : rect.top);
|
||
|
bottom = Math.floor(bottom >= bottomBound ? maxBottom : rect.bottom);
|
||
|
}
|
||
|
return {
|
||
|
left: left,
|
||
|
top: top,
|
||
|
bottom: bottom,
|
||
|
};
|
||
|
}
|
||
|
function getAbsoluteRect(rect) {
|
||
|
var documentScroll = styleUtils$6.getElementScroll(document);
|
||
|
return {
|
||
|
left: rect.left + documentScroll.left,
|
||
|
top: rect.top + documentScroll.top,
|
||
|
bottom: rect.bottom + documentScroll.top,
|
||
|
};
|
||
|
}
|
||
|
function getSelectionRectangleInContentEditableElement(element, position) {
|
||
|
var range = domUtils$a.findDocument(element).createRange();
|
||
|
var selectionPosition = contentEditable$2.calculateNodeAndOffsetByPosition(element, position);
|
||
|
range.setStart(selectionPosition.node, Math.min(selectionPosition.offset, selectionPosition.node.length));
|
||
|
range.setEnd(selectionPosition.node, Math.min(selectionPosition.offset, selectionPosition.node.length));
|
||
|
return range.getClientRects()[0];
|
||
|
}
|
||
|
function getTextSelectionRectangle(element, position) {
|
||
|
var range = element.createTextRange();
|
||
|
range.collapse(true);
|
||
|
range.moveStart('character', position);
|
||
|
range.moveEnd('character', position);
|
||
|
range.collapse(true);
|
||
|
return range.getBoundingClientRect();
|
||
|
}
|
||
|
function getSelectionRectangle(element, position) {
|
||
|
var clientRectBeforeFakeDiv = element.getBoundingClientRect();
|
||
|
var fakeDiv = createFakeDiv(element);
|
||
|
var rect = null;
|
||
|
var clientRectAfterFakeDiv = element.getBoundingClientRect();
|
||
|
var topBoundDiff = clientRectAfterFakeDiv.top - clientRectBeforeFakeDiv.top;
|
||
|
var leftBoundDiff = clientRectAfterFakeDiv.left - clientRectBeforeFakeDiv.left;
|
||
|
var valueLength = domUtils$a.getElementValue(element).length;
|
||
|
try {
|
||
|
var range = document.createRange(); //B254723
|
||
|
range.setStart(hammerhead__default.nativeMethods.nodeFirstChildGetter.call(fakeDiv), Math.min(position, valueLength));
|
||
|
// NOTE: The range.getClientRects function returns wrong result if range length is 0 in Safari 11
|
||
|
range.setEnd(hammerhead__default.nativeMethods.nodeFirstChildGetter.call(fakeDiv), Math.min(position + 1, valueLength + 1));
|
||
|
if (domUtils$a.isTextAreaElement(element)) {
|
||
|
rect = range.getBoundingClientRect();
|
||
|
if (rect.width === 0 && rect.height === 0)
|
||
|
rect = range.getClientRects()[0];
|
||
|
}
|
||
|
else
|
||
|
rect = range.getClientRects()[0];
|
||
|
}
|
||
|
catch (err) {
|
||
|
rect = null;
|
||
|
}
|
||
|
domUtils$a.remove(fakeDiv);
|
||
|
if (!rect)
|
||
|
return null;
|
||
|
return {
|
||
|
width: rect.width,
|
||
|
height: rect.height,
|
||
|
top: rect.top - topBoundDiff,
|
||
|
bottom: rect.bottom - topBoundDiff,
|
||
|
left: rect.left - leftBoundDiff,
|
||
|
right: rect.right - leftBoundDiff,
|
||
|
};
|
||
|
}
|
||
|
function createFakeDiv(element) {
|
||
|
var body = document.body;
|
||
|
var elementOffset = positionUtils$4.getOffsetPosition(element);
|
||
|
var elementMargin = styleUtils$6.getElementMargin(element);
|
||
|
var elementTop = elementOffset.top - elementMargin.top;
|
||
|
var elementLeft = elementOffset.left - elementMargin.left;
|
||
|
var fakeDiv = document.createElement('div');
|
||
|
var fakeDivCssStyles = 'white-space:pre-wrap;border-style:solid;';
|
||
|
if (styleUtils$6.get(body, 'position') === 'absolute') {
|
||
|
var bodyMargin = styleUtils$6.getElementMargin(body);
|
||
|
var bodyLeft = styleUtils$6.get(body, 'left');
|
||
|
var bodyTop = styleUtils$6.get(body, 'top');
|
||
|
elementLeft -= bodyMargin.left + (parseInt(bodyLeft.replace('px', ''), 10) || 0);
|
||
|
elementTop -= bodyMargin.top + (parseInt(bodyTop.replace('px', ''), 10) || 0);
|
||
|
}
|
||
|
arrayUtils$1.forEach(MODIFIERS_LIST, function (modifier) {
|
||
|
fakeDivCssStyles += "".concat(modifier, ":").concat(styleUtils$6.get(element, modifier), ";");
|
||
|
});
|
||
|
styleUtils$6.set(fakeDiv, {
|
||
|
cssText: fakeDivCssStyles,
|
||
|
position: 'absolute',
|
||
|
left: elementLeft + 'px',
|
||
|
top: elementTop + 'px',
|
||
|
width: element.scrollWidth + 'px',
|
||
|
height: element.scrollHeight + 'px',
|
||
|
});
|
||
|
hammerhead__default.nativeMethods.nodeTextContentSetter.call(fakeDiv, domUtils$a.getElementValue(element) + ' ');
|
||
|
body.appendChild(fakeDiv);
|
||
|
return fakeDiv;
|
||
|
}
|
||
|
function getPositionCoordinates(element, position) {
|
||
|
var rect = null;
|
||
|
if (domUtils$a.isContentEditableElement(element))
|
||
|
rect = getSelectionRectangleInContentEditableElement(element, position);
|
||
|
else if (typeof element.createTextRange === 'function')
|
||
|
rect = getTextSelectionRectangle(element, position);
|
||
|
else
|
||
|
rect = getSelectionRectangle(element, position);
|
||
|
if (!rect)
|
||
|
return null;
|
||
|
rect = ensureRectangleInsideElement(element, rect);
|
||
|
rect = getAbsoluteRect(rect);
|
||
|
return {
|
||
|
x: rect.left,
|
||
|
y: Math.floor(rect.top + (rect.bottom - rect.top) / 2),
|
||
|
};
|
||
|
}
|
||
|
function getSelectionCoordinatesByPosition(element, position) {
|
||
|
var isTextEditable = domUtils$a.isTextEditableElement(element);
|
||
|
var isContentEditable = domUtils$a.isContentEditableElement(element);
|
||
|
var hasText = isTextEditable && domUtils$a.getElementValue(element).length > 0 ||
|
||
|
isContentEditable && contentEditable$2.getContentEditableValue(element).length;
|
||
|
if (!hasText)
|
||
|
return positionUtils$4.findCenter(element);
|
||
|
return getPositionCoordinates(element, position);
|
||
|
}
|
||
|
function getSelectionCoordinatesByNodeAndOffset(element, node, offset) {
|
||
|
var range = domUtils$a.findDocument(element).createRange();
|
||
|
range.setStart(node, Math.min(offset, node.length));
|
||
|
range.setEnd(node, Math.min(offset, node.length));
|
||
|
var rect = range.getClientRects()[0];
|
||
|
if (!rect)
|
||
|
return null;
|
||
|
rect = ensureRectangleInsideElement(element, rect);
|
||
|
rect = getAbsoluteRect(rect);
|
||
|
return {
|
||
|
x: rect.left,
|
||
|
y: Math.floor(rect.top + (rect.bottom - rect.top) / 2),
|
||
|
};
|
||
|
}
|
||
|
function getLastVisibleSelectionPosition(element, startPos, endPos) {
|
||
|
var backward = startPos > endPos;
|
||
|
var inc = backward ? 1 : -1;
|
||
|
var currentPos = endPos;
|
||
|
var currentPoint = null;
|
||
|
while (currentPos !== startPos) {
|
||
|
currentPos += inc;
|
||
|
currentPoint = getPositionCoordinates(element, currentPos);
|
||
|
if (currentPoint)
|
||
|
break;
|
||
|
}
|
||
|
if (!currentPoint) {
|
||
|
currentPoint = getPositionCoordinates(element, startPos) ||
|
||
|
positionUtils$4.findCenter(element);
|
||
|
}
|
||
|
return currentPoint;
|
||
|
}
|
||
|
function scrollEditableElementByPoint(element, point) {
|
||
|
if (!domUtils$a.isEditableElement(element))
|
||
|
return;
|
||
|
var isTextarea = domUtils$a.isTextAreaElement(element);
|
||
|
var isInputElement = domUtils$a.isInputElement(element);
|
||
|
// NOTE: we don't need to scroll input elements in Mozilla and
|
||
|
// IE > 10 because it happens automatically on selection setting
|
||
|
if (isInputElement && (browserUtils$e.isFirefox || browserUtils$e.isIE && browserUtils$e.version > 10))
|
||
|
return;
|
||
|
var elementOffset = positionUtils$4.getOffsetPosition(element);
|
||
|
var elementBorders = styleUtils$6.getBordersWidth(element);
|
||
|
var elementScroll = styleUtils$6.getElementScroll(element);
|
||
|
var offsetX = point.x - elementOffset.left - elementBorders.left;
|
||
|
var offsetY = point.y - elementOffset.top - elementBorders.top;
|
||
|
var scrollValue = null;
|
||
|
if (isTextarea) {
|
||
|
if (offsetY < elementScroll.top)
|
||
|
scrollValue = offsetY;
|
||
|
if (offsetY > element.clientHeight + elementScroll.top)
|
||
|
scrollValue = offsetY - element.clientHeight;
|
||
|
if (scrollValue !== null)
|
||
|
styleUtils$6.setScrollTop(element, Math.round(scrollValue));
|
||
|
return;
|
||
|
}
|
||
|
if (offsetX < elementScroll.left)
|
||
|
scrollValue = offsetX;
|
||
|
if (offsetX > element.clientWidth + elementScroll.left)
|
||
|
scrollValue = offsetX - element.clientWidth;
|
||
|
if (scrollValue !== null)
|
||
|
styleUtils$6.setScrollLeft(element, Math.round(scrollValue));
|
||
|
}
|
||
|
function excludeElementScroll(element, point) {
|
||
|
var isTextEditable = domUtils$a.isTextEditableElement(element);
|
||
|
var isInputElement = domUtils$a.isInputElement(element);
|
||
|
if (!(isTextEditable || domUtils$a.isContentEditableElement(element)))
|
||
|
return point;
|
||
|
var elementOffset = positionUtils$4.getOffsetPosition(element);
|
||
|
var elementBorders = styleUtils$6.getBordersWidth(element);
|
||
|
var elementScroll = styleUtils$6.getElementScroll(element);
|
||
|
var maxLeft = elementOffset.left + elementBorders.left + element.clientWidth;
|
||
|
// NOTE: we can't know input elements' scroll value in Mozilla and
|
||
|
// IE > 10 (https://bugzilla.mozilla.org/show_bug.cgi?id=293186)
|
||
|
if (isInputElement && isTextEditable &&
|
||
|
(browserUtils$e.isFirefox || browserUtils$e.isIE && browserUtils$e.version > 10)) {
|
||
|
return {
|
||
|
x: Math.min(point.x, maxLeft),
|
||
|
y: point.y,
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
x: point.x - elementScroll.left,
|
||
|
y: point.y - elementScroll.top,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var Promise$c = hammerhead__default.Promise;
|
||
|
var browserUtils$f = hammerhead__default.utils.browser;
|
||
|
var featureDetection$5 = hammerhead__default.utils.featureDetection;
|
||
|
var eventSimulator$d = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var focusBlurSandbox$4 = hammerhead__default.eventSandbox.focusBlur;
|
||
|
var contentEditable$3 = testCafeCore__default.contentEditable;
|
||
|
var domUtils$b = testCafeCore__default.domUtils;
|
||
|
var positionUtils$5 = testCafeCore__default.positionUtils;
|
||
|
var eventUtils$6 = testCafeCore__default.eventUtils;
|
||
|
var delay$4 = testCafeCore__default.delay;
|
||
|
var SelectBaseAutomation = /** @class */ (function (_super) {
|
||
|
__extends(SelectBaseAutomation, _super);
|
||
|
function SelectBaseAutomation(element, actionOptions) {
|
||
|
var _this = _super.call(this, element, actionOptions, window, cursor) || this;
|
||
|
_this.absoluteStartPoint = null;
|
||
|
_this.absoluteEndPoint = null;
|
||
|
_this.clientPoint = null;
|
||
|
_this.speed = actionOptions.speed;
|
||
|
_this.downEvent = featureDetection$5.isTouchDevice ? 'touchstart' : 'mousedown';
|
||
|
_this.upEvent = featureDetection$5.isTouchDevice ? 'touchend' : 'mouseup';
|
||
|
_this.eventArgs = {
|
||
|
options: null,
|
||
|
element: null,
|
||
|
};
|
||
|
_this.eventState = {
|
||
|
mousedownPrevented: false,
|
||
|
simulateDefaultBehavior: true,
|
||
|
};
|
||
|
return _this;
|
||
|
}
|
||
|
SelectBaseAutomation.prototype._calculateEventArguments = function () {
|
||
|
var _this = this;
|
||
|
var clientPoint = positionUtils$5.offsetToClientCoords(this.clientPoint);
|
||
|
return getElementFromPoint$2(clientPoint)
|
||
|
.then(function (element) {
|
||
|
if (!element) {
|
||
|
throw new ActionElementIsInvisibleError(null, {
|
||
|
reason: positionUtils$5.getElOutsideBoundsReason(_this.element),
|
||
|
});
|
||
|
}
|
||
|
return {
|
||
|
element: element,
|
||
|
options: {
|
||
|
clientX: clientPoint.x,
|
||
|
clientY: clientPoint.y,
|
||
|
},
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._move = function (_a) {
|
||
|
var _this = this;
|
||
|
var element = _a.element, offsetX = _a.offsetX, offsetY = _a.offsetY, speed = _a.speed;
|
||
|
var moveOptions = new MoveOptions({ offsetX: offsetX, offsetY: offsetY, speed: speed }, false);
|
||
|
return MoveAutomation.create(element, moveOptions, window, cursor)
|
||
|
.then(function (moveAutomation) {
|
||
|
return moveAutomation.run();
|
||
|
})
|
||
|
.then(function () { return delay$4(_this.automationSettings.mouseActionStepDelay); });
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._bindMousedownHandler = function () {
|
||
|
var _this = this;
|
||
|
var onmousedown = function (e) {
|
||
|
_this.eventState.mousedownPrevented = e.defaultPrevented;
|
||
|
eventUtils$6.preventDefault(e);
|
||
|
eventUtils$6.unbind(_this.element, 'mousedown', onmousedown);
|
||
|
};
|
||
|
eventUtils$6.bind(this.element, 'mousedown', onmousedown);
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._calculateAbsoluteStartPoint = function () {
|
||
|
throw new Error('Not implemented');
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._calculateAbsoluteEndPoint = function () {
|
||
|
throw new Error('Not implemented');
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._moveToPoint = function (point) {
|
||
|
scrollEditableElementByPoint(this.element, point);
|
||
|
this.clientPoint = excludeElementScroll(this.element, point);
|
||
|
var moveArguments = {
|
||
|
element: document.documentElement,
|
||
|
offsetX: this.clientPoint.x,
|
||
|
offsetY: this.clientPoint.y,
|
||
|
speed: this.speed,
|
||
|
};
|
||
|
return this._move(moveArguments);
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._mousedown = function () {
|
||
|
var _this = this;
|
||
|
return cursor
|
||
|
.leftButtonDown()
|
||
|
.then(function () { return _this._calculateEventArguments(); })
|
||
|
.then(function (args) {
|
||
|
_this.eventArgs = args;
|
||
|
// NOTE: In WebKit and IE, the mousedown event opens the select element's dropdown;
|
||
|
// therefore, we should prevent mousedown and hide the dropdown (B236416).
|
||
|
var needCloseSelectDropDown = (browserUtils$f.isWebKit || browserUtils$f.isIE) &&
|
||
|
domUtils$b.isSelectElement(_this.element);
|
||
|
if (needCloseSelectDropDown)
|
||
|
_this._bindMousedownHandler();
|
||
|
_this.eventState.simulateDefaultBehavior = eventSimulator$d[_this.downEvent](_this.eventArgs.element, _this.eventArgs.options);
|
||
|
if (_this.eventState.simulateDefaultBehavior === false)
|
||
|
_this.eventState.simulateDefaultBehavior = needCloseSelectDropDown && !_this.eventState.mousedownPrevented;
|
||
|
return _this._focus();
|
||
|
});
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._focus = function () {
|
||
|
var _this = this;
|
||
|
return new Promise$c(function (resolve) {
|
||
|
// NOTE: If the target element is a child of a contentEditable element, we need to call focus for its parent
|
||
|
var elementForFocus = domUtils$b.isContentEditableElement(_this.element) ?
|
||
|
contentEditable$3.findContentEditableParent(_this.element) : _this.element;
|
||
|
focusBlurSandbox$4.focus(elementForFocus, resolve, false, true);
|
||
|
});
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._setSelection = function () {
|
||
|
throw new Error('Not implemented');
|
||
|
};
|
||
|
SelectBaseAutomation.prototype._mouseup = function () {
|
||
|
var _this = this;
|
||
|
return cursor
|
||
|
.buttonUp()
|
||
|
.then(function () {
|
||
|
_this._setSelection();
|
||
|
return _this._calculateEventArguments();
|
||
|
})
|
||
|
.then(function (args) {
|
||
|
_this.eventArgs = args;
|
||
|
eventSimulator$d[_this.upEvent](_this.eventArgs.element, _this.eventArgs.options);
|
||
|
});
|
||
|
};
|
||
|
SelectBaseAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
this.absoluteStartPoint = this._calculateAbsoluteStartPoint();
|
||
|
this.absoluteEndPoint = this._calculateAbsoluteEndPoint();
|
||
|
return this
|
||
|
._moveToPoint(this.absoluteStartPoint)
|
||
|
.then(function () { return _this._mousedown(); })
|
||
|
.then(function () { return _this._moveToPoint(_this.absoluteEndPoint); })
|
||
|
.then(function () { return _this._mouseup(); });
|
||
|
};
|
||
|
return SelectBaseAutomation;
|
||
|
}(VisibleElementAutomation));
|
||
|
|
||
|
var textSelection$3 = testCafeCore__default.textSelection;
|
||
|
var domUtils$c = testCafeCore__default.domUtils;
|
||
|
var positionUtils$6 = testCafeCore__default.positionUtils;
|
||
|
var SelectTextAutomation = /** @class */ (function (_super) {
|
||
|
__extends(SelectTextAutomation, _super);
|
||
|
function SelectTextAutomation(element, startPos, endPos, actionOptions) {
|
||
|
var _this = _super.call(this, element, actionOptions) || this;
|
||
|
_this.startPos = startPos;
|
||
|
_this.endPos = endPos;
|
||
|
return _this;
|
||
|
}
|
||
|
SelectTextAutomation.prototype._calculateAbsoluteStartPoint = function () {
|
||
|
var point = getSelectionCoordinatesByPosition(this.element, this.startPos);
|
||
|
return point || positionUtils$6.findCenter(this.element);
|
||
|
};
|
||
|
SelectTextAutomation.prototype._calculateAbsoluteEndPoint = function () {
|
||
|
var point = getSelectionCoordinatesByPosition(this.element, this.endPos);
|
||
|
if (point)
|
||
|
return point;
|
||
|
// NOTE: if selection ends on an invisible symbol, we should try to find the last visible selection position
|
||
|
if (domUtils$c.isContentEditableElement(this.element))
|
||
|
return getLastVisibleSelectionPosition(this.element, this.startPos, this.endPos);
|
||
|
return positionUtils$6.findCenter(this.element);
|
||
|
};
|
||
|
SelectTextAutomation.prototype._setSelection = function () {
|
||
|
var isTextEditable = domUtils$c.isTextEditableElement(this.element);
|
||
|
var isContentEditable = domUtils$c.isContentEditableElement(this.element);
|
||
|
if (!(isTextEditable || isContentEditable) || this.eventState.simulateDefaultBehavior === false)
|
||
|
return;
|
||
|
textSelection$3.select(this.element, this.startPos, this.endPos);
|
||
|
};
|
||
|
SelectTextAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
return this
|
||
|
._ensureElement(useStrictElementCheck)
|
||
|
.then(function () { return _super.prototype.run.call(_this); });
|
||
|
};
|
||
|
return SelectTextAutomation;
|
||
|
}(SelectBaseAutomation));
|
||
|
|
||
|
var textSelection$4 = testCafeCore__default.textSelection;
|
||
|
var contentEditable$4 = testCafeCore__default.contentEditable;
|
||
|
var positionUtils$7 = testCafeCore__default.positionUtils;
|
||
|
var SelectEditableContentAutomation = /** @class */ (function (_super) {
|
||
|
__extends(SelectEditableContentAutomation, _super);
|
||
|
function SelectEditableContentAutomation(startNode, endNode, actionOptions) {
|
||
|
var _this = _super.call(this, contentEditable$4.getNearestCommonAncestor(startNode, endNode), actionOptions) || this;
|
||
|
var startOffset = contentEditable$4.getFirstVisiblePosition(startNode);
|
||
|
var endOffset = contentEditable$4.getLastVisiblePosition(endNode);
|
||
|
var startPos = { node: startNode, offset: startOffset };
|
||
|
var endPos = { node: endNode, offset: endOffset };
|
||
|
var startPosition = contentEditable$4.calculatePositionByNodeAndOffset(_this.element, startPos);
|
||
|
var endPosition = contentEditable$4.calculatePositionByNodeAndOffset(_this.element, endPos);
|
||
|
if (startPosition > endPosition) {
|
||
|
startOffset = contentEditable$4.getLastVisiblePosition(startNode);
|
||
|
endOffset = contentEditable$4.getFirstVisiblePosition(endNode);
|
||
|
}
|
||
|
// NOTE: We should recalculate nodes and offsets for selection because we
|
||
|
// may have to select children of expectedStartNode and expectedEndNode
|
||
|
startPos = contentEditable$4.calculateNodeAndOffsetByPosition(startNode, startOffset);
|
||
|
endPos = contentEditable$4.calculateNodeAndOffsetByPosition(endNode, endOffset);
|
||
|
_this.startNode = startPos.node;
|
||
|
_this.startOffset = startPos.offset;
|
||
|
_this.endNode = endPos.node;
|
||
|
_this.endOffset = endPos.offset;
|
||
|
return _this;
|
||
|
}
|
||
|
SelectEditableContentAutomation.prototype._calculateAbsoluteStartPoint = function () {
|
||
|
var point = getSelectionCoordinatesByNodeAndOffset(this.element, this.startNode, this.startOffset);
|
||
|
return point || positionUtils$7.findCenter(this.element);
|
||
|
};
|
||
|
SelectEditableContentAutomation.prototype._calculateAbsoluteEndPoint = function () {
|
||
|
var point = getSelectionCoordinatesByNodeAndOffset(this.element, this.endNode, this.endOffset);
|
||
|
return point || positionUtils$7.findCenter(this.element);
|
||
|
};
|
||
|
SelectEditableContentAutomation.prototype._setSelection = function () {
|
||
|
if (this.eventState.simulateDefaultBehavior === false)
|
||
|
return;
|
||
|
// NOTE: The same cursor position may correspond to different nodes, so, if we
|
||
|
// know which nodes should be selected eventually, we should select them directly.
|
||
|
var startPos = { node: this.startNode, offset: this.startOffset };
|
||
|
var endPos = { node: this.endNode, offset: this.endOffset };
|
||
|
textSelection$4.selectByNodesAndOffsets(startPos, endPos, true);
|
||
|
};
|
||
|
return SelectEditableContentAutomation;
|
||
|
}(SelectBaseAutomation));
|
||
|
|
||
|
var Promise$d = hammerhead__default.Promise;
|
||
|
var extend$4 = hammerhead__default.utils.extend;
|
||
|
var browserUtils$g = hammerhead__default.utils.browser;
|
||
|
var eventSimulator$e = hammerhead__default.eventSandbox.eventSimulator;
|
||
|
var elementEditingWatcher$1 = hammerhead__default.eventSandbox.elementEditingWatcher;
|
||
|
var domUtils$d = testCafeCore__default.domUtils;
|
||
|
var promiseUtils = testCafeCore__default.promiseUtils;
|
||
|
var contentEditable$5 = testCafeCore__default.contentEditable;
|
||
|
var textSelection$5 = testCafeCore__default.textSelection;
|
||
|
var delay$5 = testCafeCore__default.delay;
|
||
|
var SPECIAL_KEYS = testCafeCore__default.KEY_MAPS.specialKeys;
|
||
|
var TypeAutomation = /** @class */ (function () {
|
||
|
function TypeAutomation(element, text, typeOptions) {
|
||
|
this.element = TypeAutomation.findTextEditableChild(element) || element;
|
||
|
this.typingText = text.toString();
|
||
|
this.modifiers = typeOptions.modifiers;
|
||
|
this.caretPos = typeOptions.caretPos;
|
||
|
this.replace = typeOptions.replace;
|
||
|
this.paste = typeOptions.paste;
|
||
|
this.offsetX = typeOptions.offsetX;
|
||
|
this.offsetY = typeOptions.offsetY;
|
||
|
this.speed = typeOptions.speed;
|
||
|
this.automationSettings = new AutomationSettings(this.speed);
|
||
|
this.elementChanged = element !== this.element;
|
||
|
this.currentPos = 0;
|
||
|
this.currentKeyCode = null;
|
||
|
this.currentCharCode = null;
|
||
|
this.currentKey = null;
|
||
|
this.currentKeyIdentifier = null;
|
||
|
this.ignoreChangeEvent = true;
|
||
|
this.eventArgs = {
|
||
|
options: null,
|
||
|
element: null,
|
||
|
};
|
||
|
this.eventState = {
|
||
|
skipType: false,
|
||
|
simulateKeypress: true,
|
||
|
simulateTypeChar: true,
|
||
|
};
|
||
|
}
|
||
|
TypeAutomation.findTextEditableChild = function (element) {
|
||
|
var innerElement = null;
|
||
|
if (!domUtils$d.isEditableElement(element)) {
|
||
|
var allChildren = element.querySelectorAll('*');
|
||
|
for (var i = 0; i < allChildren.length; i++) {
|
||
|
if (domUtils$d.isTextEditableElementAndEditingAllowed(allChildren[i])) {
|
||
|
innerElement = allChildren[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return innerElement;
|
||
|
};
|
||
|
TypeAutomation.prototype._calculateEventArguments = function (isPressEvent) {
|
||
|
var activeElement = domUtils$d.getActiveElement();
|
||
|
var isContentEditable = domUtils$d.isContentEditableElement(this.element);
|
||
|
var element = this.eventArgs.element || this.element;
|
||
|
// T162478: Wrong typing and keys pressing in editor
|
||
|
if (!isContentEditable && activeElement !== element)
|
||
|
element = TypeAutomation.findTextEditableChild(activeElement) || activeElement;
|
||
|
var options = extend$4({
|
||
|
keyCode: isPressEvent ? this.currentCharCode : this.currentKeyCode,
|
||
|
}, this.modifiers);
|
||
|
if (isPressEvent)
|
||
|
options.charCode = this.currentCharCode;
|
||
|
extend$4(options, getKeyProperties(isPressEvent, this.currentKey, this.currentKeyIdentifier));
|
||
|
return { element: element, options: options };
|
||
|
};
|
||
|
TypeAutomation.prototype._calculateTargetElement = function () {
|
||
|
var activeElement = domUtils$d.getActiveElement();
|
||
|
var isContentEditable = domUtils$d.isContentEditableElement(this.element);
|
||
|
if (isContentEditable) {
|
||
|
if (activeElement !== contentEditable$5.findContentEditableParent(this.element)) {
|
||
|
this.eventState.skipType = true;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if (activeElement !== this.element) {
|
||
|
this.eventState.skipType = true;
|
||
|
return;
|
||
|
}
|
||
|
this.element = isContentEditable ? this.element : activeElement;
|
||
|
};
|
||
|
TypeAutomation.prototype._click = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
var activeElement = domUtils$d.getActiveElement();
|
||
|
var isTextEditable = domUtils$d.isTextEditableElementAndEditingAllowed(this.element);
|
||
|
var isContentEditable = domUtils$d.isContentEditableElement(this.element);
|
||
|
if (activeElement !== this.element) {
|
||
|
var _a = getDefaultAutomationOffsets(this.element), offsetX = _a.offsetX, offsetY = _a.offsetY;
|
||
|
var clickOptions = new ClickOptions({
|
||
|
offsetX: this.elementChanged ? offsetX : this.offsetX,
|
||
|
offsetY: this.elementChanged ? offsetY : this.offsetY,
|
||
|
speed: this.speed,
|
||
|
caretPos: this.caretPos,
|
||
|
modifiers: this.modifiers,
|
||
|
});
|
||
|
var clickAutomation = new ClickAutomation(this.element, clickOptions, window, cursor);
|
||
|
return clickAutomation
|
||
|
.run(useStrictElementCheck)
|
||
|
.then(function () { return delay$5(_this.automationSettings.mouseActionStepDelay); });
|
||
|
}
|
||
|
if (isTextEditable)
|
||
|
elementEditingWatcher$1.watchElementEditing(this.element);
|
||
|
var isEditableElement = isTextEditable || isContentEditable;
|
||
|
if (isEditableElement) {
|
||
|
var selectionStart = textSelection$5.getSelectionStart(this.element);
|
||
|
if (!isNaN(parseInt(this.caretPos, 10)) && this.caretPos !== selectionStart)
|
||
|
textSelection$5.select(this.element, this.caretPos, this.caretPos);
|
||
|
}
|
||
|
return Promise$d.resolve();
|
||
|
};
|
||
|
TypeAutomation.prototype._type = function () {
|
||
|
var _this = this;
|
||
|
if (this.eventState.skipType)
|
||
|
return Promise$d.resolve();
|
||
|
var isContentEditable = domUtils$d.isContentEditableElement(this.element);
|
||
|
if (this.replace) {
|
||
|
if (domUtils$d.isTextEditableElementAndEditingAllowed(this.element))
|
||
|
textSelection$5.select(this.element);
|
||
|
else if (isContentEditable)
|
||
|
textSelection$5.deleteSelectionContents(this.element, true);
|
||
|
}
|
||
|
return promiseUtils.whilst(function () { return !_this._isTypingFinished(); }, function () { return _this._typingStep(); });
|
||
|
};
|
||
|
TypeAutomation.prototype._isTypingFinished = function () {
|
||
|
return this.currentPos === this.typingText.length;
|
||
|
};
|
||
|
TypeAutomation.prototype._typingStep = function () {
|
||
|
var char = this.typingText.charAt(this.currentPos);
|
||
|
this.currentKeyCode = getKeyCode(char);
|
||
|
this.currentCharCode = this.typingText.charCodeAt(this.currentPos);
|
||
|
this.currentKey = this.currentKeyCode === SPECIAL_KEYS['enter'] ? 'Enter' : char;
|
||
|
this.currentKeyIdentifier = getKeyIdentifier(this.currentKey);
|
||
|
this.ignoreChangeEvent = domUtils$d.getElementValue(this.element) === elementEditingWatcher$1.getElementSavedValue(this.element);
|
||
|
this._keydown();
|
||
|
this._keypress();
|
||
|
return this._keyup();
|
||
|
};
|
||
|
TypeAutomation.prototype._keydown = function () {
|
||
|
this.eventArgs = this._calculateEventArguments();
|
||
|
this.eventState.simulateKeypress = eventSimulator$e.keydown(this.eventArgs.element, this.eventArgs.options);
|
||
|
};
|
||
|
TypeAutomation.prototype._keypress = function () {
|
||
|
if (this.eventState.simulateKeypress === false)
|
||
|
return;
|
||
|
this.eventArgs = this._calculateEventArguments(true);
|
||
|
this.eventState.simulateTypeChar = browserUtils$g.isAndroid || eventSimulator$e.keypress(this.eventArgs.element, this.eventArgs.options);
|
||
|
};
|
||
|
TypeAutomation.prototype._keyup = function () {
|
||
|
var _this = this;
|
||
|
var elementForTyping = this.eventArgs.element;
|
||
|
this.eventArgs = this._calculateEventArguments();
|
||
|
var isTextEditableElement = domUtils$d.isTextEditableElement(this.element);
|
||
|
var isContentEditable = domUtils$d.isContentEditableElement(this.element);
|
||
|
var shouldTypeAllText = this.paste || !isTextEditableElement && !isContentEditable;
|
||
|
return Promise$d
|
||
|
.resolve()
|
||
|
.then(function () {
|
||
|
return shouldTypeAllText ? _this._typeAllText(elementForTyping) : _this._typeChar(elementForTyping);
|
||
|
})
|
||
|
.then(function () {
|
||
|
eventSimulator$e.keyup(_this.eventArgs.element, _this.eventArgs.options);
|
||
|
if (shouldTypeAllText)
|
||
|
_this.currentPos = _this.typingText.length;
|
||
|
else
|
||
|
_this.currentPos++;
|
||
|
});
|
||
|
};
|
||
|
TypeAutomation.prototype._typeChar = function (element) {
|
||
|
// NOTE: change event must not be raised after prevented keydown
|
||
|
// or keypress even if element value was changed (B253816)
|
||
|
if (this.eventState.simulateKeypress === false || this.eventState.simulateTypeChar === false) {
|
||
|
// NOTE: change event should still be raised if element value
|
||
|
// was changed before the prevented keypress or keydown (GH-4881)
|
||
|
if (this.ignoreChangeEvent)
|
||
|
elementEditingWatcher$1.restartWatchingElementEditing(element);
|
||
|
return delay$5(this.automationSettings.keyActionStepDelay);
|
||
|
}
|
||
|
var currentChar = this.typingText.charAt(this.currentPos);
|
||
|
var isDigit = /^\d$/.test(currentChar);
|
||
|
var prevChar = this.currentPos === 0 ? null : this.typingText.charAt(this.currentPos - 1);
|
||
|
var isInputTypeNumber = domUtils$d.isInputElement(element) && element.type === 'number';
|
||
|
if (isInputTypeNumber) {
|
||
|
var selectionStart = textSelection$5.getSelectionStart(element);
|
||
|
var valueLength = domUtils$d.getInputValue(element).length;
|
||
|
var textHasDigits = /^\d/.test(this.typingText);
|
||
|
var isPermissibleSymbol = currentChar === '.' || currentChar === '-' && valueLength;
|
||
|
if (!isDigit && (textHasDigits || !isPermissibleSymbol || selectionStart !== 0))
|
||
|
return delay$5(this.automationSettings.keyActionStepDelay);
|
||
|
// NOTE: allow to type '.' or '-' only if it is the first symbol and the input already has
|
||
|
// a value, or if '.' or '-' are added to a digit. Otherwise, the value won't be set.
|
||
|
if (isDigit && (prevChar === '.' || prevChar === '-' && !valueLength))
|
||
|
currentChar = prevChar + currentChar;
|
||
|
}
|
||
|
typeText(element, currentChar, null);
|
||
|
return delay$5(this.automationSettings.keyActionStepDelay);
|
||
|
};
|
||
|
TypeAutomation.prototype._typeAllText = function (element) {
|
||
|
typeText(element, this.typingText, this.caretPos);
|
||
|
return delay$5(this.automationSettings.keyActionStepDelay);
|
||
|
};
|
||
|
TypeAutomation.prototype.run = function (useStrictElementCheck) {
|
||
|
var _this = this;
|
||
|
return this
|
||
|
._click(useStrictElementCheck)
|
||
|
.then(function () { return _this._calculateTargetElement(); })
|
||
|
.then(function () { return _this._type(); });
|
||
|
};
|
||
|
return TypeAutomation;
|
||
|
}());
|
||
|
|
||
|
var UploadAutomation = /** @class */ (function () {
|
||
|
function UploadAutomation(element, paths, createError) {
|
||
|
this.element = element;
|
||
|
this.paths = paths;
|
||
|
this.createError = createError;
|
||
|
}
|
||
|
UploadAutomation.prototype.run = function () {
|
||
|
var _this = this;
|
||
|
return hammerhead.doUpload(this.element, this.paths)
|
||
|
.then(function (errs) {
|
||
|
if (!errs.length)
|
||
|
return;
|
||
|
var filePaths = testCafeCore.arrayUtils.map(errs, function (err) { return err.path; });
|
||
|
var scannedFilePaths = testCafeCore.arrayUtils.reduce(errs, function (prev, current) {
|
||
|
return prev.concat(current.resolvedPaths);
|
||
|
}, []);
|
||
|
throw _this.createError(filePaths, scannedFilePaths);
|
||
|
});
|
||
|
};
|
||
|
return UploadAutomation;
|
||
|
}());
|
||
|
|
||
|
var domUtils$e = testCafeCore__default.domUtils;
|
||
|
var contentEditable$6 = testCafeCore__default.contentEditable;
|
||
|
function getSelectTextAreaContentArguments(element, argumentsObject) {
|
||
|
var value = domUtils$e.getTextAreaValue(element);
|
||
|
var linesArray = value && value.length ? value.split('\n') : [];
|
||
|
var lastLineIndex = linesArray.length - 1;
|
||
|
var startLineIndex = !argumentsObject.startLine ? 0 : Math.min(argumentsObject.startLine, lastLineIndex);
|
||
|
var startLineLength = linesArray[startLineIndex] ? linesArray[startLineIndex].length : 0;
|
||
|
var startPos = !argumentsObject.startPos ? 0 : Math.min(argumentsObject.startPos, startLineLength);
|
||
|
var endLineIndex = argumentsObject.endLine === void 0 || argumentsObject.endLine === null ?
|
||
|
lastLineIndex : Math.min(argumentsObject.endLine, lastLineIndex);
|
||
|
var endLineLength = linesArray[endLineIndex] ? linesArray[endLineIndex].length : 0;
|
||
|
var endPos = argumentsObject.endPos === void 0 ||
|
||
|
argumentsObject.endPos ===
|
||
|
null ? endLineLength : Math.min(argumentsObject.endPos, endLineLength);
|
||
|
var startLinePosition = domUtils$e.getTextareaPositionByLineAndOffset(element, startLineIndex, 0);
|
||
|
var endLinePosition = domUtils$e.getTextareaPositionByLineAndOffset(element, endLineIndex, 0);
|
||
|
return {
|
||
|
startPos: startLinePosition + startPos,
|
||
|
endPos: endLinePosition + endPos,
|
||
|
};
|
||
|
}
|
||
|
function calculateSelectTextArguments (element, argumentsObject) {
|
||
|
if (argumentsObject === void 0) { argumentsObject = {}; }
|
||
|
var isTextEditable = domUtils$e.isTextEditableElement(element);
|
||
|
var firstPos = isTextEditable ? 0 : contentEditable$6.getFirstVisiblePosition(element);
|
||
|
var lastPos = isTextEditable ? domUtils$e.getElementValue(element).length : contentEditable$6.getLastVisiblePosition(element);
|
||
|
var startPos = !argumentsObject.startPos ? firstPos : Math.min(argumentsObject.startPos, lastPos);
|
||
|
var endPos = argumentsObject.endPos === void 0 ||
|
||
|
argumentsObject.endPos === null ? lastPos : Math.min(argumentsObject.endPos, lastPos);
|
||
|
if (argumentsObject.offset !== void 0) {
|
||
|
if (argumentsObject.offset >= 0)
|
||
|
endPos = Math.min(argumentsObject.offset, endPos);
|
||
|
else {
|
||
|
startPos = endPos;
|
||
|
endPos = Math.max(0, endPos + argumentsObject.offset);
|
||
|
}
|
||
|
return { startPos: startPos, endPos: endPos };
|
||
|
}
|
||
|
if (argumentsObject.startLine !== void 0)
|
||
|
return getSelectTextAreaContentArguments(element, argumentsObject);
|
||
|
return { startPos: startPos, endPos: endPos };
|
||
|
}
|
||
|
|
||
|
var exports$1 = {};
|
||
|
exports$1.DispatchEvent = DispatchEventAutomation;
|
||
|
exports$1.SetScroll = SetScrollAutomation;
|
||
|
exports$1.ScrollIntoView = ScrollIntoViewAutomation;
|
||
|
exports$1.Click = ClickAutomation;
|
||
|
exports$1.SelectChildClick = SelectChildClickAutomation;
|
||
|
exports$1.DblClick = DblClickAutomation;
|
||
|
exports$1.DragToOffset = DragToOffsetAutomation;
|
||
|
exports$1.DragToElement = DragToElementAutomation;
|
||
|
exports$1.Hover = HoverAutomation;
|
||
|
exports$1.Press = PressAutomation;
|
||
|
exports$1.RClick = RClickAutomation;
|
||
|
exports$1.SelectText = SelectTextAutomation;
|
||
|
exports$1.SelectEditableContent = SelectEditableContentAutomation;
|
||
|
exports$1.Type = TypeAutomation;
|
||
|
exports$1.Upload = UploadAutomation;
|
||
|
exports$1.MouseOptions = MouseOptions;
|
||
|
exports$1.ClickOptions = ClickOptions;
|
||
|
exports$1.TypeOptions = TypeOptions;
|
||
|
exports$1.AutomationSettings = AutomationSettings;
|
||
|
exports$1.getOffsetOptions = getOffsetOptions;
|
||
|
exports$1.calculateSelectTextArguments = calculateSelectTextArguments;
|
||
|
exports$1.cursor = cursor;
|
||
|
exports$1.getNextFocusableElement = getNextFocusableElement;
|
||
|
exports$1.SHORTCUT_TYPE = SHORTCUT_TYPE;
|
||
|
exports$1.getSelectionCoordinatesByPosition = getSelectionCoordinatesByPosition;
|
||
|
exports$1.getElementFromPoint = getElementFromPoint$2;
|
||
|
// NOTE: for testing purposes
|
||
|
exports$1.MoveAutomation = MoveAutomation;
|
||
|
var nativeMethods$e = hammerhead__default.nativeMethods;
|
||
|
var evalIframeScript = hammerhead__default.EVENTS.evalIframeScript;
|
||
|
nativeMethods$e.objectDefineProperty(window, '%testCafeAutomation%', { configurable: true, value: exports$1 });
|
||
|
// eslint-disable-next-line no-undef
|
||
|
hammerhead__default.on(evalIframeScript, function (e) { return initTestCafeAutomation(nativeMethods$e.contentWindowGetter.call(e.iframe), true); });
|
||
|
|
||
|
}(window['%hammerhead%'], window['%hammerhead%'].Promise, window['%testCafeCore%'], window['%testCafeUI%']));
|
||
|
|
||
|
}
|
||
|
|
||
|
initTestCafeAutomation(window);
|
||
|
})();
|