cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.72k stars 3.16k forks source link

An ancestor element with `display: contents` and `overflow: hidden` causes visibility check to fail #25199

Open kevinleedrum opened 1 year ago

kevinleedrum commented 1 year ago

Current behavior

If an element has an ancestor with both overflow: hidden and display: contents, Cypress will think that element is not visible because Cypress sees the ancestor element as having zero width and height (and no overflow).

image

Desired behavior

Although it is silly to combine overflow: hidden with display: contents, and I can easily work around this issue in the app being tested, the child elements are technically visible, so ideally this should be fixed in cypress.

Cypress should give elements with display: contents a pass when checking that the element has a width and height since those elements don't really render a box to measure. The visibility check would then fall to the next descendent.

Test code to reproduce

See https://github.com/kevinleedrum/cypress-test-tiny. The markup is in index.html; npm run cypress:run should reproduce the failure.

The relevant bit is that the <section> below will be seen as NOT visible, even though it is.

      <div style="display: contents; overflow: hidden">
        <section>Hello</section>
      </div>

Cypress Version

12.1.0

Node version

v14.17.0

Operating System

macOS 13.0.1

Debug Logs

[1]   cypress:server:run spec results { stats: { suites: 1, tests: 1, passes: 0, pending: 0, skipped: 0, failures: 1, wallClockStartedAt: 2022-12-16T16:22:31.891Z, wallClockEndedAt: 2022-12-16T16:22:37.453Z, wallClockDuration: 5562 }, reporter: 'spec', reporterStats: { suites: 1, tests: 1, passes: 0, pending: 0, failures: 1, start: 2022-12-16T16:22:31.893Z, end: 2022-12-16T16:22:37.459Z, duration: 5566 }, hooks: [], tests: [ { testId: 'r3', title: [Array], state: 'failed', body: '() => {\n' + '    cy.visit("http://localhost:8888");\n' + '    cy.get("section").should("be.visible");\n' + '  }', displayError: "AssertionError: Timed out retrying after 4000ms: expected '<section>' to be 'visible'\n" + '\n' + 'This element `<section>` is not visible because its parent `<div>` has CSS property: `overflow: hidden` and an effective width and height of: `0 x 0` pixels.\n' + '    at Context.eval (webpack:///./cypress/e2e/spec.cy.js:5:22)', attempts: [Array] } ], error: null, video: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/videos/spec.cy.js.mp4', screenshots: [ { screenshotId: 'o2mit', name: null, testId: 'r3', testAttemptIndex: 0, takenAt: '2022-12-16T16:22:37.238Z', path: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/screenshots/spec.cy.js/page -- has a visible section (failed).png', height: 720, width: 1280, pathname: undefined } ], spec: { fileExtension: '.js', baseName: 'spec.cy.js', fileName: 'spec', specFileExtension: '.cy.js', relativeToCommonRoot: 'spec.cy.js', specType: 'integration', name: 'cypress/e2e/spec.cy.js', relative: 'cypress/e2e/spec.cy.js', absolute: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/e2e/spec.cy.js' }, shouldUploadVideo: true } +753ms
[1]   cypress:server:run final results of all runs: { status: 'finished', startedTestsAt: 2022-12-16T16:22:31.891Z, endedTestsAt: 2022-12-16T16:22:37.453Z, totalDuration: 5562, totalSuites: 1, totalTests: 1, totalPassed: 0, totalPending: 0, totalFailed: 1, totalSkipped: 0, runs: [ { stats: [Object], reporter: 'spec', reporterStats: [Object], hooks: [], tests: [Array], error: null, video: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/videos/spec.cy.js.mp4', screenshots: [Array], spec: [Object], shouldUploadVideo: true } ], browserPath: '', browserName: 'electron', browserVersion: '106.0.5249.51', osName: 'darwin', osVersion: '22.1.0', cypressVersion: '12.1.0', runUrl: undefined, config: { setupNodeEvents: '[Function setupNodeEvents]', projectRoot: '/Users/kevin.drum/repos/cypress-test-tiny', projectName: 'cypress-test-tiny', repoRoot: '/Users/kevin.drum/repos/cypress-test-tiny', rawJson: { e2e: [Object], setupNodeEvents: '[Function setupNodeEvents]', envFile: {}, projectRoot: '/Users/kevin.drum/repos/cypress-test-tiny', projectName: 'cypress-test-tiny', repoRoot: '/Users/kevin.drum/repos/cypress-test-tiny' }, configFile: 'cypress.config.js', morgan: false, isTextTerminal: true, socketId: 'nvp18urthh', report: true, animationDistanceThreshold: 5, arch: 'x64', baseUrl: null, blockHosts: null, chromeWebSecurity: true, clientCertificates: [], defaultCommandTimeout: 4000, downloadsFolder: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/downloads', env: {}, execTimeout: 60000, experimentalFetchPolyfill: false, experimentalInteractiveRunEvents: false, experimentalRunAllSpecs: false, experimentalModifyObstructiveThirdPartyCode: false, experimentalOriginDependencies: false, experimentalSourceRewriting: false, experimentalSingleTabRunMode: false, experimentalStudio: false, experimentalWebKitSupport: false, fileServerFolder: '/Users/kevin.drum/repos/cypress-test-tiny', fixturesFolder: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/fixtures', excludeSpecPattern: '*.hot-update.js', includeShadowDom: false, keystrokeDelay: 0, modifyObstructiveCode: true, nodeVersion: undefined, numTestsKeptInMemory: 0, platform: 'darwin', pageLoadTimeout: 60000, port: 58834, projectId: null, redirectionLimit: 20, reporter: 'spec', reporterOptions: null, requestTimeout: 5000, resolvedNodePath: '/Users/kevin.drum/.nvm/versions/node/v14.17.0/bin/node', resolvedNodeVersion: '14.17.0', responseTimeout: 30000, retries: { runMode: 0, openMode: 0 }, screenshotOnRunFailure: true, screenshotsFolder: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/screenshots', slowTestThreshold: 10000, scrollBehavior: 'top', supportFile: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/support/e2e.js', supportFolder: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/support', taskTimeout: 60000, testIsolation: true, trashAssetsBeforeRuns: true, userAgent: null, video: true, videoCompression: 32, videosFolder: '/Users/kevin.drum/repos/cypress-test-tiny/cypress/videos', videoUploadOnPasses: true, viewportHeight: 660, viewportWidth: 1000, waitForAnimations: true, watchForFileChanges: false, specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}', additionalIgnorePattern: [], autoOpen: false, browsers: [ [Object], [Object], [Object] ], clientRoute: '/__/', cypressBinaryRoot: '/Users/kevin.drum/Library/Caches/Cypress/12.1.0/Cypress.app/Contents/Resources/app', devServerPublicPathRoute: '/__cypress/src', hosts: null, isInteractive: true, namespace: '__cypress', reporterRoute: '/__cypress/reporter', socketIoCookie: '__socket', socketIoRoute: '/__socket', version: '12.1.0', cypressEnv: 'production', resolved: { animationDistanceThreshold: [Object], arch: [Object], baseUrl: [Object], blockHosts: [Object], chromeWebSecurity: [Object], clientCertificates: [Object], defaultCommandTimeout: [Object], downloadsFolder: [Object], env: {}, execTimeout: [Object], experimentalFetchPolyfill: [Object], experimentalInteractiveRunEvents: [Object], experimentalRunAllSpecs: [Object], experimentalModifyObstructiveThirdPartyCode: [Object], experimentalOriginDependencies: [Object], experimentalSourceRewriting: [Object], experimentalSingleTabRunMode: [Object], experimentalStudio: [Object], experimentalWebKitSupport: [Object], fileServerFolder: [Object], fixturesFolder: [Object], excludeSpecPattern: [Object], includeShadowDom: [Object], keystrokeDelay: [Object], modifyObstructiveCode: [Object], nodeVersion: [Object], numTestsKeptInMemory: [Object], platform: [Object], pageLoadTimeout: [Object], port: [Object], projectId: [Object], redirectionLimit: [Object], reporter: [Object], reporterOptions: [Object], requestTimeout: [Object], resolvedNodePath: [Object], resolvedNodeVersion: [Object], responseTimeout: [Object], retries: [Object], screenshotOnRunFailure: [Object], screenshotsFolder: [Object], slowTestThreshold: [Object], scrollBehavior: [Object], supportFile: [Object], supportFolder: [Object], taskTimeout: [Object], testIsolation: [Object], trashAssetsBeforeRuns: [Object], userAgent: [Object], video: [Object], videoCompression: [Object], videosFolder: [Object], videoUploadOnPasses: [Object], viewportHeight: [Object], viewportWidth: [Object], waitForAnimations: [Object], watchForFileChanges: [Object], specPattern: [Object], browsers: [Object], hosts: [Object], isInteractive: [Object] }, testingType: 'e2e', remote: { auth: undefined, origin: 'http://localhost:58834', strategy: 'file', fileServer: 'http://localhost:58835', domainName: 'localhost', props: null }, browser: null, specs: [], proxyUrl: 'http://localhost:58834', browserUrl: 'http://localhost:58834/__/', reporterUrl: 'http://localhost:58834/__cypress/reporter', proxyServer: 'http://localhost:58834', state: {} } } +1ms

Other

No response

mike-plummer commented 1 year ago

Hi @kevinleedrum , thanks for letting us know about this. Also, thanks so much for the reproduction! Visibility is one of the trickiest things we have to juggle (it's pretty complex for anyone else stumbling across this comment).

I can confirm this is a hole in our logic so I'll get this passed along to the team to look into, but it might be a little while before we have time to work it. If anyone in the community would like to take a stab at improving this logic a good place to start would be packages/driver/src/dom/visibility.ts.

mirobo commented 1 year ago

@kevinleedrum See also my discussion here https://github.com/cypress-io/cypress/discussions/23900 which is also about display: contents. My code samples revolve around the problem on how to make sure that selectors in page objects are pointing to the correct element but I could remove some hacky code if the "display: contents" visibility check would be different (i.e. check child elements for visibility as you suggested as well)..

roelaenomar commented 1 year ago

I am also experiencing this, the CSS property overflow-x is not found, however, if I will assert that it exists, it passed. image

developernarendra commented 1 year ago

hi can you pls guide me how i can start this means how i can take to this my local machine i dont know anything i know how to fork but not able to understand how to start this and go for pull request

mike-plummer commented 1 year ago

Hi @developernarendra , thanks for showing an interest in contributing to Cypress! I would recommend starting with our Contributors Guide. That document includes (or links to) information on how to clone Cypress locally, build it, make changes, and finally open a PR.

bastiansmn commented 1 year ago

Hello, currently working on this since I reproduced locally with latest and started to have a good idea on how to fix.

senpl commented 3 months ago

Should b fixed in https://github.com/cypress-io/cypress/pull/29680