Cypress: Cy.screenshot should only capture the app

Created on 6 Jul 2016  路  34Comments  路  Source: cypress-io/cypress

The screenshot captures the entire chrome viewport. It should only capture the app.

Will this be fixed for free with 17?

pythagorean

pkdriver feature

Most helpful comment

@necinc awesome - thanks for that.

I've got good news and bad news for you.

The good news is that one of our devs has spent the last month working on this to its fullest capacity. It may initially look really simple to do, but there is a ton of complexity around taking the screenshot at the right time. For instance, we found that Chrome itself does not actually paint or render synchronously (even when it recalculates the box models) because it has internal optimizations. In other words, given your method, it is possible for the screenshot to happen and render the Cypress UI even though it's technically been hidden with CSS.

We also expanded the API's to not only hide the Cypress UI, and to also handle the scaling (as you've done), but also to capture full page screenshots (we automatically stitch together the UI) and have even added support for element screenshots. We also took into account devicePixelRatio.

Additionally - we also added support for "blacking out" elements and provide callback functions prior to taking the screenshot, so that you may modify the DOM to remove things like dynamic elements, sliding banners etc.

We also even took it upon ourselves to try to create more deterministic tests by preventing all asynchronous callbacks in your app from firing and even forcing animations to be disabled during the screenshot taking process. Phew...

The bad news is that it's not quite done yet - but it's sitting in a PR here: https://github.com/cypress-io/cypress/pull/1504

You can see it is quite... a lot... of work.

All 34 comments

Yah this is a good idea - we will make this configurable.

+1 Thanks!

+1 Nice idea

It would be great if there would be options to toggle:

  • side-panel
  • toolbar
  • full-height screenshots

Perhaps screenshot and video recording as well?

If we did this for video it would kind of take away the entire point of knowing why your tests failed.

Screenshots make sense to hide away the Cypress UI elements.

However "full height" and application size scaling is where the problems come in with screenshot diffing (and is just one tiny aspect which makes this very difficult to do well).

For instance if one machine is running Cypress at a different resolution than another, while we correctly scale the application, the screenshot will also be scaled, which means the same screenshot at two different scales will in fact register as completely different and fail.

So the machine taking the screenshots would need to be "normalized" and cannot change even though Cypress insulates you from different sized screens, there is no way to normalize the actual pixels the browser decides to paint when scaled.

Makes sense. Thanks!

+1 :)

Hi Cypress team,

Is there any ETA on this feature? That feature would be very nice.

Everyone, no need to comment with +1 - use the reaction buttons!

To monkey-patch it, maybe something like this:

var screenshot = file => () => {
    var reporter = window.parent.document.getElementsByClassName('reporter-wrap')[0],
        display = reporter.style.display;
    reporter.style.display = 'none';
    return cy.wait(1).screenshot(file).then(() => {
        reporter.style.display = display;
    });
};

Use like doSomething.then(screenshot('foo')).

Not sure if this is reliable, i.e. if the DOM will always have updated 'display' when the screenshot happens, but it has been working for me so far.

+1 This feature would be great

If possible, it would be great to hijack chrome's "Capture full size screenshot" functionality to get app-only, full height scaled screenshots. Not sure if this relies on native events, etc.

+1 for this feature.

can we specify screenshot height and width in config.js file?

@alisharaju94 Not as of 1.4.1

Implementing this feature would go a long way for those of us that can't wait for https://github.com/cypress-io/cypress/issues/495, or want to use a different screen diffing algorithm.

And ideally there would be an option to capture only the viewport (the configured size, not the browser size).

I don't mind having the sidebar there, but the amount of space given to the sidebar vs the app itself is kind of ridiculous:

apps page -- shows keys not including af keys

So even just customizing the width of the Cypress chrome would be very helpful.

The amount of space is controlled by you - you can drag the reporter (next to the scrollbar) which will resize the application automatically.

I can't drag anything; this is a screenshot taken automatically in a headless run.

@dallonf So what's happening is that Cypress keeps a local cache of the reporter's width anytime you change it when running in interactive mode via cypress open. It does this so each time you open Cypress it'll use the last cached value.

When you go to run all your tests it continues to use that last cached width. So I think you just need to go into cypress open and then drag it - and then run in cypress run. We should probably open a separate issue for this since it's a bit unintuitive.

