depending on existing nodes
-# ## but this shouldn't really matter that much, so ignore for now
-# # if elementToInsertAfter.tagName is 'P'
-# # typeOfNewElement = '
'
-# $newElement = $(outerNewElement).append(clonedElements)
-# $newElement.insertAfter(elementToInsertAfter)
-# newElement = $newElement.get(0)
-# if !newElement.innerHTML
-# newElement.innerHTML = '
'
-# range.selectNodeContents(newElement)
-# else
-# newTextNode = _getFirstTextNode(newElement)
-# range.selectNodeContents(newTextNode)
-# range.collapse(true)
-
-# _contenteditableMoveToEndOfPrevLine = (el) ->
-# bounds = _contenteditableGetNodesAround(el)
-# if bounds.prev
-# range = _getSelectionRangeByEl(el)
-# prevTextNode = _getInnerLastChild(bounds.prev)
-# range.setStart(prevTextNode, prevTextNode.length)
-# range.setEnd(prevTextNode, prevTextNode.length)
-
-# _contenteditableMoveToStartOfNextLine = (el) ->
-# bounds = _contenteditableGetNodesAround(el)
-# if bounds.next
-# range = _getSelectionRangeByEl(el)
-# nextTextNode = _getFirstTextNode(bounds.next)
-# range.setStart(nextTextNode, 1)
-# range.setEnd(nextTextNode, 1)
-
-# _contenteditableGetNodesAround = (el) ->
-# range = _getSelectionRangeByEl(el)
-# textNode = range.startContainer
-# curEl = textNode
-# while curEl && !curEl.nextSibling?
-# curEl = curEl.parentNode
-# nextTextNode = _getFirstTextNode(curEl.nextSibling)
-# curEl = textNode
-# while curEl && !curEl.previousSibling?
-# curEl = curEl.parentNode
-# prevTextNode = _getInnerLastChild(curEl.previousSibling)
-# {
-# prev: prevTextNode
-# next: nextTextNode
-# }
-
-# _getFirstTextNode = (el) ->
-# while (el.firstChild)
-# el = el.firstChild
-# return el
+ return $elements.callNativeMethod(this, "select");
+};
+
+//# Selection API implementation of insert newline.
+//# Worth keeping around if we ever have to insert native
+//# newlines if we are trying to support a browser or
+//# environment without the document.execCommand('insertText', etc...)
+//#
+// _insertNewlineIntoContentEditable = (el) ->
+// selection = _getSelectionByEl(el)
+// selection.deleteFromDocument()
+// $elements.callNativeMethod(selection, "modify", "extend", "forward", "lineboundary")
+// range = selection.getRangeAt(0)
+// clonedElements = range.cloneContents()
+// selection.deleteFromDocument()
+// elementToInsertAfter
+// if range.startContainer is el
+// elementToInsertAfter = _getInnerLastChild(el)
+// else
+// curEl = range.startContainer
+// ## make sure we have firstLevel child element from contentEditable
+// while (curEl.parentElement && curEl.parentElement isnt el )
+// curEl = curEl.parentElement
+// elementToInsertAfter = curEl
+// range = _getSelectionRangeByEl(el)
+// outerNewElement = '
or
depending on existing nodes
+// ## but this shouldn't really matter that much, so ignore for now
+// # if elementToInsertAfter.tagName is 'P'
+// # typeOfNewElement = '
'
+// $newElement = $(outerNewElement).append(clonedElements)
+// $newElement.insertAfter(elementToInsertAfter)
+// newElement = $newElement.get(0)
+// if !newElement.innerHTML
+// newElement.innerHTML = '
'
+// range.selectNodeContents(newElement)
+// else
+// newTextNode = _getFirstTextNode(newElement)
+// range.selectNodeContents(newTextNode)
+// range.collapse(true)
+
+// _contenteditableMoveToEndOfPrevLine = (el) ->
+// bounds = _contenteditableGetNodesAround(el)
+// if bounds.prev
+// range = _getSelectionRangeByEl(el)
+// prevTextNode = _getInnerLastChild(bounds.prev)
+// range.setStart(prevTextNode, prevTextNode.length)
+// range.setEnd(prevTextNode, prevTextNode.length)
+
+// _contenteditableMoveToStartOfNextLine = (el) ->
+// bounds = _contenteditableGetNodesAround(el)
+// if bounds.next
+// range = _getSelectionRangeByEl(el)
+// nextTextNode = _getFirstTextNode(bounds.next)
+// range.setStart(nextTextNode, 1)
+// range.setEnd(nextTextNode, 1)
+
+// _contenteditableGetNodesAround = (el) ->
+// range = _getSelectionRangeByEl(el)
+// textNode = range.startContainer
+// curEl = textNode
+// while curEl && !curEl.nextSibling?
+// curEl = curEl.parentNode
+// nextTextNode = _getFirstTextNode(curEl.nextSibling)
+// curEl = textNode
+// while curEl && !curEl.previousSibling?
+// curEl = curEl.parentNode
+// prevTextNode = _getInnerLastChild(curEl.previousSibling)
+// {
+// prev: prevTextNode
+// next: nextTextNode
+// }
+
+// _getFirstTextNode = (el) ->
+// while (el.firstChild)
+// el = el.firstChild
+// return el
module.exports = {
- getSelectionBounds
- deleteRightOfCursor
- deleteLeftOfCursor
- selectAll
- deleteSelectionContents
- moveSelectionToEnd
- getCaretPosition
- moveCursorLeft
- moveCursorRight
- moveCursorUp
- moveCursorDown
- replaceSelectionContents
- isCollapsed
+ getSelectionBounds,
+ deleteRightOfCursor,
+ deleteLeftOfCursor,
+ selectAll,
+ deleteSelectionContents,
+ moveSelectionToEnd,
+ getCaretPosition,
+ moveCursorLeft,
+ moveCursorRight,
+ moveCursorUp,
+ moveCursorDown,
+ replaceSelectionContents,
+ isCollapsed,
interceptSelect
-}
+};
diff --git a/packages/driver/src/dom/visibility.js b/packages/driver/src/dom/visibility.js
index dd0dc7e58e52..c84f430ad6ac 100644
--- a/packages/driver/src/dom/visibility.js
+++ b/packages/driver/src/dom/visibility.js
@@ -1,289 +1,321 @@
-_ = require("lodash")
-
-$jquery = require("./jquery")
-$document = require("./document")
-$elements = require("./elements")
-$coordinates = require("./coordinates")
-
-fixedOrAbsoluteRe = /(fixed|absolute)/
-
-OVERFLOW_PROPS = ["hidden", "scroll", "auto"]
-
-## WARNING:
-## developer beware. visibility is a sink hole
-## that leads to sheer madness. you should
-## avoid this file before its too late.
-
-isVisible = (el) ->
- not isHidden(el, "isVisible()")
-
-## TODO: we should prob update dom
-## to be passed in $utils as a dependency
-## because of circular references
-isHidden = (el, name) ->
- if not $elements.isElement(el)
- name ?= "isHidden()"
-
- throw new Error("Cypress.dom.#{name} must be passed a basic DOM element.")
-
- $el = $jquery.wrap(el)
-
- ## in Cypress-land we consider the element hidden if
- ## either its offsetHeight or offsetWidth is 0 because
- ## it is impossible for the user to interact with this element
- ## offsetHeight / offsetWidth includes the ef
- elHasNoEffectiveWidthOrHeight($el) or
-
- ## additionally if the effective visibility of the element
- ## is hidden (which includes any parent nodes) then the user
- ## cannot interact with this element and thus it is hidden
- elHasVisibilityHidden($el) or
-
- ## we do some calculations taking into account the parents
- ## to see if its hidden by a parent
- elIsHiddenByAncestors($el) or
-
- ## if this is a fixed element check if its covered
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS104: Avoid inline assignments
+ * DS204: Change includes calls to have a more natural evaluation order
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const _ = require("lodash");
+
+const $jquery = require("./jquery");
+const $document = require("./document");
+const $elements = require("./elements");
+const $coordinates = require("./coordinates");
+
+const fixedOrAbsoluteRe = /(fixed|absolute)/;
+
+const OVERFLOW_PROPS = ["hidden", "scroll", "auto"];
+
+//# WARNING:
+//# developer beware. visibility is a sink hole
+//# that leads to sheer madness. you should
+//# avoid this file before its too late.
+
+const isVisible = el => !isHidden(el, "isVisible()");
+
+//# TODO: we should prob update dom
+//# to be passed in $utils as a dependency
+//# because of circular references
+var isHidden = function(el, name) {
+ if (!$elements.isElement(el)) {
+ if (name == null) { name = "isHidden()"; }
+
+ throw new Error(`Cypress.dom.${name} must be passed a basic DOM element.`);
+ }
+
+ const $el = $jquery.wrap(el);
+
+ //# in Cypress-land we consider the element hidden if
+ //# either its offsetHeight or offsetWidth is 0 because
+ //# it is impossible for the user to interact with this element
+ //# offsetHeight / offsetWidth includes the ef
+ return elHasNoEffectiveWidthOrHeight($el) ||
+
+ //# additionally if the effective visibility of the element
+ //# is hidden (which includes any parent nodes) then the user
+ //# cannot interact with this element and thus it is hidden
+ elHasVisibilityHidden($el) ||
+
+ //# we do some calculations taking into account the parents
+ //# to see if its hidden by a parent
+ elIsHiddenByAncestors($el) ||
+
+ //# if this is a fixed element check if its covered
(
- if elIsFixed($el)
+ elIsFixed($el) ?
elIsNotElementFromPoint($el)
- else
- ## else check if el is outside the bounds
- ## of its ancestors overflow
+ :
+ //# else check if el is outside the bounds
+ //# of its ancestors overflow
elIsOutOfBoundsOfAncestorsOverflow($el)
- )
-
-elHasNoEffectiveWidthOrHeight = ($el) ->
- elOffsetWidth($el) <= 0 or elOffsetHeight($el) <= 0 or $el[0].getClientRects().length <= 0
-
-elHasNoOffsetWidthOrHeight = ($el) ->
- elOffsetWidth($el) <= 0 or elOffsetHeight($el) <= 0
-
-elOffsetWidth = ($el) ->
- $el[0].offsetWidth
-
-elOffsetHeight = ($el) ->
- $el[0].offsetHeight
-
-elHasVisibilityHidden = ($el) ->
- $el.css("visibility") is "hidden"
-
-elHasDisplayNone = ($el) ->
- $el.css("display") is "none"
-
-elHasOverflowHidden = ($el) ->
- "hidden" in [$el.css("overflow"), $el.css("overflow-y"), $el.css("overflow-x")]
-
-elHasPositionRelative = ($el) ->
- $el.css("position") is "relative"
-
-elHasClippableOverflow = ($el) ->
- $el.css("overflow") in OVERFLOW_PROPS or
- $el.css("overflow-y") in OVERFLOW_PROPS or
- $el.css("overflow-x") in OVERFLOW_PROPS
-
-canClipContent = ($el, $ancestor) ->
- ## can't clip without clippable overflow
- if not elHasClippableOverflow($ancestor)
- return false
-
- $offsetParent = $jquery.wrap($el[0].offsetParent)
-
- ## even if overflow is clippable, if an ancestor of the ancestor is the
- ## element's offset parent, the ancestor will not clip the element
- ## unless the element is position relative
- if not elHasPositionRelative($el) and $elements.isAncestor($ancestor, $offsetParent)
- return false
-
- return true
-
-elIsFixed = ($el) ->
- if $stickyOrFixedEl = $elements.getFirstFixedOrStickyPositionParent($el)
- $stickyOrFixedEl.css("position") is "fixed"
-
-elAtCenterPoint = ($el) ->
- elProps = $coordinates.getElementPositioning($el)
-
- { topCenter, leftCenter } = elProps.fromViewport
-
- doc = $document.getDocumentFromElement($el.get(0))
-
- if el = $coordinates.getElementAtPointFromViewport(doc, leftCenter, topCenter)
- $jquery.wrap(el)
-
-elDescendentsHavePositionFixedOrAbsolute = ($parent, $child) ->
- ## create an array of all elements between $parent and $child
- ## including child but excluding parent
- ## and check if these have position fixed|absolute
- $els = $child.parentsUntil($parent).add($child)
-
- _.some $els.get(), (el) ->
- fixedOrAbsoluteRe.test $jquery.wrap(el).css("position")
-
-elIsNotElementFromPoint = ($el) ->
- ## if we have a fixed position element that means
- ## it is fixed 'relative' to the viewport which means
- ## it MUST be available with elementFromPoint because
- ## that is also relative to the viewport
- $elAtPoint = elAtCenterPoint($el)
-
- ## if the element at point is not a descendent
- ## of our $el then we know it's being covered or its
- ## not visible
- return not $elements.isDescendent($el, $elAtPoint)
-
-elIsOutOfBoundsOfAncestorsOverflow = ($el, $ancestor) ->
- $ancestor ?= $el.parent()
-
- ## no ancestor, not out of bounds!
- return false if not $ancestor
-
- ## if we've reached the top parent, which is document
- ## then we're in bounds all the way up, return false
- return false if $ancestor.is("body,html") or $document.isDocument($ancestor)
-
- elProps = $coordinates.getElementPositioning($el)
-
- if canClipContent($el, $ancestor)
- ancestorProps = $coordinates.getElementPositioning($ancestor)
-
- ## target el is out of bounds
- return true if (
- ## target el is to the right of the ancestor's visible area
- elProps.fromWindow.left > (ancestorProps.width + ancestorProps.fromWindow.left) or
-
- ## target el is to the left of the ancestor's visible area
- (elProps.fromWindow.left + elProps.width) < ancestorProps.fromWindow.left or
-
- ## target el is under the ancestor's visible area
- elProps.fromWindow.top > (ancestorProps.height + ancestorProps.fromWindow.top) or
-
- ## target el is above the ancestor's visible area
- (elProps.fromWindow.top + elProps.height) < ancestorProps.fromWindow.top
- )
-
- elIsOutOfBoundsOfAncestorsOverflow($el, $ancestor.parent())
-
-elIsHiddenByAncestors = ($el, $origEl) ->
- ## store the original $el
- $origEl ?= $el
-
- ## walk up to each parent until we reach the body
- ## if any parent has an effective offsetHeight of 0
- ## and its set overflow: hidden then our child element
- ## is effectively hidden
- ## -----UNLESS------
- ## the parent or a descendent has position: absolute|fixed
- $parent = $el.parent()
-
- ## stop if we've reached the body or html
- ## in case there is no body
- ## or if parent is the document which can
- ## happen if we already have an element
- return false if $parent.is("body,html") or $document.isDocument($parent)
-
- if elHasOverflowHidden($parent) and elHasNoEffectiveWidthOrHeight($parent)
- ## if any of the elements between the parent and origEl
- ## have fixed or position absolute
- return not elDescendentsHavePositionFixedOrAbsolute($parent, $origEl)
-
- ## continue to recursively walk up the chain until we reach body or html
- elIsHiddenByAncestors($parent, $origEl)
+ );
+};
-parentHasNoOffsetWidthOrHeightAndOverflowHidden = ($el) ->
- ## if we've walked all the way up to body or html then return false
- return false if not $el.length or $el.is("body,html")
+var elHasNoEffectiveWidthOrHeight = $el => (elOffsetWidth($el) <= 0) || (elOffsetHeight($el) <= 0) || ($el[0].getClientRects().length <= 0);
- ## if we have overflow hidden and no effective width or height
- if elHasOverflowHidden($el) and elHasNoEffectiveWidthOrHeight($el)
- return $el
- else
- ## continue walking
- return parentHasNoOffsetWidthOrHeightAndOverflowHidden($el.parent())
+const elHasNoOffsetWidthOrHeight = $el => (elOffsetWidth($el) <= 0) || (elOffsetHeight($el) <= 0);
-parentHasDisplayNone = ($el) ->
- ## if we have no $el or we've walked all the way up to document
- ## then return false
- return false if not $el.length or $document.isDocument($el)
+var elOffsetWidth = $el => $el[0].offsetWidth;
- ## if we have display none then return the $el
- if elHasDisplayNone($el)
- return $el
- else
- ## continue walking
- return parentHasDisplayNone($el.parent())
-
-parentHasVisibilityNone = ($el) ->
- ## if we've walked all the way up to document then return false
- return false if not $el.length or $document.isDocument($el)
+var elOffsetHeight = $el => $el[0].offsetHeight;
- ## if we have display none then return the $el
- if elHasVisibilityHidden($el)
- return $el
- else
- ## continue walking
- return parentHasVisibilityNone($el.parent())
+var elHasVisibilityHidden = $el => $el.css("visibility") === "hidden";
-getReasonIsHidden = ($el) ->
- ## TODO: need to add in the reason an element
- ## is hidden when its fixed position and its
- ## either being covered or there is no el
+const elHasDisplayNone = $el => $el.css("display") === "none";
- node = $elements.stringify($el, "short")
+const elHasOverflowHidden = function($el) {
+ let needle;
+ return (needle = "hidden", [$el.css("overflow"), $el.css("overflow-y"), $el.css("overflow-x")].includes(needle));
+};
- ## returns the reason in human terms why an element is considered not visible
- switch
- when elHasDisplayNone($el)
- "This element '#{node}' is not visible because it has CSS property: 'display: none'"
+const elHasPositionRelative = $el => $el.css("position") === "relative";
- when $parent = parentHasDisplayNone($el.parent())
- parentNode = $elements.stringify($parent, "short")
+const elHasClippableOverflow = function($el) {
+ let needle, needle1, needle2;
+ return (needle = $el.css("overflow"), OVERFLOW_PROPS.includes(needle)) ||
+ (needle1 = $el.css("overflow-y"), OVERFLOW_PROPS.includes(needle1)) ||
+ (needle2 = $el.css("overflow-x"), OVERFLOW_PROPS.includes(needle2));
+};
- "This element '#{node}' is not visible because its parent '#{parentNode}' has CSS property: 'display: none'"
+const canClipContent = function($el, $ancestor) {
+ //# can't clip without clippable overflow
+ if (!elHasClippableOverflow($ancestor)) {
+ return false;
+ }
- when $parent = parentHasVisibilityNone($el.parent())
- parentNode = $elements.stringify($parent, "short")
+ const $offsetParent = $jquery.wrap($el[0].offsetParent);
- "This element '#{node}' is not visible because its parent '#{parentNode}' has CSS property: 'visibility: hidden'"
+ //# even if overflow is clippable, if an ancestor of the ancestor is the
+ //# element's offset parent, the ancestor will not clip the element
+ //# unless the element is position relative
+ if (!elHasPositionRelative($el) && $elements.isAncestor($ancestor, $offsetParent)) {
+ return false;
+ }
- when elHasVisibilityHidden($el)
- "This element '#{node}' is not visible because it has CSS property: 'visibility: hidden'"
-
- when elHasNoOffsetWidthOrHeight($el)
- width = elOffsetWidth($el)
- height = elOffsetHeight($el)
-
- "This element '#{node}' is not visible because it has an effective width and height of: '#{width} x #{height}' pixels."
+ return true;
+};
- when $parent = parentHasNoOffsetWidthOrHeightAndOverflowHidden($el.parent())
- parentNode = $elements.stringify($parent, "short")
- width = elOffsetWidth($parent)
- height = elOffsetHeight($parent)
-
- "This element '#{node}' is not visible because its parent '#{parentNode}' has CSS property: 'overflow: hidden' and an effective width and height of: '#{width} x #{height}' pixels."
+var elIsFixed = function($el) {
+ let $stickyOrFixedEl;
+ if ($stickyOrFixedEl = $elements.getFirstFixedOrStickyPositionParent($el)) {
+ return $stickyOrFixedEl.css("position") === "fixed";
+ }
+};
- else
- ## nested else --___________--
- if elIsFixed($el)
- if elIsNotElementFromPoint($el)
- ## show the long element here
- covered = $elements.stringify(elAtCenterPoint($el))
-
- return """
- This element '#{node}' is not visible because it has CSS property: 'position: fixed' and its being covered by another element:
-
- #{covered}
- """
- else
- if elIsOutOfBoundsOfAncestorsOverflow($el)
- return "This element '#{node}' is not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: 'hidden', 'scroll' or 'auto'"
+const elAtCenterPoint = function($el) {
+ let el;
+ const elProps = $coordinates.getElementPositioning($el);
- return "Cypress could not determine why this element '#{node}' is not visible."
+ const { topCenter, leftCenter } = elProps.fromViewport;
+
+ const doc = $document.getDocumentFromElement($el.get(0));
+
+ if (el = $coordinates.getElementAtPointFromViewport(doc, leftCenter, topCenter)) {
+ return $jquery.wrap(el);
+ }
+};
+
+const elDescendentsHavePositionFixedOrAbsolute = function($parent, $child) {
+ //# create an array of all elements between $parent and $child
+ //# including child but excluding parent
+ //# and check if these have position fixed|absolute
+ const $els = $child.parentsUntil($parent).add($child);
+
+ return _.some($els.get(), el => fixedOrAbsoluteRe.test($jquery.wrap(el).css("position")));
+};
+
+var elIsNotElementFromPoint = function($el) {
+ //# if we have a fixed position element that means
+ //# it is fixed 'relative' to the viewport which means
+ //# it MUST be available with elementFromPoint because
+ //# that is also relative to the viewport
+ const $elAtPoint = elAtCenterPoint($el);
+
+ //# if the element at point is not a descendent
+ //# of our $el then we know it's being covered or its
+ //# not visible
+ return !$elements.isDescendent($el, $elAtPoint);
+};
+
+var elIsOutOfBoundsOfAncestorsOverflow = function($el, $ancestor) {
+ if ($ancestor == null) { $ancestor = $el.parent(); }
+
+ //# no ancestor, not out of bounds!
+ if (!$ancestor) { return false; }
+
+ //# if we've reached the top parent, which is document
+ //# then we're in bounds all the way up, return false
+ if ($ancestor.is("body,html") || $document.isDocument($ancestor)) { return false; }
+
+ const elProps = $coordinates.getElementPositioning($el);
+
+ if (canClipContent($el, $ancestor)) {
+ const ancestorProps = $coordinates.getElementPositioning($ancestor);
+
+ //# target el is out of bounds
+ if (
+ //# target el is to the right of the ancestor's visible area
+ (elProps.fromWindow.left > (ancestorProps.width + ancestorProps.fromWindow.left)) ||
+
+ //# target el is to the left of the ancestor's visible area
+ ((elProps.fromWindow.left + elProps.width) < ancestorProps.fromWindow.left) ||
+
+ //# target el is under the ancestor's visible area
+ (elProps.fromWindow.top > (ancestorProps.height + ancestorProps.fromWindow.top)) ||
+
+ //# target el is above the ancestor's visible area
+ ((elProps.fromWindow.top + elProps.height) < ancestorProps.fromWindow.top)
+ ) { return true; }
+ }
+
+ return elIsOutOfBoundsOfAncestorsOverflow($el, $ancestor.parent());
+};
+
+var elIsHiddenByAncestors = function($el, $origEl) {
+ //# store the original $el
+ if ($origEl == null) { $origEl = $el; }
+
+ //# walk up to each parent until we reach the body
+ //# if any parent has an effective offsetHeight of 0
+ //# and its set overflow: hidden then our child element
+ //# is effectively hidden
+ //# -----UNLESS------
+ //# the parent or a descendent has position: absolute|fixed
+ const $parent = $el.parent();
+
+ //# stop if we've reached the body or html
+ //# in case there is no body
+ //# or if parent is the document which can
+ //# happen if we already have an element
+ if ($parent.is("body,html") || $document.isDocument($parent)) { return false; }
+
+ if (elHasOverflowHidden($parent) && elHasNoEffectiveWidthOrHeight($parent)) {
+ //# if any of the elements between the parent and origEl
+ //# have fixed or position absolute
+ return !elDescendentsHavePositionFixedOrAbsolute($parent, $origEl);
+ }
+
+ //# continue to recursively walk up the chain until we reach body or html
+ return elIsHiddenByAncestors($parent, $origEl);
+};
+
+var parentHasNoOffsetWidthOrHeightAndOverflowHidden = function($el) {
+ //# if we've walked all the way up to body or html then return false
+ if (!$el.length || $el.is("body,html")) { return false; }
+
+ //# if we have overflow hidden and no effective width or height
+ if (elHasOverflowHidden($el) && elHasNoEffectiveWidthOrHeight($el)) {
+ return $el;
+ } else {
+ //# continue walking
+ return parentHasNoOffsetWidthOrHeightAndOverflowHidden($el.parent());
+ }
+};
+
+var parentHasDisplayNone = function($el) {
+ //# if we have no $el or we've walked all the way up to document
+ //# then return false
+ if (!$el.length || $document.isDocument($el)) { return false; }
+
+ //# if we have display none then return the $el
+ if (elHasDisplayNone($el)) {
+ return $el;
+ } else {
+ //# continue walking
+ return parentHasDisplayNone($el.parent());
+ }
+};
+
+var parentHasVisibilityNone = function($el) {
+ //# if we've walked all the way up to document then return false
+ if (!$el.length || $document.isDocument($el)) { return false; }
+
+ //# if we have display none then return the $el
+ if (elHasVisibilityHidden($el)) {
+ return $el;
+ } else {
+ //# continue walking
+ return parentHasVisibilityNone($el.parent());
+ }
+};
+
+const getReasonIsHidden = function($el) {
+ //# TODO: need to add in the reason an element
+ //# is hidden when its fixed position and its
+ //# either being covered or there is no el
+
+ let $parent;
+ const node = $elements.stringify($el, "short");
+
+ //# returns the reason in human terms why an element is considered not visible
+ switch (false) {
+ case !elHasDisplayNone($el):
+ return `This element '${node}' is not visible because it has CSS property: 'display: none'`;
+
+ case !($parent = parentHasDisplayNone($el.parent())):
+ var parentNode = $elements.stringify($parent, "short");
+
+ return `This element '${node}' is not visible because its parent '${parentNode}' has CSS property: 'display: none'`;
+
+ case !($parent = parentHasVisibilityNone($el.parent())):
+ parentNode = $elements.stringify($parent, "short");
+
+ return `This element '${node}' is not visible because its parent '${parentNode}' has CSS property: 'visibility: hidden'`;
+
+ case !elHasVisibilityHidden($el):
+ return `This element '${node}' is not visible because it has CSS property: 'visibility: hidden'`;
+
+ case !elHasNoOffsetWidthOrHeight($el):
+ var width = elOffsetWidth($el);
+ var height = elOffsetHeight($el);
+
+ return `This element '${node}' is not visible because it has an effective width and height of: '${width} x ${height}' pixels.`;
+
+ case !($parent = parentHasNoOffsetWidthOrHeightAndOverflowHidden($el.parent())):
+ parentNode = $elements.stringify($parent, "short");
+ width = elOffsetWidth($parent);
+ height = elOffsetHeight($parent);
+
+ return `This element '${node}' is not visible because its parent '${parentNode}' has CSS property: 'overflow: hidden' and an effective width and height of: '${width} x ${height}' pixels.`;
+
+ default:
+ //# nested else --___________--
+ if (elIsFixed($el)) {
+ if (elIsNotElementFromPoint($el)) {
+ //# show the long element here
+ const covered = $elements.stringify(elAtCenterPoint($el));
+
+ return `\
+This element '${node}' is not visible because it has CSS property: 'position: fixed' and its being covered by another element:
+
+${covered}\
+`;
+ }
+ } else {
+ if (elIsOutOfBoundsOfAncestorsOverflow($el)) {
+ return `This element '${node}' is not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: 'hidden', 'scroll' or 'auto'`;
+ }
+ }
+
+ return `Cypress could not determine why this element '${node}' is not visible.`;
+ }
+};
module.exports = {
- isVisible
+ isVisible,
- isHidden
+ isHidden,
getReasonIsHidden
-}
+};
diff --git a/packages/driver/src/dom/window.js b/packages/driver/src/dom/window.js
index d99035f0a410..a148a3126d09 100644
--- a/packages/driver/src/dom/window.js
+++ b/packages/driver/src/dom/window.js
@@ -1,30 +1,41 @@
-$jquery = require("./jquery")
-$document = require("./document")
-
-getWindowByElement = (el) ->
- if isWindow(el)
- return el
-
- doc = $document.getDocumentFromElement(el)
- getWindowByDocument(doc)
-
-getWindowByDocument = (doc) ->
- ## parentWindow for IE
- doc.defaultView or doc.parentWindow
-
-isWindow = (obj) ->
- try
- if $jquery.isJquery(obj)
- obj = obj[0]
-
- Boolean(obj and obj.window is obj)
- catch
- false
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const $jquery = require("./jquery");
+const $document = require("./document");
+
+const getWindowByElement = function(el) {
+ if (isWindow(el)) {
+ return el;
+ }
+
+ const doc = $document.getDocumentFromElement(el);
+ return getWindowByDocument(doc);
+};
+
+var getWindowByDocument = doc =>
+ //# parentWindow for IE
+ doc.defaultView || doc.parentWindow
+;
+
+var isWindow = function(obj) {
+ try {
+ if ($jquery.isJquery(obj)) {
+ obj = obj[0];
+ }
+
+ return Boolean(obj && (obj.window === obj));
+ } catch (error) {
+ return false;
+ }
+};
module.exports = {
- getWindowByElement
+ getWindowByElement,
- getWindowByDocument
+ getWindowByDocument,
isWindow
-}
+};