UNPKG

webdriverio

Version:

Next-gen browser and mobile automation test framework for Node.js

110 lines (109 loc) 4.35 kB
// src/scripts/isElementClickable.ts function isElementClickable(elem) { if (!elem.getBoundingClientRect || !elem.scrollIntoView || !elem.contains || !elem.getClientRects || !document.elementFromPoint) { return false; } const isOldEdge = !!window.StyleMedia; const scrollIntoViewFullSupport = !(window.safari || isOldEdge); function getOverlappingElement(elem2, context) { context = context || document; const elemDimension = elem2.getBoundingClientRect(); const x = elemDimension.left + elem2.clientWidth / 2; const y = elemDimension.top + elem2.clientHeight / 2; return context.elementFromPoint(x, y); } function getOverlappingRects(elem2, context) { context = context || document; const rects = elem2.getClientRects(); const rect = rects[0]; const x = rect.left + rect.width / 2; const y = rect.top + rect.height / 2; return [context.elementFromPoint(x, y)]; } function getOverlappingElements(elem2, context) { return [getOverlappingElement(elem2, context)].concat(getOverlappingRects(elem2, context)); } function nodeContains(elem2, otherNode) { if (isOldEdge) { let tmpElement = otherNode; while (tmpElement) { if (tmpElement === elem2) { return true; } tmpElement = tmpElement.parentNode; if (tmpElement && tmpElement.nodeType === 11 && tmpElement.host) { tmpElement = tmpElement.host; } } return false; } return elem2.contains(otherNode); } function isOverlappingElementMatch(elementsFromPoint, elem2) { if (elementsFromPoint.some(function(elementFromPoint) { return elementFromPoint === elem2 || nodeContains(elem2, elementFromPoint); })) { return true; } let elemsWithShadowRoot = [].concat(elementsFromPoint); elemsWithShadowRoot = elemsWithShadowRoot.filter(function(x) { return x && x.shadowRoot && x.shadowRoot.elementFromPoint; }); let shadowElementsFromPoint = []; for (let i = 0; i < elemsWithShadowRoot.length; ++i) { const shadowElement = elemsWithShadowRoot[i]; shadowElementsFromPoint = shadowElementsFromPoint.concat( getOverlappingElements(elem2, shadowElement.shadowRoot) ); } shadowElementsFromPoint = [].concat(shadowElementsFromPoint); shadowElementsFromPoint = shadowElementsFromPoint.filter(function(x) { return !elementsFromPoint.includes(x); }); if (shadowElementsFromPoint.length === 0) { return false; } return isOverlappingElementMatch(shadowElementsFromPoint, elem2); } function isElementInViewport(elem2) { if (!elem2.getBoundingClientRect) { return false; } const rect = elem2.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 isEnabled(elem2) { return elem2.disabled !== true; } function hasOverlaps(elem2) { return !isOverlappingElementMatch(getOverlappingElements(elem2), elem2); } function isFullyDisplayedInViewport(elem2) { return isElementInViewport(elem2) && !hasOverlaps(elem2); } function getViewportScrollPositions() { return { // Cross-browser compatibility x: window.scrollX !== null && window.scrollX !== void 0 ? window.scrollX : window.pageXOffset, y: window.scrollY !== null && window.scrollY !== void 0 ? window.scrollY : window.pageYOffset }; } let _isFullyDisplayedInViewport = isFullyDisplayedInViewport(elem); if (!_isFullyDisplayedInViewport) { const { x: originalX, y: originalY } = getViewportScrollPositions(); elem.scrollIntoView(scrollIntoViewFullSupport ? { block: "center", inline: "center" } : false); _isFullyDisplayedInViewport = isFullyDisplayedInViewport(elem); const { x: currentX, y: currentY } = getViewportScrollPositions(); if (currentX !== originalX || currentY !== originalY) { window.scroll(originalX, originalY); } } return _isFullyDisplayedInViewport && isEnabled(elem); } export { isElementClickable as default };