Cypress: CSS `scroll-behavior: smooth;` on the `html` el breaks actionability

Created on 23 Jan 2019  路  17Comments  路  Source: cypress-io/cypress

Current behavior:

  • Multiple tests when attempting to leverage the .click() and .check() methods with the following error:

CypressError: Timed out retrying: cy.click() failed because the center of this element is hidden from view:

Desired behavior:

  • Ideally this CSS would not impact Cypress' ability to view elements appropriately
  • Not a showstopper for our project as we can remove the styles and keep on trucking!

Steps to reproduce: (app code and test code)

  1. Add the following CSS:
html {
  scroll-behavior: smooth;
}
  1. Try running a Cypress test that leverages the .click() or .check() methods

Versions

Cypress version 3.1.4, Mac OSX, Chrome

A huge thank you to all of the contributors on this project. It's a great great tool!

existing workaround first-timers-only internal-priority pkdriver ready for work actionability scrolling 鈫曪笍 bug

Most helpful comment

Same bug here, ended up disabling the style with the following snippet:

/**
 * Disable css smooth scroll, that doesn't plays nice with cypress.
 * See https://github.com/cypress-io/cypress/issues/3200
 */
const disableSmoothScroll = () => {
  cy.document().then(document => {
    const node = document.createElement('style');
    node.innerHTML = 'html { scroll-behavior: inherit !important; }';
    document.body.appendChild(node);
  });
};

describe('test', () => {
  it('does stuff', () => {
    cy.visit(...);
    disableSmoothScroll();
    cy.get(...).scrollIntoView();
  })
})

All 17 comments

Hey @nicklemmon, I've opened a PR for this - writing a failing test for this behavior here: https://github.com/cypress-io/cypress/pull/3213

Now someone will need to look into why this failure occurs and fix Cypress calculations. Just from watching the test run, it looks as if the scroll is happening after the .click command has errored.

The error is being thrown at this line of code: https://github.com/cypress-io/cypress/blob/issue-3200-scroll-behavior-smooth/packages/driver/src/cy/ensures.coffee#L224

@Bkucera Brian was hoping you could pick this issue up as well as part of 3.1.6. 馃檹 Thank you!

@jennifer-shehane this issue can't be fixed by simply passing options into scrollIntoView, it seems the css property will force all calls to scrollIntoView to be smooth.

The solution is to mutate the styles of the element with scroll-behavior:smooth just before the call to scrollIntoView, and then change it back right after.

I'm not sure why this would be a priority and need to go in the next patch, currently you can just work around this bug by removing that style

I start having this issue when updated to Cypress 3.1.4 and I solved it by adding to cy.visit the following:

cy.visit('/', {
      onBeforeLoad(win) {
        cy.stub(win, 'scrollTo').as('windowScroll');
      }
    });

cc. @jennifer-shehane Hope this helps you.

Same bug here, ended up disabling the style with the following snippet:

/**
 * Disable css smooth scroll, that doesn't plays nice with cypress.
 * See https://github.com/cypress-io/cypress/issues/3200
 */
const disableSmoothScroll = () => {
  cy.document().then(document => {
    const node = document.createElement('style');
    node.innerHTML = 'html { scroll-behavior: inherit !important; }';
    document.body.appendChild(node);
  });
};

describe('test', () => {
  it('does stuff', () => {
    cy.visit(...);
    disableSmoothScroll();
    cy.get(...).scrollIntoView();
  })
})

I've solved this by adding class e2e to the html element when running in test mode, and setting

html:not(.e2e) {
  scroll-behavior: smooth;
}

Use only window.scrollTo(0,0);
Old model phone dont work if use window.scrollTo({top: 0, behavior: 'smooth'});

@jennifer-shehane Can I suggest we at least give out a warning when scroll-behaviour: smooth is in use and scrolling happens? I spent an hour trying to figure out why a simple test case didn't work, we can help a lot of people save time. I am willing to issue a PR with a little guidance regarding the appropriate place in the codebase to throw such a warning.

