cypress-io / cypress

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

Screenshot "scroll and stitch together" is not correct when `html` and `body` have `height: 100%` css style #2681

Open GordonTester opened 5 years ago

GordonTester commented 5 years ago

I'm experiencing an issue with screenshot functionality on a website under test.

It seems Cypress does not approve and when generating a full height screenshot of my page, it includes the sticky header and the "above fold" page content several times, completely ignoring any of the content (and the site footer) which you'd have to scroll to access.

On pages where the header is not sticky, part of the bottom of the page repeats, as below.

I've taken a look at attempting to invoke some of the CSS, but the likelihood is that there are multiple elements on some of the more complex pages which may require this hack.

Has anyone experienced this / found a solution?

GordonTester commented 5 years ago

See below for an example... screenshot comparison -- match login page against baseline screenshot -- loginpage

testquantilope commented 5 years ago

We are experiencing the same issue with our React Web-App. This doesn't happen all the time, but only once in a while. Usually we have 5-10 such problems in our 3000 screenshots we are taking during one test run.

survey_ui_rating_matrix_slider_without_titles png___survey_ui_rating_matrix_slider_without_titles png_0 184459

jennifer-shehane commented 5 years ago

Can anyone provide a way to reproduce this reliably?

GordonTester commented 5 years ago

I can reproduce it reliably on my employers website with standard screenshot functionality. I can share the URL via a private message as it's super secret at the moment.

My hacky fix has been to take the main div holding the site together and invoke 100% width and absolute (or fixed depending on the page) positioning as below:

cy.get('div[id=app]').invoke('css', 'position', 'absolute').invoke('css', 'width', '100%')

neocoder commented 5 years ago

I have the exact same issue. It's a plain page, though. In my case it breaks because of this css

html, body {
    height: 100%;
}

I thinks it's a part of some old framework or css-reset, not sure. Here's a workaround:

cy.get('html').invoke('css', 'height', 'initial');
cy.get('body').invoke('css', 'height', 'initial');
jennifer-shehane commented 5 years ago

@GordonTester You can email any private code / tests directly to support@cypress.io

Elshaikh commented 5 years ago

Hii @jennifer-shehane Need your help and advice here plz , how to interact with slider with 2 handle , HTML

<div class="horizontal-slider" style="position: relative;">
    <div class="bar bar-0" style="position: absolute; left: 0px; right: 225px; will-change: left, right;"></div>
    <div class="bar bar-1" style="position: absolute; left: 0px; right: 0.0139758px; will-change: left, right;"></div>
    <div class="bar bar-2" style="position: absolute; left: 224.986px; right: 0px; will-change: left, right;"></div>
    <div class="handle handle-0 " tabindex="0" role="slider" aria-valuenow="162.08" aria-valuemin="162.08"
         aria-valuemax="9177.64" style="position: absolute; z-index: 1; left: 0px;"></div>
    <div class="handle handle-1 " tabindex="0" role="slider" aria-valuenow="9177.08" aria-valuemin="162.08"
         aria-valuemax="9177.64" style="position: absolute; z-index: 2; left: 224.986px;"></div>
</div>

cypress step

cy.get('div.handle.handle-0').invoke('attr', 'aria-valuenow', "1000").click() // handle 1
cy.get('div.handle.handle-1').invoke('attr', 'aria-valuenow', "4188").click() // handle 2
nathanhere commented 4 years ago

I have the exact same issue. It's a plain page, though. In my case it breaks because of this css

html, body {
    height: 100%;
}

I thinks it's a part of some old framework or css-reset, not sure. Here's a workaround:

cy.get('html').invoke('css', 'height', 'initial');
cy.get('body').invoke('css', 'height', 'initial');

@neocoder this finally put an end to three straight days of constantly combing the web for a solution. Many, Many, Many thanks.

jennifer-shehane commented 4 years ago

I can recreate this with the following code:

index.html

<html style="height: 100%;">
<body style="height: 100%; background: linear-gradient(yellow, blue, red);">
</body>
</html>

spec.js

it('screenshot', () => {
  cy.visit('index.html')
  cy.screenshot()
});

Expected screenshot

screenshot

Actual screenshot

screenshot (2)

Workaround

As explained by @neocoder, this workaround fixes the screenshot.

it('screenshot', () => {
  cy.visit('index.html')
  cy.get('html').invoke('css', 'height', 'initial');
  cy.get('body').invoke('css', 'height', 'initial');
  cy.screenshot()
  cy.get('html').invoke('css', 'height', '100%');
  cy.get('body').invoke('css', 'height', '100%');
});
harunurhan commented 4 years ago

this work around doesn't fix the issue with sticky headers though, it still requires more css injection to make it work. And at the end what you're testing ends up being too different than the actual production code.

@jennifer-shehane

srinu-kodi commented 4 years ago

