diff --git a/packages/driver/cypress/e2e/dom/visibility.cy.ts b/packages/driver/cypress/e2e/dom/visibility.cy.ts index 43c7e31bbbf..1d91f16da6c 100644 --- a/packages/driver/cypress/e2e/dom/visibility.cy.ts +++ b/packages/driver/cypress/e2e/dom/visibility.cy.ts @@ -1,13 +1,54 @@ // @ts-ignore const { $, dom } = Cypress -describe('src/cypress/dom/visibility', () => { - const add = (el) => { - return $(el).appendTo(cy.$$('body')) +describe('src/cypress/dom/visibility', { + slowTestThreshold: 500, +}, () => { + function assertVisibilityForEl (el: HTMLElement) { + // once experimentalFastVisibility is added, switch based on the config value + // and use `cy-fast-expect` instead of `cy-legacy-expect` when it is enabled. + const expected = el.getAttribute('cy-expect') ?? el.getAttribute('cy-legacy-expect') + + if (!expected) { + throw new Error(`Expected attribute 'cy-expect' or 'cy-legacy-expect' not found on test case_ element ${el.outerHTML}`) + } + + expect( + $(el).is(`:${expected}`), + `${el.getAttribute('cy-label') ?? el.textContent ?? 'empty text content'} should be ${expected}`, + ).to.be.true + + expect(el).to.be[expected] + + cy.wrap(el).should(`be.${expected}`) + + const opposite = expected === 'hidden' ? 'visible' : 'hidden' + + expect( + $(el).is(`:${opposite}`), + `${el.getAttribute('cy-label') ?? el.textContent ?? 'empty text content'} should not be ${opposite}`, + ).to.be.false + + expect(el).to.not.be[opposite] + + cy.wrap(el).should(`not.be.${opposite}`) } - const reasonIs = ($el: JQuery, str: string) => { - expect(dom.getReasonIsHidden($el)).to.eq(str) + function prepareFixtureSection (section: string) { + cy.get('.test-section').each((el) => el.removeClass('active')) + cy.get(`[cy-section="${section}"]`).then((el) => el.addClass('active')) + cy.get(`[cy-section="${section}"]`).scrollIntoView() + } + + function assertVisibilityForSections (sections: string[]) { + for (const section of sections) { + it(`detects visibility for ${section} test cases`, () => { + prepareFixtureSection(section) + cy.get(`[cy-section="${section}"] .testCase`).then((els) => { + els.get().forEach(assertVisibilityForEl) + }) + }) + } } beforeEach(() => { @@ -169,1337 +210,303 @@ describe('src/cypress/dom/visibility', () => { }) }) - context('hidden/visible overrides', () => { - beforeEach(function () { - // ensure all tests run against a scrollable window - const scrollThisIntoView = add('
Should be in view
') - - this.$visHidden = add('') - this.$parentVisHidden = add('') - this.$displayNone = add('') - this.$inputHidden = add('') - this.$divNoWidth = add('
') - this.$divNoHeight = add('
') - this.$divDetached = $('
foo
') - this.$divVisible = add(`
visible
`) - - this.$optionInSelect = add(`\ -\ -`) - - this.$optgroupInSelect = add(`\ -\ -`) - - this.$optionInHiddenSelect = add(`\ -\ -`) - - this.$optionOutsideSelect = add(`\ -
- -
-
- -
\ -`) - - this.$optionHiddenInSelect = add(`\ -\ -`) - - this.$btnOpacityZero = add(`\ -\ -`) - - this.$btnOpacityHalf = add(`\ -\ -`) - - this.$parentOpacityZero = add(`\ -
- -
\ -`) - - this.$tableVisCollapse = add(`\ - - - - - - - - - - - -
NarutoSasukeSakura
KaguyaMadaraOrochimaro
\ -`) - - this.$parentNoWidth = add(`\ -
- parent width: 0 -
`) - - this.$parentNoHeight = add(`\ -
- parent height: 0 -
`) - - this.$parentNoWidthHeightOverflowAuto = add(`\ -
- parent no size, overflow: auto -
`) - - this.$parentWithWidthHeightNoOverflow = add(`\ -
- parent with size, overflow: hidden -
`) - - this.$ancestorWithWidthHeightNoOverflow = add(`\ -
-
parent with size, overflow: hidden
-
`) - - this.$ancestorNoWidth = add(`\ -
-
- ancestor width: 0 -
-
`) - - this.$ancestorNoHeight = add(`\ -
-
- ancestor height: 0 -
-
`) - - this.$childPosAbs = add(`\ -
-
- position: absolute -
-
`) - - this.$childPosFixed = add(`\ -
- -
`) - - this.$childPointerEventsNone = add(`\ -
- child pointer-events: none -
\ -`) - - this.$descendentPosAbs = add(`\ -
-
- no width, descendant position: absolute -
-
`) - - this.$descendentPosFixed = add(`\ -
-
- -
-
`) - - this.$descendantInPosFixed = add(`\ -
-
- underneath -
on top of the other
-
-
\ -`) - - this.$coveredUpPosFixed = add(`\ -
-
underneath
-
on top
-
\ -`) - - this.$offScreenPosFixed = add(`\ -
off screen
\ -`) - - this.$parentPosAbs = add(`\ -
-
- parent position: absolute -
-
`) - - this.$parentDisplayNone = add(`\ -\ -`) - - this.$parentPointerEventsNone = add(`\ -
- parent pointer-events: none -
\ -`) - - this.$parentPointerEventsNoneCovered = add(`\ -
- parent pointer-events: none -
-covering the element with pointer-events: none\ -`) - - this.$parentDisplayInlineChildDisplayBlock = add(`\ -
- - - -
\ -`) - - this.$elOutOfParentBoundsToLeft = add(`\ -
- position: absolute, out of bounds left -
\ -`) - - this.$elOutOfParentBoundsToRight = add(`\ -
- position: absolute, out of bounds right -
\ -`) - - this.$elOutOfParentBoundsAbove = add(`\ -
- position: absolute, out of bounds above -
\ -`) - - this.$elOutOfParentBoundsBelow = add(`\ -
- position: absolute, out of bounds below -
\ -`) - - this.$elOutOfParentWithOverflowYHiddenBounds = add(`\ -
- position: absolute, out of bounds below -
\ -`) - - this.$elOutOfParentWithOverflowXHiddenBounds = add(`\ -
- position: absolute, out of bounds below -
\ -`) - - this.$elOutOfParentWithFlexAndOverflowHiddenBounds = add(`\ -
-
red
-
green
-
blue
-
\ -`) - - this.$elOutOfParentWithOverflowHiddenBoundsButCloserPositionAbsoluteParent = add(`\ -
-
- Hello -
\ -`) - - this.$elOutOfAncestorOverflowAutoBounds = add(`\ -
-
- out of bounds, parent wide, ancestor overflow: auto -
-
\ -`) - - this.$elInPosAbsParentsBounds = add(`\ -
-
-
- in bounds, parent position: absolute -
-
-
\ -`) - - this.$elOutOfPosAbsParentsBounds = add(`\ -
-
-
- out of bounds, parent position: absolute -
-
-
\ -`) - - this.$elInParentBounds = add(`\ -
- in bounds, position: absolute -
\ -`) - - this.$elOutOfScrollingParentBounds = add(`\ -
-
-
- out of scrolling bounds, position: absolute -
-
-
\ -`) - - this.$elIsOutOfBoundsOfAncestorsOverflowButWithinRelativeAncestor = add(`\ -
-
-
- in bounds of ancestor, position: absolute, parent overflow: hidden -
-
-
\ -`) - - this.$elIsRelativeAndOutOfBoundsOfAncestorOverflow = add(`\ -
-
- out of bounds, position: relative -
-
\ -`) - - this.$elIsRelativeAndOutOfBoundsOfAncestorButAncestorShowsOverflow = add(`\ -
-
- out of bounds but visible, position: relative -
-
\ -`) - - this.$parentOutOfBoundsButElInBounds = add(`\ -
-
-
- in bounds of ancestor, parent out of bounds -
-
-
\ -`) - - this.$parentWithClipPathAbsolutePositionElOutsideClipPath = add(`\ -
- clip-path -
\ -`) - - this.$parentWithClipPathAbsolutePositionElInsideClipPath = add(`\ -
- clip-path -
\ -`) - - this.$parentWithTransformScaleElOutsideScale = add(`\ -
- TRANSFORMERS -
\ -`) - - this.$parentWithTransformScaleElInsideScale = add(`\ -
- TRANSFORMERS -
\ -`) - - this.$ancestorTransformMakesElOutOfBoundsOfAncestor = add(`\ -
-
-
- out of ancestor's bounds due to ancestor translate -
-
-
\ -`) - - this.$ancestorTransformMakesElInBoundsOfAncestor = add(`\ -
-
-
- out of ancestor's bounds due to ancestor translate -
-
- in ancestor's bounds due to ancestor translate -
-
-
\ -`) - - // scroll the 2nd element into view so that - // there is always a scrollTop so we ensure - // its factored in (window vs viewport) calculations - scrollThisIntoView.get(1).scrollIntoView() - }) - - describe('html or body', () => { - it('is visible if html', () => { - expect(cy.$$('html').is(':hidden')).to.be.false - expect(cy.$$('html').is(':visible')).to.be.true - - expect(cy.$$('html')).not.to.be.hidden - expect(cy.$$('html')).to.be.visible - - cy.wrap(cy.$$('html')).should('not.be.hidden') - cy.wrap(cy.$$('html')).should('be.visible') + describe('visibility scenarios', () => { + describe('html and body overrides', () => { + beforeEach(() => { + cy.visit('/fixtures/empty.html') }) - it('is visible if body', () => { - expect(cy.$$('body').is(':hidden')).to.be.false - expect(cy.$$('body').is(':visible')).to.be.true - - expect(cy.$$('body')).not.to.be.hidden - expect(cy.$$('body')).to.be.visible - - cy.wrap(cy.$$('body')).should('not.be.hidden') - cy.wrap(cy.$$('body')).should('be.visible') - }) - - it('is visible if display none on body or html', () => { - cy.$$('html').css('display', 'none') - cy.$$('body').css('display', 'none') - - expect(cy.$$('html')).not.to.be.hidden - expect(cy.$$('html')).to.be.visible - - expect(cy.$$('body')).not.to.be.hidden - expect(cy.$$('body')).to.be.visible - }) - }) - - describe('css visibility', () => { - it('is hidden if .css(visibility) is hidden', function () { - expect(this.$visHidden.is(':hidden')).to.be.true - expect(this.$visHidden.is(':visible')).to.be.false - - expect(this.$visHidden).to.be.hidden - expect(this.$visHidden).to.not.be.visible + describe('when display none', () => { + beforeEach(() => { + cy.get('html').then(($el) => { + $el.css('display', 'none') + }) - cy.wrap(this.$visHidden).should('be.hidden') - cy.wrap(this.$visHidden).should('not.be.visible') - }) + cy.get('body').then(($el) => { + $el.css('display', 'none') + }) + }) - it('is hidden if parents have .css(visibility) hidden', function () { - expect(this.$parentVisHidden.find('button').is(':hidden')).to.be.true - expect(this.$parentVisHidden.find('button').is(':visible')).to.be.false + it('is always visible', () => { + expect(cy.$$('html').is(':hidden')).to.be.false + expect(cy.$$('html').is(':visible')).to.be.true - expect(this.$parentVisHidden.find('button')).to.be.hidden - expect(this.$parentVisHidden.find('button')).to.not.be.visible + expect(cy.$$('html')).not.to.be.hidden + expect(cy.$$('html')).to.be.visible - cy.wrap(this.$parentVisHidden).find('button').should('be.hidden') - cy.wrap(this.$parentVisHidden).find('button').should('not.be.visible') - }) + cy.wrap(cy.$$('html')).should('not.be.hidden') + cy.wrap(cy.$$('html')).should('be.visible') + expect(cy.$$('body').is(':hidden')).to.be.false + expect(cy.$$('body').is(':visible')).to.be.true - it('is hidden if visibility collapse', function () { - expect(this.$tableVisCollapse.find('td.collapse')).to.be.hidden - expect(this.$tableVisCollapse.find('td.collapse')).to.not.be.visible + expect(cy.$$('body')).not.to.be.hidden + expect(cy.$$('body')).to.be.visible - expect(this.$tableVisCollapse.find('tr.collapse')).to.be.hidden - expect(this.$tableVisCollapse.find('tr.collapse')).to.not.be.visible - - expect(this.$tableVisCollapse.find('tr.collapse td')).to.be.hidden - expect(this.$tableVisCollapse.find('tr.collapse td')).to.not.be.visible + cy.wrap(cy.$$('body')).should('not.be.hidden') + cy.wrap(cy.$$('body')).should('be.visible') + }) }) - it('is hidden if parent has visibility collapse', function () { - expect(this.$tableVisCollapse.find('tr.collapse td')).to.be.hidden - expect(this.$tableVisCollapse.find('tr.collapse td')).to.not.be.visible + describe('when not display none', () => { + it('is visible', () => { + expect(cy.$$('html').is(':hidden')).to.be.false + expect(cy.$$('html').is(':visible')).to.be.true - expect(this.$tableVisCollapse.find('#collapse-span')).to.be.hidden - expect(this.$tableVisCollapse.find('#collapse-span')).to.not.be.visible - }) + expect(cy.$$('html')).not.to.be.hidden + expect(cy.$$('html')).to.be.visible - it('is hidden if input type hidden', function () { - expect(this.$inputHidden.is(':hidden')).to.be.true - expect(this.$inputHidden.is(':visible')).to.be.false + cy.wrap(cy.$$('html')).should('not.be.hidden') + cy.wrap(cy.$$('html')).should('be.visible') + expect(cy.$$('body').is(':hidden')).to.be.false + expect(cy.$$('body').is(':visible')).to.be.true - expect(this.$inputHidden).to.be.hidden - expect(this.$inputHidden).to.not.be.visible + expect(cy.$$('body')).not.to.be.hidden + expect(cy.$$('body')).to.be.visible - cy.wrap(this.$inputHidden).should('be.hidden') - cy.wrap(this.$inputHidden).should('not.be.visible') + cy.wrap(cy.$$('body')).should('not.be.hidden') + cy.wrap(cy.$$('body')).should('be.visible') + }) }) }) - describe('option and optgroup', () => { - it('is visible if option in visible select', function () { - expect(this.$optionInSelect.find('option').is(':hidden')).to.be.false - expect(this.$optionInSelect.find('option').is(':visible')).to.be.true - - expect(this.$optionInSelect.find('option')).not.to.be.hidden - expect(this.$optionInSelect.find('option')).to.be.visible - - cy.wrap(this.$optionInSelect.find('option')).should('not.be.hidden') - cy.wrap(this.$optionInSelect.find('option')).should('be.visible') - }) - - it('is visible if optgroup in visible select', function () { - expect(this.$optgroupInSelect.find('optgroup').is(':hidden')).to.be.false - expect(this.$optgroupInSelect.find('optgroup').is(':visible')).to.be.true - - expect(this.$optgroupInSelect.find('optgroup')).not.to.be.hidden - expect(this.$optgroupInSelect.find('optgroup')).to.be.visible - - cy.wrap(this.$optgroupInSelect.find('optgroup')).should('not.be.hidden') - cy.wrap(this.$optgroupInSelect.find('optgroup')).should('be.visible') - }) - - it('is hidden if option in hidden select', function () { - expect(this.$optionInHiddenSelect.find('option').is(':hidden')).to.be.true - expect(this.$optionInHiddenSelect.find('option').is(':visible')).to.be.false - - expect(this.$optionInHiddenSelect.find('option')).to.be.hidden - expect(this.$optionInHiddenSelect.find('option')).not.to.be.visible - - cy.wrap(this.$optionInHiddenSelect.find('option')).should('be.hidden') - cy.wrap(this.$optionInHiddenSelect.find('option')).should('not.be.visible') + describe('basic CSS properties', () => { + beforeEach(() => { + cy.visit('/fixtures/visibility/basic-css-properties.html') }) - it('is hidden if option is display none', function () { - expect(this.$optionHiddenInSelect.find('#hidden-opt').is(':hidden')).to.be.true - expect(this.$optionHiddenInSelect.find('#hidden-opt').is(':visible')).to.be.false - - expect(this.$optionHiddenInSelect.find('#hidden-opt')).to.be.hidden - expect(this.$optionHiddenInSelect.find('#hidden-opt')).not.to.be.visible - - cy.wrap(this.$optionHiddenInSelect.find('#hidden-opt')).should('be.hidden') - cy.wrap(this.$optionHiddenInSelect.find('#hidden-opt')).should('not.be.visible') - }) - - it('follows regular visibility logic if option outside of select', { browser: '!webkit' }, function () { - expect(this.$optionOutsideSelect.find('#option-hidden').is(':hidden')).to.be.true - expect(this.$optionOutsideSelect.find('#option-hidden')).to.be.hidden - cy.wrap(this.$optionOutsideSelect.find('#option-hidden')).should('be.hidden') - - expect(this.$optionOutsideSelect.find('#option-visible').is(':visible')).to.be.true - expect(this.$optionOutsideSelect.find('#option-visible')).to.be.visible - - cy.wrap(this.$optionOutsideSelect.find('#option-visible')).should('be.visible') - }) + assertVisibilityForSections([ + 'visibility-property', + 'display-property', + 'opacity-property', + 'input-elements', + 'table-elements', + 'box-interactions', + ]) }) - describe('css opacity', () => { - it('is hidden if opacity is 0', function () { - expect(this.$btnOpacityZero.is(':hidden')).to.be.true - expect(this.$btnOpacityZero.is(':visible')).to.be.false - - expect(this.$btnOpacityZero).to.be.hidden - expect(this.$btnOpacityZero).not.to.be.visible - - cy.wrap(this.$btnOpacityZero).should('be.hidden') - cy.wrap(this.$btnOpacityZero).should('not.be.visible') - }) - - it('is hidden if parent has `opacity: 0`', function () { - expect(this.$parentOpacityZero.find('button').is(':hidden')).to.be.true - expect(this.$parentOpacityZero.find('button').is(':visible')).to.be.false - - expect(this.$parentOpacityZero.find('button')).to.be.hidden - expect(this.$parentOpacityZero.find('button')).not.to.be.visible - - cy.wrap(this.$parentOpacityZero.find('button')).should('be.hidden') - cy.wrap(this.$parentOpacityZero.find('button')).should('not.be.visible') + describe('form elements', () => { + beforeEach(() => { + cy.visit('/fixtures/visibility/form-elements.html') }) - it('is visible if opacity is greater than 0 but less than 1', function () { - expect(this.$btnOpacityHalf.is(':visible')).to.be.true - expect(this.$btnOpacityHalf.is(':hidden')).to.be.false - - expect(this.$btnOpacityHalf).to.be.visible - expect(this.$btnOpacityHalf).not.to.be.hidden - - cy.wrap(this.$btnOpacityHalf).should('be.visible') - cy.wrap(this.$btnOpacityHalf).should('not.be.hidden') - }) + assertVisibilityForSections([ + 'select-and-option-elements', + 'optgroup-elements', + 'options-outside-select', + 'hidden-options-within-visible-select', + 'input-elements', + ]) }) - describe('width and height', () => { - it('is visible when el.textContent, even if offsetWidth is 0', function () { - this.$divNoWidthTextContent = add('
width: 0
') - - expect(this.$divNoWidthTextContent.is(':hidden')).to.be.false - expect(this.$divNoWidthTextContent.is(':visible')).to.be.true - - expect(this.$divNoWidthTextContent).to.not.be.hidden - expect(this.$divNoWidthTextContent).to.be.visible - - cy.wrap(this.$divNoWidthTextContent).should('be.not.hidden') - cy.wrap(this.$divNoWidthTextContent).should('be.visible') - }) - - it('is visible when el.textContent, even if offsetHeight is 0', function () { - this.$divNoHeightTextContent = add('
height: 0
') - - expect(this.$divNoHeightTextContent.is(':hidden')).to.be.false - expect(this.$divNoHeightTextContent.is(':visible')).to.be.true - - expect(this.$divNoHeightTextContent).to.not.be.hidden - expect(this.$divNoHeightTextContent).to.be.visible - - cy.wrap(this.$divNoHeightTextContent).should('be.not.hidden') - cy.wrap(this.$divNoHeightTextContent).should('be.visible') - }) - - it('is hidden when when el.textContent contains only whitespace and offsetWidth is 0', function () { - this.$divNoHeightBlankTextContent = add('
\n \t
') - - expect(this.$divNoHeightBlankTextContent.is(':hidden')).to.be.true - expect(this.$divNoHeightBlankTextContent.is(':visible')).to.be.false - - expect(this.$divNoHeightBlankTextContent).to.be.hidden - expect(this.$divNoHeightBlankTextContent).to.not.be.visible - - cy.wrap(this.$divNoHeightBlankTextContent).should('be.hidden') - cy.wrap(this.$divNoHeightBlankTextContent).should('not.be.visible') - }) - - it('is hidden when no el.textContent with offsetHeight is 0', function () { - expect(this.$divNoHeight.is(':hidden')).to.be.true - expect(this.$divNoHeight.is(':visible')).to.be.false - - expect(this.$divNoHeight).to.be.hidden - expect(this.$divNoHeight).to.not.be.visible - - cy.wrap(this.$divNoHeight).should('be.hidden') - cy.wrap(this.$divNoHeight).should('not.be.visible') - }) - - it('is hidden when no el.textContent with offsetWidth is 0', function () { - expect(this.$divNoWidth.is(':hidden')).to.be.true - expect(this.$divNoWidth.is(':visible')).to.be.false - - expect(this.$divNoWidth).to.be.hidden - expect(this.$divNoWidth).to.not.be.visible - - cy.wrap(this.$divNoWidth).should('be.hidden') - cy.wrap(this.$divNoWidth).should('not.be.visible') - }) - - it('is hidden if parent has overflow: hidden and no width', function () { - expect(this.$parentNoWidth.find('span')).to.be.hidden - expect(this.$parentNoWidth.find('span')).to.not.be.visible - }) - - it('is hidden if parent has overflow: hidden and no height', function () { - expect(this.$parentNoHeight.find('span')).to.be.hidden - expect(this.$parentNoHeight.find('span')).to.not.be.visible - }) - - it('is hidden if ancestor has overflow:hidden and no width', function () { - expect(this.$ancestorNoWidth.find('span')).to.be.hidden - expect(this.$ancestorNoWidth.find('span')).to.not.be.visible - }) - - it('is hidden if ancestor has overflow:hidden and no height', function () { - expect(this.$ancestorNoHeight.find('span')).to.be.hidden - expect(this.$ancestorNoHeight.find('span')).to.not.be.visible - }) - - it('is visible when parent has positive dimensions even with overflow hidden', function () { - expect(this.$parentWithWidthHeightNoOverflow.find('span')).to.be.visible - expect(this.$parentWithWidthHeightNoOverflow.find('span')).to.not.be.hidden - }) - - it('is visible when ancestor has positive dimensions even with overflow hidden', function () { - expect(this.$ancestorWithWidthHeightNoOverflow.find('span')).to.be.visible - expect(this.$ancestorWithWidthHeightNoOverflow.find('span')).to.not.be.hidden - }) + describe('overflow', () => { + beforeEach(() => { + cy.visit('/fixtures/visibility/overflow.html') + }) + + assertVisibilityForSections([ + 'zero-dimensions-with-overflow-hidden', + 'text-content-with-zero-dimensions', + 'positive-dimensions-with-overflow-hidden', + 'overflow-auto-with-zero-dimensions', + 'mixed-dimension-scenarios', + 'overflow-hidden', + 'overflow-y-hidden', + 'overflow-x-hidden', + 'overflow-auto-scenarios', + 'overflow-scroll-scenarios', + 'overflow-relative-positioning', + 'overflow-flex-container', + 'overflow-complex-scenarios', + 'clip-path-scenarios', + ]) }) - describe('css position', () => { - it('is visible if child has position: absolute', function () { - expect(this.$childPosAbs.find('span')).to.be.visible - expect(this.$childPosAbs.find('span')).not.be.hidden - }) - - it('is visible if child has position: fixed', function () { - expect(this.$childPosFixed.find('button')).to.be.visible - expect(this.$childPosFixed.find('button')).not.to.be.hidden - }) - - it('is visible if descendent from parent has position: fixed', function () { - expect(this.$descendentPosFixed.find('button')).to.be.visible - expect(this.$descendentPosFixed.find('button')).not.to.be.hidden + describe('positioning', () => { + beforeEach(() => { + cy.visit('/fixtures/visibility/positioning.html') }) - it('is visible if has position: fixed and descendent is found', function () { - expect(this.$descendantInPosFixed.find('#descendantInPosFixed')).to.be.visible - expect(this.$descendantInPosFixed.find('#descendantInPosFixed')).not.to.be.hidden - }) - - it('is hidden if position: fixed and covered up', function () { - expect(this.$coveredUpPosFixed.find('#coveredUpPosFixed')).to.be.hidden - expect(this.$coveredUpPosFixed.find('#coveredUpPosFixed')).not.to.be.visible - }) - - it('is hidden if position: fixed and off screen', function () { - expect(this.$offScreenPosFixed).to.be.hidden - expect(this.$offScreenPosFixed).not.to.be.visible - }) - - it('is visible if descendent from parent has position: absolute', function () { - expect(this.$descendentPosAbs.find('span')).to.be.visible - expect(this.$descendentPosAbs.find('span')).to.not.be.hidden - }) - - it('is hidden if only the parent has position absolute', function () { - expect(this.$parentPosAbs.find('span')).to.be.hidden - expect(this.$parentPosAbs.find('span')).to.not.be.visible - }) - - it('is visible if position: fixed and parent has pointer-events: none', function () { - expect(this.$parentPointerEventsNone.find('span')).to.be.visible - expect(this.$parentPointerEventsNone.find('span')).to.not.be.hidden - }) - - it('is not visible if covered when position: fixed and parent has pointer-events: none', function () { - expect(this.$parentPointerEventsNoneCovered.find('span')).to.be.hidden - expect(this.$parentPointerEventsNoneCovered.find('span')).to.not.be.visible - }) - - it('is visible if pointer-events: none and parent has position: fixed', function () { - expect(this.$childPointerEventsNone.find('span')).to.be.visible - expect(this.$childPointerEventsNone.find('span')).to.not.be.hidden - }) - - it('is visible when position: sticky', () => { - cy.visit('fixtures/sticky.html') - cy.get('#button').should('be.visible') - }) - }) - - describe('css display', function () { - // https://github.com/cypress-io/cypress/issues/6183 - it('parent is visible if display inline and child has display block', function () { - expect(this.$parentDisplayInlineChildDisplayBlock.find('span')).to.be.visible - expect(this.$parentDisplayInlineChildDisplayBlock.find('span')).to.not.be.hidden - }) - }) - - describe('css overflow', () => { - it('is hidden when parent overflow auto and no width/height', function () { - expect(this.$parentNoWidthHeightOverflowAuto.find('span')).to.not.be.visible - expect(this.$parentNoWidthHeightOverflowAuto.find('span')).to.be.hidden - }) - - it('is hidden when parent overflow hidden and out of bounds to left', function () { - expect(this.$elOutOfParentBoundsToLeft.find('span')).to.be.hidden - }) - - it('is hidden when parent overflow hidden and out of bounds to right', function () { - expect(this.$elOutOfParentBoundsToRight.find('span')).to.be.hidden - }) - - it('is hidden when parent overflow hidden and out of bounds above', function () { - expect(this.$elOutOfParentBoundsAbove.find('span#elOutOfParentBoundsAbove')).to.be.hidden - }) - - it('is hidden when parent overflow hidden and out of bounds below', function () { - expect(this.$elOutOfParentBoundsBelow.find('span')).to.be.hidden - }) - - it('is hidden when parent overflow-y hidden and out of bounds', function () { - expect(this.$elOutOfParentWithOverflowYHiddenBounds.find('span')).to.be.hidden - }) - - it('is hidden when parent overflow-x hidden and out of bounds', function () { - expect(this.$elOutOfParentWithOverflowXHiddenBounds.find('span')).to.be.hidden - }) - - it('is visible when parent overflow hidden but el in a closer parent with position absolute', function () { - expect(this.$elOutOfParentWithOverflowHiddenBoundsButCloserPositionAbsoluteParent.find('span')).to.be.visible - }) - - it('is hidden when parent flex and overflow hidden and el out of bounds', function () { - expect(this.$elOutOfParentWithFlexAndOverflowHiddenBounds.find('#red')).to.be.visible - expect(this.$elOutOfParentWithFlexAndOverflowHiddenBounds.find('#green')).to.be.visible - expect(this.$elOutOfParentWithFlexAndOverflowHiddenBounds.find('#blue')).to.be.hidden - }) - - it('is hidden when parent is wide and ancestor is overflow auto', function () { - expect(this.$elOutOfAncestorOverflowAutoBounds.find('span')).to.be.hidden - }) - - it('is hidden when parent overflow scroll and out of bounds', function () { - expect(this.$elOutOfScrollingParentBounds.find('span')).to.be.hidden - }) - - it('is hidden when parent absolutely positioned and overflow hidden and out of bounds', function () { - expect(this.$elOutOfPosAbsParentsBounds.find('span')).to.be.hidden - }) - - it('is visible when parent absolutely positioned and overflow hidden and not out of bounds', function () { - expect(this.$elInPosAbsParentsBounds.find('span')).to.be.visible - }) - - it('is visible when parent overflow hidden and not out of bounds', function () { - expect(this.$elInParentBounds.find('span')).to.be.visible - }) - - it('is hidden when parent overflow clip and height is 0', function () { - cy.$$('body').empty() - - const el = add('
I am not visible
') - - expect(el.find('#hidden')).to.be.hidden - reasonIs(el.find('#hidden'), 'This element `` is not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: `hidden`, `clip`, `scroll` or `auto`') - }) - - it('is visible when parent overflow clip and height is non-0', function () { - cy.$$('body').empty() - - const el = add('
I am visible
') - - expect(el.find('#visible')).to.be.visible - }) - - it('is visible when ancestor is overflow hidden but more distant ancestor is the offset parent', function () { - expect(this.$elIsOutOfBoundsOfAncestorsOverflowButWithinRelativeAncestor.find('span')).to.be.visible - }) - - it('is hidden when relatively positioned outside ancestor with overflow hidden', function () { - expect(this.$elIsRelativeAndOutOfBoundsOfAncestorOverflow.find('span')).to.be.hidden - }) - - it('is visible when el is relatively positioned outside ancestor that does not hide overflow', function () { - expect(this.$elIsRelativeAndOutOfBoundsOfAncestorButAncestorShowsOverflow.find('span')).to.be.visible - }) - - 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 () { - cy.$$('body').empty() - - const el = add(` -
-
-
- -
-
-
- `) - - 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 () { - cy.$$('body').empty() - - const el = add(` -
-
-
-
-