Ideally fixing the issue as @Bkucera described would be the best solution. https://github.com/cypress-io/cypress/issues/3200#issuecomment-461595024

There is already a PR open with a failing test case if someone would like to make a PR using that test case as a base. https://github.com/cypress-io/cypress/pull/3213/files

It is not just because of cypress itself. I have the same issue when I use nothing, but plain JS on Chrome, too. Seems to be a problem with the Chrome browser.

Just wanted to highlight what this issue is more clearly.

index.html

<html style="scroll-behavior: smooth">
<body>
  <div style="height: 4000px; background-color: red;"></div>
  <div style="height: 200px; background-color: green;">TEST</div>
</body>
</html>
it('should be able to find and click', () => {
  cy.visit('index.html')
  cy.get('div:last')
    .click()
})

If you remove the scroll-behavior: smooth, it correctly clicks.

Screen Shot 2020-07-06 at 3 19 19 PM

Hello,

I'm having a very tough time using the workaround. I don't have a single page app, so every time Cypress goes to a different route in my specs I have to re-disable smooth scrolling since the workaround above is dependant on injecting a style tag in the existing DOM.

Any suggestions? I tried putting disableSmoothScroll into a Cypress.on("window:load" but I got an error about a promise within a promise or something 馃

If you're using this workaround - you would have to call disableSmoothScroll after the cy.visit() https://github.com/cypress-io/cypress/issues/3200#issuecomment-505965470, so yes you would need to call this after every cy.visit().

You could also write a custom command so this is always called after your visit. https://on.cypress.io/custom-commands#Overwrite-Existing-Commands

Cypress.Commands.add('visitApp', (url) => {
  cy.visit(url)
  cy.document().then(document => {
    const node = document.createElement('style');
    node.innerHTML = 'html { scroll-behavior: inherit !important; }';
    document.body.appendChild(node);
  });
})

it('test', () => {
  cy.visitApp('https://...')
})

Thanks @jennifer-shehane

I think this will work for now. Unfortunately if any of my specs click on links I also have to remember to invoke this 馃槥

Hopefully a fix comes out someday 馃憖

This work around is great!
I personally adapted it slightly only to allow the site to continue to work as expected. This a "toggle" approach:

Maybe this will help others as it did me until something else comes in :)

in commands add a new function:

Cypress.Commands.add("toggleSmoothScrollStyle", () => {
    cy.document().then((document) => {
        let element = document.getElementById("smoothScroll_disable");
        if (typeof element != "undefined" && element != null) {
            element.remove();
        } else {
            const node = document.createElement("style");
            node.innerHTML = "html { scroll-behavior: inherit !important; }";
            node.setAttribute("id", "smoothScroll_disable");
            document.body.appendChild(node);
        }
    });
});

Then use this before and after to add and then remove this styling change from the DOM

it("A test name", () => {
    cy.toggleSmoothScrollStyle(); //Adds

    cy.get(".className").scrollIntoView().click();

    cy.toggleSmoothScrollStyle(); // Removes
});

Thanks everyone for providing workarounds; they do seem to work.

That said, I do really wish that the original issue were to be resolved. Having to factor this workaround into tests is quite arduous. Yes, you can write your own custom command to use the workaround after a cy.visit, but this doesn't account for uses of cy.reload or cy.go for which you also need to write custom commands. Furthermore, if your application sends you to a new page during a test (as a result of clicking a button or some other user interaction) you also have to deliberately apply the workaround in those instances since the scroll behaviour will have been reset to smooth.

It is not impossible to deal with, but it is much more work than I would expect to have to do in order to be able to write basic tests out of the box on a page that uses smooth scrolling.

Just my two cents.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

EirikBirkeland picture EirikBirkeland  路  3Comments

carloscheddar picture carloscheddar  路  3Comments

brian-mann picture brian-mann  路  3Comments

jennifer-shehane picture jennifer-shehane  路  3Comments

tahayk picture tahayk  路  3Comments