-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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: #29093 for elements with length in rem #29224
The head ref may contain hidden characters: "issue-29093-fix-Visible-elements-are-\"not-visible\"-for-Cypress"
fix: #29093 for elements with length in rem #29224
Conversation
|
…-visible"-for-Cypress
changelog update
fix pipeline bug
fix pipeline for line2
fix pipeline3
@senpl Thanks! Can you add a test around this new behavior? There is a Contributing Guide that covers how to contribute and get Cypress running locally in generally here: https://github.com/cypress-io/cypress/blob/develop/.github/CONTRIBUTING.md Here's an example of another issue's test code:
To run the tests:
Instructions for running the |
…-visible"-for-Cypress
…-visible"-for-Cypress
…-visible"-for-Cypress
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I manually tested the change against the 3 examples this is expected to fix. It does fix them.
There are some other tests failing however, so it looks like this logic has broken some other visibility checks:
I had some concern around performance of this, and whether this would mean slower performance. Running benchmarks against offsetWidth
vs getBoundingClientRect
seem to indicate that getBoundingClientRect
is actually faster.
Before
After
pipeline speed improvement
…-visible"-for-Cypress
…-visible"-for-Cypress
id for precise locator gind
…-visible"-for-Cypress
@@ -117,10 +117,10 @@ describe('FileRow', () => { | |||
cy.contains(changesRequiredDescription).should('be.visible') | |||
cy.get('pre').should('have.length', 2) | |||
|
|||
cy.get('.shiki').should('be.visible') | |||
cy.get('div.rounded > div.text-left.cursor-text').should('be.visible') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @senpl ,
There are two .shiki
elements in this component. One of them is always hidden, and one of them that should show/hide on click. The hidden state for this element is caused by a parent element with maxHeight of 0, and overflow:hidden.
I do agree that the .shiki
selector here should be more specific. I edited it to assert the expected visibility state of both elements:
// A FileRow with status=valid should not be initially open
cy.get('[data-cy=valid] .shiki').should('not.be.visible')
// A FileRow with status=changes should be initially open
cy.get('[data-cy=changes] .shiki').should('be.visible')
// Clicking the header should collapse the shiki code view in the FileRow
cy.contains('cypress/integration/command.js').click()
cy.get('[data-cy=valid] .shiki').should('not.be.visible')
cy.get('[data-cy=changes] .shiki').should('not.be.visible')
Unfortunately, while this test passes on the develop
, it does not pass with the visibility changes in this branch. Can you look into why?
Thank you!
…-visible"-for-Cypress
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the issue being tested in the fixture added with this PR is related to display: contents
, rather than rem
units.
This seems like a separate issue from #29093 and #28638
For fixing the display:contents
issue directly, I recommend checking for this css rule in canClipContent
, as elements with display:contents
cannot clip content. I've opened an issue to track that here: #29605
The rem
issue should have a fixture that uses rem units. I do believe there is a useful fix here regarding them and using getClientBoundingRect()
to calculate float dimensions rather than int dimensions. Fixing the rem issue and the display: contents issue should be separated into two different pull requests. But disregarding certain combinations of clipping ancestors will cause many more issues, giving lots of false positives.
Thank you so much for contributing!
|
||
if (elHasPositionAbsolute($el) && (ancestorProps.width === 0 || ancestorProps.height === 0)) { | ||
return elIsOutOfBoundsOfAncestorsOverflow($el, getParent($ancestor)) | ||
if ((elHasPositionAbsolute($el) || elHasBlockStyle($el)) && (ancestorProps.width === 0 || ancestorProps.height === 0)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Block elements that have ancestors that hide them via overflow clipping will assert as visible even if they are not.
For example, with this DOM:
<div style="overflow: hidden; width: 0; height: 0">
<div style="height:100px; width:100px;">
<div id="hidden" style="height: 100px; width: 100px;">This content is hidden</div>
</div>
</div>
this assertion will fail:
cy.get('#hidden').should('not.be.visible')
However, this DOM:
<div style="overflow: hidden; width: 0; height: 0">
<div style="height:100px; width:100px;">
<span id="hidden">This content is hidden</div>
</div>
</div>
Will succeed with the same assertion.
As will this DOM:
<div style="overflow: hidden; width: 0; height: 0">
<div id="hidden">This content is hidden</div>
</div>
Removing the elHasBlockStyle
portion of this if
block should resolve the issue.
To verify, you can add additional test cases in visibility.cy.ts
for parent vs. grandparent visibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified. elHasBlockStyle removed. Test in visibility.cy.ts added.
// no ancestor, not out of bounds! | ||
// if we've reached the top parent, which is not a normal DOM el | ||
// then we're in bounds all the way up, return false | ||
if (isUndefinedOrHTMLBodyDoc($ancestor)) { | ||
return false | ||
} | ||
|
||
//fix for 28638 | ||
if (elHasPositionRelative($el) && elHasPositionAbsolute($ancestor)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relative elements can be clipped by absolute ancestors that have height
or width
of 0
and overflow:hidden
. canClipContent
(L#230) checks for various edge cases with offset parents before comparing the dimensions of an element and their ancestor to determine if the element is actually obscured by clipping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to canClipContent. This is just first working fix. Assumption is: when El has position relative and it's ancestor Absolute than this can not be clipped. But if this assumption is not exactly correct then more complicated check could be done. It's just better then existing version for this case.
@@ -308,47 +322,54 @@ const elIsNotElementFromPoint = function ($el) { | |||
return true | |||
} | |||
|
|||
const elIsOutOfBoundsOfAncestorsOverflow = function ($el, $ancestor = getParent($el)) { | |||
const elIsOutOfBoundsOfAncestorsOverflow = function ($el, el: HTMLElement, $ancestor = getParent($el)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$el.get(0)
and el
refer to the same element - let's remove the extraneous argument to make this function easier to follow. For getting rid of the implicit any
on $el
, JQuery<HTMLElement>
works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed. I guess it was just naive aproach to pass pipeline limitations in hugeJS file and not calculating jQuery when it was necessery. Still probably not needed and not that optimal anyway. Suggested getBoundingCalculation is probably better optimalisation anyway.
const elOffsetWidth = ($el) => { | ||
return $el[0].offsetWidth | ||
const elClientHeight = ($el) => { | ||
return $el[0].getBoundingClientRect().height |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each call to .getBoundingClientRect()
forces a layout/reflow of the browser. Calling this many times for each element/ancestor comparison in a complicated DOM may cause performance issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed into function. So result could be stored.
} | ||
|
||
.contents { | ||
display: contents |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what is causing Cypress to not properly determine that #sidebar-left
is not hidden in the fixture. display: contents
causes the element to not generate its own box, which prevents overflow:hidden from being applied as expected - the element is effectively replaced by its children, and its box model (and overflow settings) should be disregarded. See: https://drafts.csswg.org/css-display/#valdef-display-contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true. Check moved to canClip.
…-visible"-for-Cypress
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the latest changes!
The next step for this PR is to decide which issue you would like it to fix. We like to keep PRs narrowly focused on one issue at a time.
If you wish to fix the display: contents
issue (#29605) in this PR, please remove any changes that are unnecessary to fix it. I think the only change necessary to fix this is the addition of the CSS rule check in canClipContent
. If you wish to continue fixing any rem
/em
issues, please open a second PR to address it
If you wish to fix issues that are arising due to rounding dimensions with rem
and em
units, please add a test case for that in this PR and remove any changes that are unnecessary to fix that specific test case. If you wish, open a second PR to address the display:contents
issue.
Thank you again!
I choose second approach, added tests and tried to demonstrate need of this change. Still it's not that simple because it's only fix for not correctly detected as visible element that are with display: contents so they are detected as with 0 width without it. Anyway this change is needed in some cases. I just not found good test to demonstrate it yet. |
This changes are now part of other PR where they are needed to work. When their are accepted that one will no longer be needed. |
Visible elements are "not visible" for Cypress #29093
Additional details
Change was necessary because previous visibility check version works only with integer values for visibility. Current fix provide it with getting real width.
In theory it now fixes issue when visible element throws error as hidden/invisible or without width/height.
Still how visibility should behave when grid is used is not really clear, so there might be cases that this check is not perfect. Still I guess it's better than it was before.
Steps to test
e2e or component test
How has the user experience changed?
User no longer has to use {force: true} fix.
PR Tasks
cypress-documentation
?type definitions
?