Example

-
- -
-
-
-
-
- `) - - expect(el.find('#visible-button')).to.be.visible - }) - - it('is hidden when parent element is absolutely position and offset parent is a decendent of the ancestor', function () { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
-
- `) - - cy.contains('test-2').should('not.be.visible') - cy.contains('test-1').should('be.visible') - }) - - it('is hidden when element is an option and the parent has overflow clip', function () { - cy.$$('body').empty() - - add(` -
-
- -
- `) - - cy.get('option').should('not.be.visible').then(($el) => { - reasonIs($el, 'This element `` is not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: `hidden`, `clip`, `scroll` or `auto`') - }) - - cy.get('select').should('not.be.visible').then(($el) => { - reasonIs($el, 'This element ` - - - - -
- `) - - cy.get('option').should('be.visible') - cy.get('optgroup').should('be.visible') - cy.get('select').should('be.visible') - }) - - it('is visible when x direction is clip but element is visible in y direction', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('be.visible') - }) - - it('is hidden when x direction is hidden and y direction is coerced by browser to auto', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('not.be.visible') - }) - - it('is hidden when x direction is auto and y direction is coerced by browser to auto', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('not.be.visible') - }) - - it('is hidden when y direction is hidden and x direction is set to clip but coerced by browser to hidden', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('not.be.visible') - }) - - it('is hidden when y direction is auto and x direction is set to clip but coerced by browser to hidden', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('not.be.visible') - }) - - it('is visible when x direction is clip and y direction is visible', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('be.visible') - }) - - it('is hidden when y direction is overriden by setting overflow to clip', () => { - cy.$$('body').empty() - - add(` -
-
-
- - -
-
- `) - - cy.get('label').should('not.be.visible') - }) + assertVisibilityForSections([ + 'position-fixed-element-covered-by-another', + 'static-ancestor-fixed-descendant', + 'static-parent-fixed-child', + 'positioning-with-zero-dimensions', + 'fixed-positioning-with-zero-dimensions', + 'position-absolute-scenarios', + 'position-sticky-scenarios', + ]) }) - describe('css clip-path', () => { - // TODO: handle clip path 'hidden' equivalents - it.skip('is hidden when outside of parents clip-path', function () { - expect(this.$parentWithClipPathAbsolutePositionElOutsideClipPath.find('span')).to.be.hidden - }) - - it('is visible when inside of parents clip-path', function () { - expect(this.$parentWithClipPathAbsolutePositionElInsideClipPath.find('span')).to.be.visible - }) + describe('transforms', () => { + beforeEach(() => { + cy.visit('/fixtures/visibility/transforms.html') + }) + + assertVisibilityForSections([ + 'scaling', + 'translation', + 'rotation', + 'skew', + 'matrix', + 'perspective', + 'multiple', + 'multiple-3d', + 'backface-visibility', + ]) }) + }) - describe('css transform', () => { - describe('element visibility by css transform', () => { - it('is visible when an element is translated a bit', () => { - const el = add(`
Translated
`) - - expect(el).to.be.visible - }) - - it('is visible when an element is only skewed', () => { - const el = add(`
Skewed
`) - - expect(el).to.be.visible - }) - - it('is visible when an element is only rotated', () => { - const el = add(`
Rotated
`) - - expect(el).to.be.visible - }) - - it('is visible when an element is scaled by non-zero', () => { - const el = add(`
Scaled
`) - - expect(el).to.be.visible - }) - - it('is visible when an element is transformed in multiple ways but not scaled to zero', () => { - const el = add(`
Multiple transform
`) - - expect(el).to.be.visible - }) - - it('is visible when an element is rotateZ(90deg)', () => { - const el = add(`
rotateZ(90deg)
`) - - expect(el).to.be.visible - }) - - // https://github.com/cypress-io/cypress/issues/6745 - it('is visible even if there is a dangling element in the tree', () => { - cy.visit('/fixtures/dangling-element.html') - cy.get('.hello') - }) - - it('is hidden when an element is scaled to X axis in 0', () => { - const el = add(`
ScaleX(0)
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is scaled to Y axis in 0', () => { - const el = add(`
ScaleY(0)
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is scaled to Z axis in 0', () => { - const el = add(`
ScaleZ(0)
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is transformed in multiple ways but scaled to 0 in one axis', () => { - const el = add(`
Multiple 2
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is rotateX(90deg)', () => { - const el = add(`
rotateX(90deg)
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is rotateY(90deg)', () => { - const el = add(`
rotateY(90deg)
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is rotateX(90deg) rotateY(90deg)', () => { - const el = add(`
rotateX(90deg)
`) - - expect(el).to.be.hidden - }) - - it('is hidden when an element is transformed in multiple ways but rotated to 90 deg in X or Y axis', () => { - const el = add(`
rotateX(90deg)
`) - - expect(el).to.be.hidden - - const el2 = add(`
rotateX(90deg)
`) - - expect(el2).to.be.hidden - - const el3 = add(`
rotateX(90deg)
`) - - expect(el3).to.be.hidden - }) - }) - - describe('when height/width is set', () => { - it('is visible when transform is not 0, but height is 0', () => { - const el = add('
Text
') - - expect(el).to.be.visible - }) - - it('is visible when transform is not 0, but width is 0', () => { - const el = add('

Text

') - - expect(el).to.be.visible - }) - - it('is visible when parent transform is not 0, but height is 0', () => { - const el = add('

Text

') - - expect(el.find('#tr-p-0')).to.be.visible - }) - - it('is visible when parent transform is not 0, but width is 0', () => { - const el = add('

Test

') - - expect(el.find('#tr-p-1')).to.be.visible - }) - - it('is invisible when parent transform is 0, but height is not 0', () => { - const el = add('

Test

') - - expect(el.find('#tr-p-2')).to.be.hidden - }) - - describe('invisible when overflow: hidden', () => { - it('height: 0 + overflow', () => { - const el = add('

Test

') - - expect(el.find('#h0th')).to.be.hidden - }) - - it('height: 0 + overflow-x', () => { - const el = add('

Test

') - - expect(el.find('#h0th')).to.be.hidden - }) - - it('height: 0 + overflow-y', () => { - const el = add('

Test

') - - expect(el.find('#h0th')).to.be.hidden - }) - - it('width: 0 + overflow', () => { - const el = add('

Test

') - - expect(el.find('#h0th')).to.be.hidden - }) - - it('width: 0 + overflow-x', () => { - const el = add('

Test

') - - expect(el.find('#h0th')).to.be.hidden - }) - - it('width: 0 + overflow-y', () => { - const el = add('

Test

') - - expect(el.find('#h0th')).to.be.hidden - }) - }) - }) - - it('is hidden when outside parents transform scale', function () { - expect(this.$parentWithTransformScaleElOutsideScale.find('span')).to.be.hidden - }) - - it('is visible when inside of parents transform scale', function () { - expect(this.$parentWithTransformScaleElInsideScale.find('span')).to.be.visible - }) - - it('is hidden when out of ancestor\'s bounds due to ancestor\'s transform', function () { - expect(this.$ancestorTransformMakesElOutOfBoundsOfAncestor.find('span')).to.be.hidden - }) + context('#getReasonIsHidden', () => { + const reasonIs = ($el: JQuery, str: string) => { + expect(dom.getReasonIsHidden($el)).to.eq(str) + } - it('is visible when in ancestor\'s bounds due to ancestor\'s transform', function () { - expect(this.$ancestorTransformMakesElInBoundsOfAncestor.find('#inbounds')).to.be.visible + describe('basic css / box model', () => { + beforeEach(() => { + cy.visit('/fixtures/visibility/basic-css-properties.html') }) - }) - describe('#getReasonIsHidden', () => { it('has `display: none`', function () { - reasonIs(this.$displayNone, 'This element ` `) - reasonIs(el.find('#needsScroll'), `This element \`\` is not visible because its ancestor has \`position: fixed\` CSS property and it is overflowed by other elements. How about scrolling to the element with \`cy.scrollIntoView()\`?`) - }) + reasonIs(el.find('#needsScroll'), `This element \`\` is not visible because its ancestor has \`position: fixed\` CSS property and it is overflowed by other elements. How about scrolling to the element with \`cy.scrollIntoView()\`?`) + }) - it('cannot determine why element is not visible', function () { - // this element is actually visible - // but used here as an example that does not match any of the above - reasonIs(this.$divVisible, 'This element `
` is not visible.') - }) + it('cannot determine why element is not visible', function () { + // this element is actually visible + // but used here as an example that does not match any of the above + const visible = cy.$$('
Visible
') + + cy.$$('body').append(visible) + reasonIs(visible, 'This element `
` is not visible.') }) }) }) diff --git a/packages/driver/cypress/fixtures/visibility/basic-css-properties.html b/packages/driver/cypress/fixtures/visibility/basic-css-properties.html new file mode 100644 index 00000000000..726195b1993 --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/basic-css-properties.html @@ -0,0 +1,67 @@ + + + + Basic CSS Properties Visibility Tests + + + + +

Basic CSS Properties Visibility Tests

+ +
+

Visibility Property

+ +
Visible by visibility
+ +
+ +
+

Display Property

+ +
Visible by display: block
+ +
+ +
+

Opacity Property

+
Hidden by opacity: 0
+
Semi-transparent (opacity: 0.5)
+
Fully opaque (opacity: 1)
+
+ +
+
+ +
+

Input Elements

+ + +
+ +
+

Table Elements

+ + + + + + + + + + +
Normal CellNormal CellCell by visibility: collapse
Cell hidden by row's visibility: collapse
+
+
+
+ + + +
+
+ + diff --git a/packages/driver/cypress/fixtures/visibility/empty.html b/packages/driver/cypress/fixtures/visibility/empty.html new file mode 100644 index 00000000000..f799f0cb387 --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/empty.html @@ -0,0 +1,4 @@ + + +
+ \ No newline at end of file diff --git a/packages/driver/cypress/fixtures/visibility/form-elements.html b/packages/driver/cypress/fixtures/visibility/form-elements.html new file mode 100644 index 00000000000..bac1d20d04f --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/form-elements.html @@ -0,0 +1,65 @@ + + + + Form Elements Visibility Tests + + + + +

Form Elements Visibility Tests

+ +
+

Select and Option Elements

+ + + +
+ +
+

Optgroup Elements

+ + + +
+ +
+

Options Outside Select

+ +
+ +
+
+ +
+

Hidden Options Within Visible Select

+ +
+ +
+

Input Elements

+ + + +
+ + diff --git a/packages/driver/cypress/fixtures/visibility/overflow.html b/packages/driver/cypress/fixtures/visibility/overflow.html new file mode 100644 index 00000000000..589691779dd --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/overflow.html @@ -0,0 +1,272 @@ + + + + Overflow Visibility Tests + + + + +

Overflow Visibility Tests

+ +
+

Zero Dimensions with Overflow Hidden

+ + +
+
+ Zero width ancestor, parent, self +
+
+ + +
+
+ Zero height ancestor, parent, self +
+
+ + +
+
+ Zero width ancestor, positive parent +
+
+ + +
+
+ Zero height ancestor, positive parent +
+
+
+ +
+

Text Content with Zero Dimensions

+ + +
+ lorem ipsum dolor sit amet +
+ + +
+ lorem ipsum dolor sit amet +
+ + +
+ +
+ + +
+
+ ancestor width: 0 +
+
+ + +
+
+ ancestor height: 0 +
+
+
+ +
+

Positive Dimensions with Overflow Hidden

+ + +
+
+ ancestor with size, parent with size & overflow: hidden +
+
+ + +
+
+ positive ancestor, zero parent +
+
+
+ +
+

Overflow Auto with Zero Dimensions

+ + +
+ parent no size, overflow: auto +
+
+ +
+

Mixed Dimension Scenarios

+ + +
Zero width
+
Has text content
+
+ + +
+
Has text content
+
+ + +
+
+
+
+
+

Overflow Hidden scenarios

+
+
+
+
+
+
+
+
+
+

Overflow Y Hidden scenarios

+
+
+
+
+
+
+
+

Overflow X Hidden scenarios

+
+
+
+
+
+
+ +
+

Overflow Auto Scenarios

+ + +
+
+ out of bounds, parent wide, ancestor overflow: auto +
+
+ + +
+ parent no size, overflow: auto +
+
+ +
+

Overflow Scroll Scenarios

+ + +
+
+
+ out of scrolling bounds, position: absolute +
+
+
+
+ +
+

Overflow with Relative Positioning

+ + +
+
+ out of bounds, position: relative +
+
+ + +
+
+ out of bounds but visible, position: relative +
+
+
+ +
+

Overflow with Flex Container

+ + +
+
red
+
green
+
blue
+
+
+ +
+

Complex Overflow Scenarios

+ + +
+
+
+
+

Example

+
+ +
+
+
+
+
+ + +
+
+
+ + +
+
+
+
+ +
+

Clip-Path Scenarios (note: legacy mode does not support clip-path)

+ + +
+ clip-path child of polygon that clips everything +
+ + +
+ clip-path +
+ + +
+ clipped content +
+ + +
+ visible content +
+ + +
+ elliptical content +
+ + +
+ path content +
+
+ + diff --git a/packages/driver/cypress/fixtures/visibility/positioning.html b/packages/driver/cypress/fixtures/visibility/positioning.html new file mode 100644 index 00000000000..0dbb50eacf9 --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/positioning.html @@ -0,0 +1,113 @@ + + + + Positioning Visibility Tests + + + + +

Positioning Visibility Tests

+
+

Positioning with Zero Dimensions

+
+ Child with absolute positioning +
+
+ +
+

Fixed Positioning with Zero Dimensions

+ + + + +
+
+ Child with position: fixed +
+
+
+ +
+

Static ancestor with fixed positioned descendant

+ +
+
+ +
+
+
+ +
+ + +
underneath
+
on top
+
+ +
+

Static parent with a fixed child

+ + +
+ +
+
+
+ +
off screen
+ + +
+ child pointer-events: none +
+
+
+

Parent with pointer-events: none

+ +
+ parent pointer-events: none +
+ + +
+ parent pointer-events: none +
+
covering the element with pointer-events: none
+ +
+
+

Position Absolute Scenarios

+ + +
+
+ position: absolute +
+
+ + +
+
+ no width, descendant position: absolute +
+
+ + +
+
+ parent position: absolute +
+
+
+ +
+

Position Sticky Scenarios

+ + +
+ +
+
+ + + diff --git a/packages/driver/cypress/fixtures/visibility/style.css b/packages/driver/cypress/fixtures/visibility/style.css new file mode 100644 index 00000000000..e95a616f443 --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/style.css @@ -0,0 +1,21 @@ +body { margin: 20px; font-family: Arial, sans-serif; } +.test-section { display:none; margin: 20px 0; padding: 10px; border: 1px solid #ccc; } +.test-section h3 { margin-top: 0; } +.test-section.active { display: block; } +table { border-collapse: collapse; margin: 10px 0; } +td, th { border: 1px solid #ccc; padding: 5px; } +nav { + display: block; +} +nav li { + display: inline-block; + list-style: none; +} + +[cy-expect="hidden"], [cy-legacy-expect="hidden"], [cy-fast-expect="hidden"] { + background-color: lightcoral; +} + +[cy-expect="visible"], [cy-legacy-expect="visible"], [cy-fast-expect="visible"] { + background-color: lightgreen; +} diff --git a/packages/driver/cypress/fixtures/visibility/table-visibility.html b/packages/driver/cypress/fixtures/visibility/table-visibility.html new file mode 100644 index 00000000000..0d533e0995c --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/table-visibility.html @@ -0,0 +1,77 @@ + + + + Table Visibility Tests + + + + +

Table Visibility Tests

+ +
+

Visibility Collapse on Table Cells

+ + + + + + +
Normal CellCollapsed CellAnother Normal Cell
+
+ +
+

Visibility Collapse on Table Rows

+ + + + + + + + + + + + + +
Normal RowNormal Row
Hidden Row Cell 1Hidden Row Cell 2
Another Normal RowAnother Normal Row
+
+ +
+

Mixed Visibility States

+ + + + + + + + + + + + + + + + +
NormalCollapsedNormal
Hidden RowHidden Row CellHidden Row
NormalNormalNormal
+
+ +
+

Normal Table (All Visible)

+ + + + + + + + + + + +
Normal Cell 1Normal Cell 2Normal Cell 3
Normal Row 2Normal Row 2Normal Row 2
+
+ + diff --git a/packages/driver/cypress/fixtures/visibility/transforms.html b/packages/driver/cypress/fixtures/visibility/transforms.html new file mode 100644 index 00000000000..210195cbd92 --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/transforms.html @@ -0,0 +1,145 @@ + + + + Transform Visibility Tests + + + + +

CSS Transform Scenarios

+ +
+

Scaling

+
+ Scaling(0,0) +
+
+ Scaling(1,1) +
+
Scaled
+ + +
ScaleX(0)
+
ScaleY(0)
+
ScaleZ(0)
+ + +
Multiple transforms with scale(0,0)
+
+
+

Translation

+
+ Translation(-10px) +
+
+ Translation(10px) +
+
Translated in 2 dimensions
+
Translated in 3rd dimension
+
Translated in 3 dimensions
+
+
+

Rotation

+
Rotated on X axis
+
Rotated on Y axis
+
Rotated on Z axis
+
Rotated on 3 axes
+ + +
RotateX(90deg)
+
RotateY(90deg)
+
RotateZ(90deg)
+ + +
RotateX(90deg) rotateY(90deg)
+ + +
Multiple with rotateX(90deg)
+
Multiple with rotateY(90deg)
+
Multiple with rotateX(90deg) rotateY(90deg)
+
+
+

Skew

+
Skewed on X axis
+
Skewed on Y axis
+
Skewed on 2 axes
+
+
+

Matrix

+
Matrix(1, 0, 0, 1, 0, 0)
+
Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
+
+
+

Perspective

+
Perspective(100px)
+
Perspective(100px) translateZ(10px)
+
Perspective(100px) rotateX(45deg)
+
Perspective(100px) rotateY(45deg)
+
Perspective(100px) rotateZ(45deg)
+
+
+

Multiple

+
Multiple transforms
+
+
+

Multiple 3D

+
Multiple 3D transforms
+
+ +
+

Transform Edge Cases

+ + +
Translated with text
+
Skewed with text
+
Rotated with text
+ + +
Text content
+
Text content
+ + +
+

Test

+
+ + +
+

Test

+
+
+

Test

+
+
+

Test

+
+
+

Test

+
+
+

Test

+
+
+

Test

+
+
+ +
+

Backface Visibility

+
Backface hidden on X axis
+
Backface hidden on Y axis
+
Backface hidden on Z axis
+
Backface hidden on 3 axes
+
Backface visible
+
+
Backface hidden on Y axis
+
+
+
RotateY(45deg) with visible backface and preserve-3d
+
Backface hidden on Y axis
+ +
Backface visible on Y axis
+
+
+ + \ No newline at end of file diff --git a/packages/driver/cypress/fixtures/visibility/ux.js b/packages/driver/cypress/fixtures/visibility/ux.js new file mode 100644 index 00000000000..b5e7e4cb9de --- /dev/null +++ b/packages/driver/cypress/fixtures/visibility/ux.js @@ -0,0 +1,37 @@ +document.addEventListener('DOMContentLoaded', () => { + const sections = document.querySelectorAll('.test-section').values().map((el) => { + return { + label: el.querySelector('h3')?.textContent ?? el.getAttribute('cy-section'), + section: el.getAttribute('cy-section'), + } + }) + const nav = document.createElement('nav') + + const list = document.createElement('ul') + + nav.appendChild(list) + sections.forEach(({ label, section }) => { + const li = document.createElement('li') + const a = document.createElement('a') + + a.href = `#${section}` + a.textContent = label + li.appendChild(a) + list.appendChild(li) + }) + + document.body.appendChild(nav) +}) + +document.addEventListener('click', (ev) => { + const [, section] = ev.target?.href?.split('#') ?? [] + + if (!section) return + + document.querySelectorAll('.test-section.active').forEach((el) => { + el.classList.remove('active') + }) + + document.querySelector(`[cy-section="${section}"]`)?.classList.add('active') + document.querySelector(`[cy-section="${section}"]`)?.scrollIntoView() +})