Cypress Scroll Position Assertions
This post goes through approaches to asserting on the scroll position.
First we’ll see how to assert that we’re at the top of the page.
Next we’ll look at 2 approaches to assert that we’ve scrolled to an element.
The examples for this post are available at github.com/HugoDF/cypress-scroll-position-assertions/.
Table of Contents
Cypress read and assert window scroll position/offset
Cypress exposes window
using cy.window()
which is a chainable Cypress wrapper. We can then use cy.window().its('scrollY')
to unpack the value we want to assert against. Finally we chain the assertion .should()
to assert against the window’s scrollY. For example to check that we’ve scrolled, we can write: cy.window().its('scrollY').should('not.equal', 0)
.
A setup for a test could look like the following, we us cy.visit('/')
to load “/”, cy.scrollTo('bottom')
to trigger a scroll to the bottom of the page, and cy.window().its('scrollY').should('not.equal', 0)
to check that we’ve started scrolling.
beforeEach(() => {
cy.visit('/')
.scrollTo('bottom')
.window()
.its('scrollY')
.should('not.equal', 0);
});
Cypress assert scroll to top of the page
Given the following application code which listens to clicks on the “Scroll to Top” button and smooth-scrolls to the top of the page (top: 0
).
<div class="demos">
<div class="spacer">Spacer 1</div>
<div class="spacer">Spacer 2</div>
<div class="spacer">Spacer 3</div>
<div data-testid="scroll-target" data-js="scroll-target">Scroll Target</div>
<div class="spacer">Spacer 4</div>
<div class="spacer">Spacer 5</div>
<div class="controls">
<button data-testid="scroll-to-top" data-js="scroll-to-top">
Scroll To Top
</button>
<button data-testid="scroll-to-element" data-js="scroll-to-element">
Scroll To Element
</button>
</div>
</div>
<script>
document.querySelector('[data-js=scroll-to-top]').addEventListener('click', () => {
window.scroll({ top: 0, behavior: 'smooth' });
});
</script>
To check that clicking “Scroll to Top” does what’s expected, we can use cy.click('[data-testid=js-scroll-to-top]')
to trigger the click. We can follow that up with an assertion against cy.window().its('scrollY')
. For that assertion to check that the scrollY is 0, in other words, the scroll position is at the top of the page, we use .should('equal', 0)
.
We can check that on click of the “Scroll to Top” yield the correct output as follows.
beforeEach(() => {
cy.visit('/');
cy.scrollTo('bottom').window().its('scrollY').should('not.equal', 0);
});
it('scrolls to top', () => {
cy.get('[data-testid=scroll-to-top]').click();
cy.window().its('scrollY').should('equal', 0);
});
Running the above test in the Cypress UI yields the following result.
Cypress assert scrolled to an element
Given the following application code which listens to clicks on the “Scroll to Target” button and smooth-scrolls to “Scroll Target” element.
<div class="demos">
<div class="spacer">Spacer 1</div>
<div class="spacer">Spacer 2</div>
<div class="spacer">Spacer 3</div>
<div data-testid="scroll-target" data-js="scroll-target">Scroll Target</div>
<div class="spacer">Spacer 4</div>
<div class="spacer">Spacer 5</div>
<div class="controls">
<button data-testid="scroll-to-top" data-js="scroll-to-top">
Scroll To Top
</button>
<button data-testid="scroll-to-element" data-js="scroll-to-element">
Scroll To Element
</button>
</div>
</div>
<script>
// handler for the "scroll-to-top"
document.querySelector('[data-js=scroll-to-element]').addEventListener('click', () => {
document.querySelector('[data-js=scroll-target]').scrollIntoView({
behavior: 'smooth'
});
});
</script>
In order to test that scrolling to an element works, we need to assert that cy.window().its('scrollY')
is equal to the offset of the scroll target.
There are 2 approaches to do this.
The first is to leverage cy.$$()
to get a jQuery wrapper. Once we’ve got the wrapper, we can use jQuery’s offset()
function and read the top
property of it. The whole expression looks like cy.$$().offset().top
, in the case of this test cy.$$('[data-testid=scroll-target]').offset().top
.
The full assertion then reads cy.window().its('scrollY').should('equal', cy.$$('[data-testid=scroll-target]').offset().top)
. In other words, the window scroll position equals the offset top of the “Scroll Target” element.
beforeEach(() => {
cy.visit('/');
cy.scrollTo('bottom').window().its('scrollY').should('not.equal', 0);
});
// tests from previous section
it('scrolls to target - cy.$$ + jQuery.offset()', () => {
cy.get('[data-testid=scroll-to-element]').click();
// Using cy.$$ (jQuery) + offset().top
cy.window()
.its('scrollY')
.should('equal', cy.$$('[data-testid=scroll-target]').offset().top);
});
The altertive is to use cy.get()
(in our case cy.get('[data-testid=scroll-target]')
), which returns a Cypress wrapper. Now we can’t access jQuery’s offset
or Element’s offsetTop
on the Cypress wrapper. We need to .then()
the selection to access the element.
In our .then
, per cy.get().then(element => {})
we can unwrap the jQuery wrapper using element.get(0)
or element[0]
.
The full .then
is therefore cy.get('[data-testid=scroll-target]').then((element) => element[0].offsetTop)
.
We can chain another .then
to this initial one, which takes the offset
from the previous then
.
Finally we can use cy.window().its('scrollY')
and assert that the scrollY equals the offset from the element in the previous step.
In full:
beforeEach(() => {
cy.visit('/');
cy.scrollTo('bottom').window().its('scrollY').should('not.equal', 0);
});
// tests from previous section
it('scrolls to target - cy.get + unwrap jQuery reference', () => {
cy.get('[data-testid=scroll-to-element]').click();
// Using cy.get() + unwrapping the jQuery reference with `el[0]` or `el.get(0)`
cy.get('[data-testid=scroll-target]')
.then((element) => element[0].offsetTop)
.then((offset) => cy.window().its('scrollY').should('equal', offset));
});
Running the above tests in the Cypress UI gives the following output:
We’ve now seen how to read the window’s scroll position and assert against it using .should()
We’ve then seen how to check that the window is scrolled to the top and 2 approaches to check that we’ve scrolled to an element.
All the code examples for this post are available at github.com/HugoDF/cypress-scroll-position-assertions/.
Photo by Mike Lewis HeadSmart Media on Unsplash.
Get The Jest Handbook (100 pages)
Take your JavaScript testing to the next level by learning the ins and outs of Jest, the top JavaScript testing library.
orJoin 1000s of developers learning about Enterprise-grade Node.js & JavaScript