It's kind of a hilarious thought to imagine us actually making the app window that small on purpose.

That makes sense. I can make a separate issue.

Edit: and done! https://github.com/cypress-io/cypress/issues/1309

This ticket is pretty old, is there an ETA for this feature?

Here is the unstable way to capture a screenshot without Cypress's runner UI

Hi guys! I've made a snippet which extends the cy.screenshot command to make a screenshot without cypress's UI controls.

Pros: Does not require any changes in your tests' code, with this we get a shot with original page scale (pixel ration is 1x1) and there is no cypress's UI on the picture.

Cons: It causes visible flash while taking a shot. Since cy.screenshot is an asynchronous (as mentioned in docs: https://docs.cypress.io/api/commands/screenshot.html#Asynchronous) original UI will be hidden until the screenshot method will resolve.

Usage

Put this snippet in __PROJECT_ROOT__/cypress/support/commands.js and that's it. It will work in all the places where cy.screenshot method had been called before.
It behaves the same as original cy.screenshot command

const screenshotModeClassName = "screenshotMode";

const styles = `
  .screenshotMode .runner.container {
    background: #444;
    left: 0 !important;
  }

  .screenshotMode .runner.container header {
    display: none;
  }

  .screenshotMode .reporter-wrap {
    display: none;
  }

  .screenshotMode .runner.container .size-container {
    transform: none !important;
    margin-left: auto !important;
    margin-right: auto;
  }

  .screenshotMode .aut-iframe {
    box-shadow: none;
  }


  .screenshotMode .message-container {
    display: none;
  }

  .screenshotMode .iframes-container {
    top: 10px;
  }
`;

Cypress.Commands.overwrite("screenshot", (originalScreenshot, filename) =>
  cy.window().then(({ parent }) => {
    const { document } = parent;
    const screenshotModeLinkTagId = "screenshotModeStyles";

    if (document.getElementById(screenshotModeLinkTagId) === null) {
      const linkTag = document.createElement("style");
      linkTag.type = "text/css";
      linkTag.id = screenshotModeLinkTagId;
      linkTag.innerHTML = styles;

      document.head.appendChild(linkTag);
    }

    document.body.classList.add(screenshotModeClassName);

    return originalScreenshot(filename).then(() => {
      document.body.classList.remove(screenshotModeClassName);
    });
  })
);

@necinc awesome - thanks for that.

I've got good news and bad news for you.

The good news is that one of our devs has spent the last month working on this to its fullest capacity. It may initially look really simple to do, but there is a ton of complexity around taking the screenshot at the right time. For instance, we found that Chrome itself does not actually paint or render synchronously (even when it recalculates the box models) because it has internal optimizations. In other words, given your method, it is possible for the screenshot to happen and render the Cypress UI even though it's technically been hidden with CSS.

We also expanded the API's to not only hide the Cypress UI, and to also handle the scaling (as you've done), but also to capture full page screenshots (we automatically stitch together the UI) and have even added support for element screenshots. We also took into account devicePixelRatio.

Additionally - we also added support for "blacking out" elements and provide callback functions prior to taking the screenshot, so that you may modify the DOM to remove things like dynamic elements, sliding banners etc.

We also even took it upon ourselves to try to create more deterministic tests by preventing all asynchronous callbacks in your app from firing and even forcing animations to be disabled during the screenshot taking process. Phew...

The bad news is that it's not quite done yet - but it's sitting in a PR here: https://github.com/cypress-io/cypress/pull/1504

You can see it is quite... a lot... of work.

@brian-mann oh聽馃檧, there is really a ton of work already done there. I will subscribe to this PR.
So it looks like I should remove "Solution" from the title of my previous comment 馃檪
Thanks for your reply!

@brian-mann it's awesome you all are tackling this! do you have an estimate of when the new cy.screenshot API will be released?

@nwshane It's mostly all working right now in the PR, but we've found a slight performance regression with the screenshot that we have to work through.

The code for this is done, but this has yet to be released. We'll update this issue and reference the changelog when it's released.

Perfect, thanks so much!

@jennifer-shehane any ETA for the next release? The last one pushed to NPM was 3 months ago :(

Perhaps tonight...

Released in 3.0.0.

Was this page helpful?
0 / 5 - 0 ratings