Avoid horizontal scroll with Cypress
Tags: webdev, javascript, beginners, frontend
Published: 2022-02-18 23:57:36

**Table of content**
- [Create the horizontal scroll](#create-the-horizontal-scroll)
- [Install Cypress](#install-cypress)
- [Test different viewport sizes](#test-different-viewport-sizes)
- [Conclusion](#conclusion)

---

Hi there! 

Last week I was working styling some elements and when I opened my dev tools console and looked into the mobile view, 
a horizontal scroll showed up. I thought, here we go again. ^^
So an idea came to my mind and I want to show you here, **how to test with Cypress if there is an element out of the viewport**.

In the first place, I want to leave the **[Github repo](https://github.com/Ismaestro/cypress-element-out-of-viewport)** where you can find all the code that I'm going to explain now. I'm going to use **Angular (v13)** to create the sample application, but you can choose whatever you like most.

Let's get down to business:

## Create the horizontal scroll

If you have already a horizontal scroll caused by elements outside the viewport, skip this step. 
If not, create an app, and add the element like this:

The app:
```xml
ng new cypress-element-out-of-viewport
```

Create the element:
```html
<!--- app.component.html --->
<div class="body__container--huge">
  THIS ONE IS OUT OF VIEWPORT
</div>
```

Just increase its width by more than 100%.
```css
/* app.component.css */
.body__container--huge {
  width: 200%;
}
```

You will see something like this if you run the app:
```xml
npm start
```

![gif showing up an horizontal scroll](https://res.cloudinary.com/ismaestro/image/upload/v1645198611/ismaelramos/posts/how-test-if-there-is-any-element-outside-the-viewport-with-cypress/scroll-horizontal_pqrttk.gif)

## Install Cypress

As I'm using Angular, I can run:

```xml
ng add @cypress/schematic
```

If not, more info [here](https://docs.cypress.io/guides/getting-started/installing-cypress) on how to install it.
Once you've done it, we only need to modify our first test a little bit to catch this buggy element.

And all the magic below. In the support index file, we need to create a function that returns an array with all the elements. All the credits to [Chris Coyier](https://dev.to/chriscoyier) for [this article](https://css-tricks.com/findingfixing-unintended-body-overflow/) and his marvellous function:
```typescript
// cypress/support/index.ts
Cypress.on('window:before:load', (win: any) => {
  win.getElementsOutOfViewport = () => {
    var elements = [];
    var all = win.document.getElementsByTagName("*"), i = 0,
      rect, docWidth = win.document.documentElement.offsetWidth;
    for (; i < all.length; i++) {
      rect = all[i].getBoundingClientRect();
      if (rect.right > docWidth || rect.left < 0) {
        elements.push(all[i]);
      }
    }
    return elements;
  }
});
```
We are also telling Cypress to store in the window object a function to calculate the elements that are outside the viewport, which name is 'getElementsOutOfViewport'. That way, we can call it in the spec file like this:

```typescript
// cypress/integration/spec.ts
describe('My First Test', () => {
  it('Visits the initial project page', () => {
    cy.visit('/')
    cy.window().then((win: any) => {
        const outOfViewportElements = win.getElementsOutOfViewport();
        assert.equal(outOfViewportElements.length, 0);
    })
  })
})
```

Here we are asserting that no elements out of the viewport exist otherwise, the test **will fail**.

To execute the test, you can type:
```xml
npm run cypress:open
```

The result is as follows:

![capture of the test failing](https://res.cloudinary.com/ismaestro/image/upload/v1645223737/ismaelramos/posts/how-test-if-there-is-any-element-outside-the-viewport-with-cypress/capture_utlhcz.jpg)


## Test different viewport sizes

Until here, I've been keeping things simple, but this kind of issue can happen in one resolution but not in other. At least, I think we should test 3 different sizes. Cypress can modify the viewport size very easily.

First, we are going to create a css rule to have horizontal scroll only in mobile. Replace the previous code with this:
```css
/* app.component.css */
@media (max-width: 576px) {
  .body__container--huge {
    width: 200%;
  }
}
```

Now, let's change the viewport size during the test execution:
```typescript
// cypress/integration/spec.ts
describe('My First Test', () => {
  it('Visits the initial project page', () => {
    cy.visit('/')
    cy.viewport('iphone-6') // <----- new line!
    cy.window().then((win: any) => {
        const outOfViewportElements = win.getElementsOutOfViewport();
        assert.equal(outOfViewportElements.length, 0);
    })
  })
})
```
This will change the resolution to match an iPhone 6 device (375x667). The result is that our test is failing again:
![capture of the test failing in mobile](https://res.cloudinary.com/ismaestro/image/upload/v1645225457/ismaelramos/posts/how-test-if-there-is-any-element-outside-the-viewport-with-cypress/capture-mobile_n56uwx.jpg)


Finally, I would like to point out a very useful inline javascript function ([from here](https://stackoverflow.com/a/52195436/1919749)) which, allow us to show the elements while we are developing:

```javascript
javascript:(function(d){var w=d.documentElement.offsetWidth,t=d.createTreeWalker(d.body,NodeFilter.SHOW_ELEMENT),b;while(t.nextNode()){b=t.currentNode.getBoundingClientRect();if(b.right>w||b.left<0){t.currentNode.style.setProperty('outline','1px dotted red','important');console.log(t.currentNode);}};}(document));
```

Just run this in the console and voilà:

![capture of the inline function and the elements outside](https://res.cloudinary.com/ismaestro/image/upload/v1645226231/ismaelramos/posts/how-test-if-there-is-any-element-outside-the-viewport-with-cypress/inline_hafuc6.jpg)

## Conclusion

With this kind of test I think we can forget about uploading to a production environment something wrong, but now that you are here, I want to know what do you think? Do you like this approach? Do you even test this kind of issue? Any suggestions?

Also, remember you have the repo with all the code **[here](https://github.com/Ismaestro/cypress-element-out-of-viewport)**.

I hope you have learned something new. If you think this might help other people, please hit the like button so that others can read it. ❤️

If you have any thoughts or questions, feel free to leave a comment!