Hi @jennifer-shehane I am facing an issue when I am taking screenshot of a react Single Page App. Since it is confidential so I cannot share the screenshot here. Basically page has

-> left nav section and bottom left nav section has Feedback option. -> right nav section and right nav section has chatbot button option.

_So when I am taking the screenshot, since the page is large so it is taking scrolls for 2 times as per the height I am passing to Cypress but due to this Chatbot & Feedback options coming as redundant and entire screenshot coming as weird._

Do you suggest how can we overcome this and take screenshot fullPage without scrolls somehow to avoid this issue...

I have gone through cypress-visual-regression & cypress-image-snapshot npm packages but all of them are underlying calling to cy.screenshot so they are not helping

Your help is highly appreciated .

only4arunkumar commented 3 years ago

May be we can try taking the screenshot of individual elements rather than the entire screen. i need to try that out. i facing the same issue with Cypress 6.8.0 ,cypress-image-snapshot: 2.2.2. The above suggested solution didn't work for me when i am testing my webpages with viewports matching mobile devices. I always get scrollbars and entire screen is not captured for visual regression

r3sdev commented 3 years ago

May be we can try taking the screenshot of individual elements rather than the entire screen. i need to try that out. i facing the same issue with Cypress 6.8.0 ,cypress-image-snapshot: 2.2.2. The above suggested solution didn't work for me when i am testing my webpages with viewports matching mobile devices. I always get scrollbars and entire screen is not captured for visual regression

I'm experiencing the same problem with cypress@6.8.0 and cypress-plugin-snapshots@^1.4.4.

Here's a screenshot:

Home -- a11y -- iphone-6 has no detectable a11y violations on load

audriusnavickasDB commented 3 years ago

This issue also affects blackouts. Usually if you have images added as the blackouts when taking a snapshot blackouts get some sort of offset and the image gets half covered or not covered at all. This is even more visible for elements, which are positioned absolute/fixed and have scrollable content and the provided fix does not help at all. Time to time you need to add specific heights for certain elements in order to get somewhat correct result.

dr-itz commented 3 years ago

Same screen shot issue here, but started happening from Bootstrap 4.6 -> Bootstrap 5.0. We already had html, body { height: 100%; }. The difference in BS5 is the added :root { scrolling-behavior: smooth; }. Overriding that fixed things again. So does passing --disable-smooth-scrolling to Chrome, i.e. in plugins/index.ts:

import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';

export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => {
  addMatchImageSnapshotPlugin(on, config);

  on('before:browser:launch', (browser: Cypress.Browser, launchOptions: Cypress.BrowserLaunchOptions) => {
    if (browser.family === 'chromium') {
      launchOptions.args.push('--force-color-profile=srgb');
      launchOptions.args.push('--disable-low-res-tiling');
      launchOptions.args.push('--disable-smooth-scrolling');
    }
    return launchOptions;
  });
};

Note, we run tests with Chrome, not Electron since it's faster and screen shots are more reliable 😉

Doc-Code commented 3 years ago

Same screen shot issue here, but started happening from Bootstrap 4.6 -> Bootstrap 5.0. We already had html, body { height: 100%; }. The difference in BS5 is the added :root { scrolling-behavior: smooth; }. Overriding that fixed things again. So does passing --disable-smooth-scrolling to Chrome, i.e. in plugins/index.ts:

import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';

export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => {
  addMatchImageSnapshotPlugin(on, config);

  on('before:browser:launch', (browser: Cypress.Browser, launchOptions: Cypress.BrowserLaunchOptions) => {
    if (browser.family === 'chromium') {
      launchOptions.args.push('--force-color-profile=srgb');
      launchOptions.args.push('--disable-low-res-tiling');
      launchOptions.args.push('--disable-smooth-scrolling');
    }
    return launchOptions;
  });
};

Note, we run tests with Chrome, not Electron since it's faster and screen shots are more reliable 😉

now it doesn't give full screen at all(((

Doc-Code commented 3 years ago
cy.get('.footer').invoke('css', 'position', 'relative');
cy.wait(0);
cy.screenshot({ capture: 'fullPage' });
cy.get('.footer').invoke('css', 'position', 'fixed');
lexanth commented 2 years ago

I had a similar screenshot issue without having height: 100% because my layout was being set up with an element-resize-detector which was listening to scroll events, which were being triggered by the screenshot scroll.

The solution in that case was to trigger a scroll to the bottom and back to the top before taking the screenshot. The first scroll triggered the layout events, so the layout didn't jump when it took the screenshot.

Just in case anyone else gets this sort of visual error.

joma74 commented 2 years ago

height: 100vh in runner does not work either in Chrome or Firefox via

cy.screenshot("article-comment-", {
      capture: "fullPage",
    });

.

See Screenshot "fullPage" to the left, Runner to the right.

CypressIssueScreenshotFullPage

