pollx
pollx

Reputation: 699

How to test web page has scrolling disabled with Cypress?

Maybe it's an easy one, but my Cypress tests fail to test locked scrolling functionality.

So I have this React modal component which sets document.body.style.overflow = 'hidden' upon mount (client side only)

I have the following Cypress's test suite:

  it('page cant scroll when modal is open', () => {
    cy.get('[data-testid="button"]')
      .first()
      .click();

    cy.window().scrollTo('bottom');
    
    // scroll should be disabled
    cy.window()
      .its('scrollY')
      .should('equal', 0);

    // cy.get('[data-testid="modal"]')
    //   .scrollTo('bottom')
    //   .its('scrollY')
    //   .should('not.equal', 0);
  });

Error message: Timed out retrying after 4000ms: expected 802 to equal 0

Looks like Cypress is able to scroll the window even though this not possible when manually scrolling the page.

Any idea what the issue could be?

OP's edit: Scrolling the page programmatically still works (window.scrollTo()). The overflow property hides the scrollbar but this doesn't mean the scroll functionality is actually blocked (beyond a simple user interaction)

I was advised to use another approach for testing the scroll freeze through pagedown and pageup key navigation. Using the mentioned keys will be blocked on the actual page and user won't be able to scroll.

  it('page cant scroll when modal is open', () => {
    cy.get('[data-testid="button"]')
      .first()
      .click();

    cy.get('body').type('{pagedown}');

    cy.window()
      .its('scrollY')
      .should('equal', 0);

    cy.get('[data-testid="overlay"]').click();

    cy.get('body').type('{pagedown}');

    cy.window()
      .its('scrollY')
      .should('not.equal', 0);
  });

As with the previous code example, it makes sense for this snippet to throw error as well. Timed out retrying after 4000ms: expected 46 to equal 0.

Upvotes: 2

Views: 2388

Answers (3)

SandroMarques
SandroMarques

Reputation: 6534

This is my solution to verify if the horizontal scroll is enabled:

  it('should guarantee that the horizontal scroll is not activated', () => {
    // Try to scroll the page to the right
    cy.scrollTo('right', { offset: 100 })

    // Get the horizontal scroll position
    cy.window().then((win) => {
      const scrollLeft = win.scrollX || win.pageXOffset
      // Check if the horizontal scroll position is at the beginning (equal to zero)
      expect(scrollLeft).to.equal(0)
    })
  })

Upvotes: 0

Richard Matsen
Richard Matsen

Reputation: 23463

It seems to me that testing that expect($el.document.body.style.overflow).to.eq('hidden') is not very useful because you already know that to be the case. You say

I have this React modal component which sets document.body.style.overflow = 'hidden' upon mount

Are you testing the React Modal component or how it interacts with the app?


Taking a look at the Material-UI Modal (Simple Modal demo), when I click on the "Open Modal" button it applies the same style to body

<body dir="ltr" style="padding-right: 16px; overflow: hidden;">

Visually the scrollbar has gone when the modal is open.

The best approach I found was to measure widths before and after opening the modal. The scrollbar is actually attached to the html element, so this is what I measured (relative to the window)

cy.visit('https://material-ui.com/components/modal/');

cy.window().then(win => {
  const htmlWidth = Cypress.$('html')[0].scrollWidth;
  const scrollBarWidth = win.innerWidth - htmlWidth;
  expect(scrollBarWidth).to.be.gt(0);                 // scrollbar is present
})

cy.contains('button', 'Open Modal').click();          // open the modal

cy.window().then(win => {
  const htmlWidth = Cypress.$('html')[0].scrollWidth;
  const scrollBarWidth = win.innerWidth - htmlWidth;
  expect(scrollBarWidth).to.be.eq(0);                 // scrollbar is absent
})

Upvotes: 4

Manuel Abascal
Manuel Abascal

Reputation: 6312

You can disable a scroll behavior on a web page by setting the overflow property to hidden like so window.document.body.style.overflow = 'hidden'.

Assuming the React modal component sets document.body.style.overflow = 'hidden' as you mentioned previously.

You could assert that scrolling is not enabled with one-liner like so:

cy.window().then(($el) => expect($el.document.body.style.overflow).to.eq('hidden'));

Upvotes: 1

Related Questions