@luminati-io/webdriverio8
Version:
Next-gen browser and mobile automation test framework for Node.js
119 lines • 11.5 kB
JavaScript
/**
* check if element is within the viewport or is overlapped by another element or disabled
* @param {HTMLElement} elem element to check
* @return {Boolean} false if element is not overlapped
*/
export default function isElementClickable(elem) {
if (!elem.getBoundingClientRect || !elem.scrollIntoView || !elem.contains || !elem.getClientRects || !document.elementFromPoint) {
return false;
}
// Edge before switching to Chromium
const isOldEdge = !!window.StyleMedia;
// returns true for Chrome and Firefox and false for Safari, Edge and IE
const scrollIntoViewFullSupport = !(window.safari || isOldEdge);
// get overlapping element
function getOverlappingElement(elem, context) {
context = context || document;
const elemDimension = elem.getBoundingClientRect();
const x = elemDimension.left + (elem.clientWidth / 2);
const y = elemDimension.top + (elem.clientHeight / 2);
return context.elementFromPoint(x, y);
}
// get overlapping element rects (currently only the first)
// applicable if element's text is multiline.
function getOverlappingRects(elem, context) {
context = context || document;
const elems = [];
const rects = elem.getClientRects();
// webdriver clicks on center of the first element's rect (line of text), it might change in future
const rect = rects[0];
const x = rect.left + (rect.width / 2);
const y = rect.top + (rect.height / 2);
elems.push(context.elementFromPoint(x, y));
return elems;
}
// get overlapping elements
function getOverlappingElements(elem, context) {
return [getOverlappingElement(elem, context)].concat(getOverlappingRects(elem, context));
}
// is a node a descendant of a given node
function nodeContains(elem, otherNode) {
// Edge doesn't support neither Shadow Dom nor contains if ShadowRoot polyfill is used
if (isOldEdge) {
let tmpElement = otherNode;
while (tmpElement) {
if (tmpElement === elem) {
return true;
}
tmpElement = tmpElement.parentNode;
// DocumentFragment / ShadowRoot polyfill like ShadyRoot
if (tmpElement && tmpElement.nodeType === 11 && tmpElement.host) {
tmpElement = tmpElement.host;
}
}
return false;
}
return elem.contains(otherNode);
}
// is one of overlapping elements the `elem` or one of its child
function isOverlappingElementMatch(elementsFromPoint, elem) {
if (elementsFromPoint.some(function (elementFromPoint) {
return elementFromPoint === elem || nodeContains(elem, elementFromPoint);
})) {
return true;
}
// shadow root
// filter unique elements with shadowRoot
// @ts-ignore
let elemsWithShadowRoot = [].concat(elementsFromPoint);
elemsWithShadowRoot = elemsWithShadowRoot.filter(function (x) {
return x && x.shadowRoot && x.shadowRoot.elementFromPoint;
});
// getOverlappingElements of every element with shadowRoot
let shadowElementsFromPoint = [];
for (let i = 0; i < elemsWithShadowRoot.length; ++i) {
const shadowElement = elemsWithShadowRoot[i];
shadowElementsFromPoint = shadowElementsFromPoint.concat(getOverlappingElements(elem, shadowElement.shadowRoot));
}
// remove duplicates and parents
// @ts-ignore
shadowElementsFromPoint = [].concat(shadowElementsFromPoint);
shadowElementsFromPoint = shadowElementsFromPoint.filter(function (x) {
return !elementsFromPoint.includes(x);
});
if (shadowElementsFromPoint.length === 0) {
return false;
}
return isOverlappingElementMatch(shadowElementsFromPoint, elem);
}
// copied from `isElementInViewport.js`
function isElementInViewport(elem) {
if (!elem.getBoundingClientRect) {
return false;
}
const rect = elem.getBoundingClientRect();
const windowHeight = (window.innerHeight || document.documentElement.clientHeight);
const windowWidth = (window.innerWidth || document.documentElement.clientWidth);
const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) > 0);
const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) > 0);
return (vertInView && horInView);
}
function isClickable(elem) {
return (isElementInViewport(elem) && elem.disabled !== true &&
isOverlappingElementMatch(getOverlappingElements(elem), elem));
}
// scroll to the element if it's not clickable
if (!isClickable(elem)) {
// works well in dialogs, but the element may be still overlapped by some sticky header/footer
elem.scrollIntoView(scrollIntoViewFullSupport ? { block: 'nearest', inline: 'nearest' } : false);
// if element is still not clickable take another scroll attempt
if (!isClickable(elem)) {
// scroll to element, try put it in the screen center.
// Should definitely work even if element was covered with sticky header/footer
elem.scrollIntoView(scrollIntoViewFullSupport ? { block: 'center', inline: 'center' } : true);
return isClickable(elem);
}
}
return true;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXNFbGVtZW50Q2xpY2thYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NjcmlwdHMvaXNFbGVtZW50Q2xpY2thYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsT0FBTyxVQUFVLGtCQUFrQixDQUFFLElBQWlCO0lBQ3pELElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLElBQUksQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUM5SCxPQUFPLEtBQUssQ0FBQTtJQUNoQixDQUFDO0lBRUQsb0NBQW9DO0lBQ3BDLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBRSxNQUFjLENBQUMsVUFBVSxDQUFBO0lBQzlDLHdFQUF3RTtJQUN4RSxNQUFNLHlCQUF5QixHQUFHLENBQUMsQ0FBRSxNQUFjLENBQUMsTUFBTSxJQUFJLFNBQVMsQ0FBQyxDQUFBO0lBRXhFLDBCQUEwQjtJQUMxQixTQUFTLHFCQUFxQixDQUFFLElBQWlCLEVBQUUsT0FBa0I7UUFDakUsT0FBTyxHQUFHLE9BQU8sSUFBSSxRQUFRLENBQUE7UUFDN0IsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUE7UUFDbEQsTUFBTSxDQUFDLEdBQUcsYUFBYSxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUE7UUFDckQsTUFBTSxDQUFDLEdBQUcsYUFBYSxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQyxDQUFDLENBQUE7UUFDckQsT0FBTyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3pDLENBQUM7SUFFRCwyREFBMkQ7SUFDM0Qs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