Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: visibility issue with parent absolute #29689

Merged
merged 43 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d2ffbec
fix 28638
senpl Jun 17, 2024
46e07c0
fix changelog
senpl Jun 17, 2024
72b37f6
changelog update as required by pipeline
senpl Jun 17, 2024
1366587
pipeline changelog fix2
senpl Jun 17, 2024
a7d3b83
Merge branch 'develop' into issue-28638-parentAbsolute
jennifer-shehane Jun 21, 2024
9494a26
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jun 27, 2024
43e3b62
changelog for pipeline
senpl Jun 27, 2024
d206d96
test fixes
senpl Jun 27, 2024
a5e7b11
fix only for firefox. coz in firefox position relative not detected a…
senpl Jun 27, 2024
e4eaa52
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jun 28, 2024
c5548ee
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 1, 2024
b7aba89
fix to go back to previous extra spaces
senpl Jul 2, 2024
d8a11d1
Merge branch 'issue-28638-parentAbsolute' of https://github.com/senpl…
senpl Jul 2, 2024
53aeba9
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 2, 2024
9749a4d
fix pipeline
senpl Jul 2, 2024
95db079
changelog new
senpl Jul 2, 2024
d1c658f
changelog cleanup
senpl Jul 2, 2024
ca8da1b
pipeline tests fix
senpl Jul 2, 2024
bb57298
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 3, 2024
2d1c953
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 8, 2024
6af9ba6
Merge branch 'develop' into issue-28638-parentAbsolute
jennifer-shehane Jul 8, 2024
c34636c
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 11, 2024
90d4f6a
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 12, 2024
de42b7d
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 25, 2024
07f5b2c
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Jul 26, 2024
397b5c1
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Aug 7, 2024
595dc90
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Aug 8, 2024
51e9113
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Aug 12, 2024
4b82d6f
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Aug 16, 2024
b1ce61f
Merge branch 'develop' into issue-28638-parentAbsolute
senpl Sep 30, 2024
5f8714a
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
senpl Oct 28, 2024
2fbc79f
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
jennifer-shehane Oct 29, 2024
e242703
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
senpl Oct 30, 2024
9d31e48
changelog fix
senpl Oct 30, 2024
50ab0df
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
jennifer-shehane Nov 6, 2024
2a0bf4a
updates
mschile Nov 26, 2024
32f8b5d
removing files
mschile Nov 26, 2024
97950dd
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
mschile Nov 26, 2024
c78d180
update
mschile Nov 26, 2024
be2129a
Update cli/CHANGELOG.md
mschile Dec 2, 2024
8030f25
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
mschile Dec 2, 2024
056c410
Merge branch 'release/14.0.0' into issue-28638-parentAbsolute
mschile Dec 2, 2024
926a5de
Update CHANGELOG.md
mschile Dec 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ in this [GitHub issue](https://github.com/cypress-io/cypress/issues/30447). Addr

- Elements with `display: contents` will no longer use box model calculations for visibility, and correctly show as visible when it is visible. Fixed in [#29680](https://github.com/cypress-io/cypress/pull/29680). Fixes [#29605](https://github.com/cypress-io/cypress/issues/29605).
- The CSS pseudo-class `:dir()` is now supported when testing in Electron. Addresses [#29766](https://github.com/cypress-io/cypress/issues/29766).
- Fixed a visibility issue when the element is positioned `static` or `relative` and the element's offset parent is positioned `absolute`, a descendent of the ancestor, and has no clippable overflow. Fixed in [#29689](https://github.com/cypress-io/cypress/pull/29689). Fixes [#28638](https://github.com/cypress-io/cypress/issues/28638).
- Fixed a visibility issue for elements with `textContent` but without a width or height. Fixed in [#29688](https://github.com/cypress-io/cypress/pull/29688). Fixes [#29687](https://github.com/cypress-io/cypress/issues/29687).
- Elements whose parent elements has `overflow: clip` and no height/width will now correctly show as hidden. Fixed in [#29778](https://github.com/cypress-io/cypress/pull/29778). Fixes [#23852](https://github.com/cypress-io/cypress/issues/23852).

Expand Down Expand Up @@ -96,7 +97,6 @@ _Released 11/5/2024_
- Updated `mobx` from `5.15.4` to `6.13.5` and `mobx-react` from `6.1.8` to `9.1.1`. Addresses [#30509](https://github.com/cypress-io/cypress/issues/30509).
- Updated `@cypress/request` from `3.0.4` to `3.0.6`. Addressed in [#30488](https://github.com/cypress-io/cypress/pull/30488).


## 13.15.1

_Released 10/24/2024_
Expand Down
52 changes: 51 additions & 1 deletion packages/driver/cypress/e2e/dom/visibility.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ describe('src/cypress/dom/visibility', () => {
context('hidden/visible overrides', () => {
beforeEach(function () {
// ensure all tests run against a scrollable window
const scrollThisIntoView = add('<div style=`height: 1000px;`></div><div>Should be in view</div>')
const scrollThisIntoView = add('<div style="height: 1000px;"></div><div>Should be in view</div>')

this.$visHidden = add('<ul style="visibility: hidden;"></ul>')
this.$parentVisHidden = add('<div class="invis" style="visibility: hidden;"><button>parent visibility: hidden</button></div>')
Expand Down Expand Up @@ -997,6 +997,56 @@ describe('src/cypress/dom/visibility', () => {
it('is visible when parent is relatively positioned out of bounds but el is relatively positioned back in bounds', function () {
expect(this.$parentOutOfBoundsButElInBounds.find('span')).to.be.visible
})

it('is visible when element is statically positioned and parent element is absolutely positioned and ancestor has overflow hidden', function () {
const add = (el) => {
return $(el).appendTo(cy.$$('body'))
}

cy.$$('body').empty()

const el = add(`
<div id="breaking-container" style="overflow: hidden">
<div>
<div style="position: absolute; bottom: 5px">
<button id="visible-button">Try me</button>
</div>
</div>
</div>
`)

expect(el.find('#visible-button')).to.be.visible
})

it('is visible when element is relatively positioned and parent element is absolutely positioned and ancestor has overflow auto', function () {
const add = (el) => {
return $(el).appendTo(cy.$$('body'))
}

cy.$$('body').empty()

const el = add(`
<div style="height: 200px; position: relative; display: flex">
<div style="border: 5px solid red">
<div
id="breaking-container"
style="overflow: auto; border: 5px solid green"
>
<div>
<h1>Example</h1>
<div style="position: absolute; bottom: 5px">
<button id="visible-button" style="position: relative">
Try me
</button>
</div>
</div>
</div>
</div>
</div>
`)

expect(el.find('#visible-button')).to.be.visible
})
})

describe('css clip-path', () => {
Expand Down
48 changes: 44 additions & 4 deletions packages/driver/cypress/e2e/dom/visibility_shadow_dom.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ export {} // make typescript see this as a module
const { $ } = Cypress

describe('src/cypress/dom/visibility - shadow dom', () => {
let add
let add: (el: string, shadowEl: string, rootIdentifier: string) => JQuery<HTMLElement>

beforeEach(() => {
cy.visit('/fixtures/empty.html').then((win) => {
win.customElements.define('shadow-root', class extends win.HTMLElement {
constructor () {
super()

// @ts-ignore
this.attachShadow({ mode: 'open' })
this.style.display = 'block'
}
Expand All @@ -20,8 +19,7 @@ describe('src/cypress/dom/visibility - shadow dom', () => {
add = (el, shadowEl, rootIdentifier) => {
const $el = $(el).appendTo(cy.$$('body'))

// @ts-ignore
$(shadowEl).appendTo(cy.$$(rootIdentifier)[0].shadowRoot)
$(shadowEl).appendTo(cy.$$(rootIdentifier)[0].shadowRoot!)

return $el
}
Expand Down Expand Up @@ -574,6 +572,48 @@ describe('src/cypress/dom/visibility - shadow dom', () => {
cy.wrap($outsideParentOutOfBoundsButElInBounds).find('span', { includeShadowDom: true }).should('be.visible')
cy.wrap($outsideParentOutOfBoundsButElInBounds).find('span', { includeShadowDom: true }).should('not.be.hidden')
})

it('is visible when element is statically positioned and parent element is absolutely positioned and ancestor has overflow hidden', function () {
const el = add(
`<div id="breaking-container" style="overflow: hidden">
<div>
<shadow-root id="shadow"></shadow-root>
</div>
</div>`,
`<div style="position: absolute; bottom: 5px">
<button id="visible-button">Try me</button>
</div>`,
'#shadow',
)

cy.wrap(el).find('#visible-button', { includeShadowDom: true }).should('be.visible')
cy.wrap(el).find('#visible-button', { includeShadowDom: true }).should('not.be.hidden')
})

it('is visible when element is relatively positioned and parent element is absolutely positioned and ancestor has overflow auto', function () {
const el = add(
`<div style="height: 200px; position: relative; display: flex">
<div style="border: 5px solid red">
<div
id="breaking-container"
style="overflow: auto; border: 5px solid green"
>
<div>
<h1>Example</h1>
<shadow-root id="shadow"></shadow-root>
</div>
</div>
</div>
</div>`,
`<div style="position: absolute; bottom: 5px">
<button id="visible-button">Try me</button>
</div>`,
'#shadow',
)

cy.wrap(el).find('#visible-button', { includeShadowDom: true }).should('be.visible')
cy.wrap(el).find('#visible-button', { includeShadowDom: true }).should('not.be.hidden')
})
})

describe('css transform', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/dom/coordinates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import $window from './window'
import $elements from './elements'
import $jquery from './jquery'

const getElementAtPointFromViewport = (doc, x, y) => {
const getElementAtPointFromViewport = (doc: Document, x: number, y: number) => {
return $elements.elementFromPoint(doc, x, y)
}

Expand Down
8 changes: 4 additions & 4 deletions packages/driver/src/dom/elements/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,11 @@ export const elementFromPoint = (doc, x, y): HTMLElement => {
* By DOM Hierarchy
* Compares two elements to see what their relationship is
*/
export const isAncestor = ($el, $maybeAncestor) => {
export const isAncestor = ($el: JQuery<HTMLElement>, $maybeAncestor: JQuery<HTMLElement>) => {
return $jquery.wrap(getAllParents($el[0])).index($maybeAncestor) >= 0
}

export const isChild = ($el, $maybeChild) => {
export const isChild = ($el: JQuery<HTMLElement>, $maybeChild: JQuery<HTMLElement>) => {
let children = $el.children()

if (children.length && children[0].nodeName === 'SHADOW-ROOT') {
Expand All @@ -185,7 +185,7 @@ export const isChild = ($el, $maybeChild) => {
return children.index($maybeChild) >= 0
}

export const isDescendent = ($el1, $el2) => {
export const isDescendent = ($el1: JQuery<HTMLElement>, $el2?: JQuery<HTMLElement>) => {
if (!$el2) {
return false
}
Expand Down Expand Up @@ -328,7 +328,7 @@ export const getContainsSelector = (text, filter = '', options: {
return selectors.join()
}

export const getInputFromLabel = ($el) => {
export const getInputFromLabel = ($el: JQuery<HTMLElement>) => {
if (!$el.is('label')) {
return $([])
}
Expand Down
35 changes: 23 additions & 12 deletions packages/driver/src/dom/visibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,15 @@ const elHasOverflowHidden = function ($el) {
return cssOverflow.includes('hidden')
}

const elHasPositionRelative = ($el) => {
const elHasPositionRelative = ($el: JQuery<HTMLElement>) => {
return $el.css('position') === 'relative'
}

const elHasPositionAbsolute = ($el) => {
const elHasPositionStatic = ($el: JQuery<HTMLElement>) => {
return $el.css('position') == null || $el.css('position') === 'static'
}

const elHasPositionAbsolute = ($el: JQuery<HTMLElement>) => {
return $el.css('position') === 'absolute'
}

Expand All @@ -220,13 +224,12 @@ const elHasClippableOverflow = function ($el) {
OVERFLOW_PROPS.includes($el.css('overflow-x'))
}

const canClipContent = function ($el, $ancestor) {
const canClipContent = function ($el: JQuery<HTMLElement>, $ancestor: JQuery<HTMLElement>) {
// can't clip without overflow properties
if (!elHasClippableOverflow($ancestor)) {
return false
}

// fix for 29605 - display: contents
if (elHasDisplayContents($ancestor)) {
return false
}
Expand All @@ -248,11 +251,21 @@ const canClipContent = function ($el, $ancestor) {

// even if ancestors' overflow is clippable, if the element's offset parent
// is a child of the ancestor, the ancestor will not clip the element
// unless the ancestor has position absolute
// unless the ancestor has a position that is not absolute
if (elHasPositionAbsolute($offsetParent) && isChild($ancestor, $offsetParent)) {
return false
}

// even if ancestors' overflow is clippable,
// if the element is position static or relative,
// and the element's offset parent is positioned absolute, a descendent of the ancestor, and has no clippable overflow,
// then the ancestor will not clip the element
if ((elHasPositionStatic($el) || elHasPositionRelative($el))
&& elHasPositionAbsolute($offsetParent) && isDescendent($ancestor, $offsetParent) && !elHasClippableOverflow($offsetParent)
) {
return false
}

return true
}

Expand All @@ -266,8 +279,7 @@ export const isW3CFocusable = (el) => {
return isFocusable(wrap(el)) && isW3CRendered(el)
}

// @ts-ignore
const elAtCenterPoint = function ($el) {
const elAtCenterPoint = function ($el: JQuery<HTMLElement>) {
const doc = $document.getDocumentFromElement($el.get(0))
const elProps = $coordinates.getElementPositioning($el)

Expand All @@ -278,6 +290,8 @@ const elAtCenterPoint = function ($el) {
if (el) {
return $jquery.wrap(el)
}

return undefined
}

const elDescendentsHavePositionFixedOrAbsolute = function ($parent, $child) {
Expand All @@ -298,7 +312,7 @@ const elHasVisibleChild = function ($el) {
})
}

const elIsNotElementFromPoint = function ($el) {
const elIsNotElementFromPoint = function ($el: JQuery<HTMLElement>) {
// 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
Expand Down Expand Up @@ -333,7 +347,6 @@ const elIsOutOfBoundsOfAncestorsOverflow = function ($el: JQuery<any>, $ancestor
return false
}

// fix for 29605 - display: contents
mschile marked this conversation as resolved.
Show resolved Hide resolved
if (elHasDisplayContents($el)) {
return false
}
Expand Down Expand Up @@ -400,8 +413,7 @@ const elIsHiddenByAncestors = function ($el, checkOpacity, $origEl = $el) {
}

if (elHasOverflowHidden($parent) && !elHasDisplayContents($parent) && elHasNoEffectiveWidthOrHeight($parent)) {
// if any of the elements between the parent and origEl
// have fixed or position absolute
// if any of the elements between the parent and origEl have fixed or position absolute
return !elDescendentsHavePositionFixedOrAbsolute($parent, $origEl)
}

Expand Down Expand Up @@ -564,7 +576,6 @@ export const getReasonIsHidden = function ($el, options = { checkOpacity: true }
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.`
}

// nested else --___________--
if (elOrAncestorIsFixedOrSticky($el)) {
if (elIsNotElementFromPoint($el)) {
// show the long element here
Expand Down