As you can see the vertical Scrollbar on the Runner app frame, for fullPage there is something below the fold. That part is not on Screenshot "fullPage".

all9lives commented 2 years ago

I was experiencing the same screenshot issues with html and body with height: 100% but even after making height: auto I still had screenshot issues, removing scroll-behavior: smooth was what fixed screenshots for me. Hopefully this may help other seeing similar issues.

cy.get("html, body").invoke(
  "attr",
  "style",
  "height: auto; scroll-behavior: auto;"
);
gundant commented 2 years ago

Similar issue with react canvas elements. Tried many ways to get around it and the workaround for this issue finally fixed it.

Screenshot of an element that was below current view would apparently not be scrolled into view by cypress (can see this doing GUI run; does not scroll unless workaround added), fullpage would in some resolutions give weird results like in this issue, scaled=false missed elements completely (black screenshot).

Usual element screenshot result would only give the top of the targeted element unless the viewport and screen were some specific large values (so that even the bottom elements did not require scrolling to be in view):

bottomTwo-actual (1)

With cy.get('html').invoke('css', 'height', 'initial'); cy.get('body').invoke('css', 'height', 'initial'); added it captures the element as expected: image

(I added the obfuscation)

ArchiMoebius commented 1 year ago

cypress.config.js


const { defineConfig } = require('cypress');

module.exports = defineConfig({
  video: false,
  e2e: {
    experimentalSessionAndOrigin: true,
    baseUrl: 'http://127.0.0.1:1880/',
    supportFile: false,
    specPattern: 'cypress/e2e/**/*.cy.js',
    waitForAnimations: false,

    setupNodeEvents(on, config) {
      on('before:browser:launch', (browser, launchOptions) => {

        launchOptions.args.push('--force-color-profile=srgb');
        launchOptions.args.push('--disable-low-res-tiling');
        launchOptions.args.push('--disable-smooth-scrolling');

        return launchOptions
      })
    }
  },
});

Thanks @dr-itz - that worked for me :man_shrugging: (using chrome)

chungchamchi19 commented 1 year ago
cy.get("html, body").invoke(
  "attr",
  "style",
  "height: auto; scroll-behavior: auto;"
);

I was experiencing the same screenshot issues with html and body with height: 100% but even after making height: auto I still had screenshot issues, removing scroll-behavior: smooth was what fixed screenshots for me. Hopefully this may help other seeing similar issues.

cy.get("html, body").invoke(
  "attr",
  "style",
  "height: auto; scroll-behavior: auto;"
);

You save my day. Many many thanks bro!

cchaglund commented 7 months ago

Same screen shot issue here, but started happening from Bootstrap 4.6 -> Bootstrap 5.0. We already had html, body { height: 100%; }. The difference in BS5 is the added :root { scrolling-behavior: smooth; }. Overriding that fixed things again. So does passing --disable-smooth-scrolling to Chrome, i.e. in plugins/index.ts:

import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';

export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => {
  addMatchImageSnapshotPlugin(on, config);

  on('before:browser:launch', (browser: Cypress.Browser, launchOptions: Cypress.BrowserLaunchOptions) => {
    if (browser.family === 'chromium') {
      launchOptions.args.push('--force-color-profile=srgb');
      launchOptions.args.push('--disable-low-res-tiling');
      launchOptions.args.push('--disable-smooth-scrolling');
    }
    return launchOptions;
  });
};

Note, we run tests with Chrome, not Electron since it's faster and screen shots are more reliable 😉

EDIT: I thought this had fixed my issue, but what really fixed my issue (which I had done at the same time) was removing my sticky header (display: none), none of the other proposed fixes had any effect on my particular issue.

Plizzz commented 4 months ago

I was experiencing the same screenshot issues with html and body with height: 100% but even after making height: auto I still had screenshot issues, removing scroll-behavior: smooth was what fixed screenshots for me. Hopefully this may help other seeing similar issues.

cy.get("html, body").invoke(
  "attr",
  "style",
  "height: auto; scroll-behavior: auto;"
);

It works for cypress v13. Thank you!

ryo-kozin commented 2 months ago

EDIT: I thought this had fixed my issue, but what really fixed my issue (which I had done at the same time) was removing my sticky header (display: none), none of the other proposed fixes had any effect on my particular issue.

I was experiencing the same screenshot issues with html and body with height: 100% but even after making height: auto I still had screenshot issues, removing scroll-behavior: smooth was what fixed screenshots for me. Hopefully this may help other seeing similar issues.

cy.get("html, body").invoke(
  "attr",
  "style",
  "height: auto; scroll-behavior: auto;"
);

It works for cypress v13.12.0. Thank you! I need to remove sticky header.

mwtrew commented 1 month ago

Same issue after upgrading to Bootstrap 5 - disabling smooth scrolling in Chrome as @dr-itz described was enough to get it working again. Thanks for the help!