---
title: "Fix Flaky Rails System Tests caused by slow scrolling or animations"
description: "Fix failing browser tests caused by slow scrolling behavior or animations. Learn how to find then and understand how to fix them."
url: "https://qameta.com/posts/fix-flaky-rails-system-tests-caused-by-slow-scrolling-or-animations/"
image: "https://qameta.com/images/posts/chrome-chromium-smooth-scrolling-flag.png"
---

# Fix Flaky Rails System Tests caused by slow scrolling or animations

![Chrome and Chromium Smooth scrolling flag](https://qameta.com/images/posts/chrome-chromium-smooth-scrolling-flag.png)

Flakiness on browser-based [system
tests](https://edgeguides.rubyonrails.org/testing.html#system-testing)
(integration tests) in [Ruby on Rails](https://rubyonrails.org) may have a lot
of different reasons. One is scrolling, which may be slowed down by browser
setup (smooth scrolling), JavaScript callbacks which result in some kind of
events like for animations, etc.

Such problems are not [Ruby on Rails](https://rubyonrails.org) related and even
not a programming language. They are mostly not related to a single browser like
[Google Chrome](https://www.google.de/intl/de/chrome/browser/),
[Chromium](https://www.chromium.org), and
[Firefox](https://www.mozilla.org/en/firefox/) only. They are also not browser
driver specific like
[Selenium](https://github.com/teamcapybara/capybara#selenium) or
[Cuprite](https://github.com/rubycdp/cuprite). Let's dive in and check, how to
analyze them, and figure out and try fix such problems.

## Randomly or constantly failing tests

This is an example of a failing test. If you encounter random or constant
failing tests with a similar message or maybe other, keep on reading:

```txt
E

Error:
BikesTest#test_update_a_bike:
Capybara::Cuprite::MouseEventFailed: Firing a click at coordinates
[180.65625, 2529.96875] failed. Cuprite detected another element with CSS
selector "none" at this position. It may be overlapping the element you are
trying to interact with. If you don't care about overlapping elements, try using
node.trigger("click").
test/system/bikes_test.rb:79:in `block in <class:BikesTest>'
```

According to this error, there is an element at the browser pixel position
**[180.65625, 2529.96875]** that has some kind of overlapping element. Let's try
to figure out, what is wrong first.

## Analyzing the problem

First of all, you need to figure out, what is going wrong. In browser testing
there are more things, you have to consider. Let's have a look at a common
browser test called [system
test](https://edgeguides.rubyonrails.org/testing.html#system-testing) in Ruby on
Rails:

```ruby
require "application_system_test_case"

class BikesTest < ApplicationSystemTestCase
  test "update a bike" do
    bike = bikes(:one)
    visit edit_bike_url(bike)

    fill_in "model", with: "Super X5v"

    click_on "Save" # <-- here the test fails

    assert_selector ".flash_message", "Bike successfully updated."
  end
end
```

According to the test, we open a [web
form](https://developer.mozilla.org/en-US/docs/Learn/Forms) to update a bike,
change one value in input\_field named model, and click "Save" to
[submit](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit)
the form and store the change in a database. This is a pretty simple test. Why
may such a test fail?

To figure out, what is wrong, let us open the browser and check the page. This
is done through
[save\_and\_open\_page](https://github.com/teamcapybara/capybara#debugging) in
[Capybara](https://github.com/teamcapybara/capybara) before saving the change.
This may look something like this:

```diff
require "application_system_test_case"

class BikesTest < ApplicationSystemTestCase
  test "as update a bike" do
    bike = bikes(:one)
    visit edit_bike_url(bike)

    fill_in "model", with: "Super X5v"

+   save_and_open_page # <-- debugger: save html page and open it in browser
    click_on "Save"

    assert_selector ".flash_message", "Bike successfully updated."
  end
end
```

For me, the page to test looked like expected in Browser. Even the "Save" button
was there and was visible without extra CSS or JavaScript.

Next, I checked the screenshot, which is saved for every failed test. You can
make one yourself if it is not done automatically by changing your test:

```diff
require "application_system_test_case"

class BikesTest < ApplicationSystemTestCase
  test "as update a bike" do
    bike = bikes(:one)
    visit edit_bike_url(bike)

    fill_in "model", with: "Super X5v"

+   save_and_open_screenshot # save screenshot as image and open it
    click_on "Save"

    assert_selector ".flash_message", "Bike successfully updated."
  end
end
```

At first, I couldn't see any problems. One thing was, that I couldn't see the
save button as it was outside of the browser window. To have it on the
screenshot, you have to scroll down first. Dependent on your driver you can use
one of these commands to scroll down to the relevant position:

* Selenium: [scroll_by(x,
  y)](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Selenium/Scroll#scroll_by-instance_method)
* Selenium: [scroll_to(element, location, position =
  nil)](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Selenium/Scroll#scroll_to-instance_method)
* Cuprite: [page.driver.scroll_to(left,
  top)](https://github.com/rubycdp/cuprite#clickingscrolling)

As I am using [Cuprite](https://github.com/rubycdp/cuprite), the code looks like
this:

```diff
require "application_system_test_case"

class BikesTest < ApplicationSystemTestCase
  test "as update a bike" do
    bike = bikes(:one)
    visit edit_bike_url(bike)

    fill_in "model", with: "Super X5v"

+    page.driver.scroll_to(0, 2000) # command for scrolling 2000 pixels down
+    sleep 1 # <-- VERY IMPORTANT: Wait as scrolling is asynchronously

+   save_and_open_screenshot # save screenshot as image and open it
    click_on "Save"

    assert_selector ".flash_message", "Bike successfully updated."
  end
end
```

**IMPORTANT:** We are working with asynchronous processes running in parallel on
one or mostly many may be fast or slow CPUs with more or less RAM. If you tell
the browser to do something, dependent on the setup and the page you are testing
it may take more or less time to finish the task.

As [scroll\_to]() and [save\_and\_open\_screenshot]() are asynchronous commands,
you need to wait between them a little bit to see the result of the `scroll_to`
command before creating a screenshot.

Suddenly the test started to work and stopped failing. There was something
related to scrolling or elements being outside of the [Browser
Viewport](https://en.wikipedia.org/wiki/Viewport).

## Ask search engines

It is an easy task to ask a search engine. I did some searching and found this
page:

* [Capybara, Cuprite, and a slow-scrolling Chrome
  ARM](https://codemeister.dev/capybara-cuprite-and-a-slow-scrolling-chrome-arm)
  <- Don't follow the advise blindly!

It looked very promising and seems to be the problem my test suite has.

**ATTENTION:** Read it first, most things won't work for you and some are just
wrong due to browser updates.

I've updated my [Capybara](https://github.com/teamcapybara/capybara) setup to
have this option set:

```diff
# test/application_system_test_case.rb

   # https://github.com/rubycdp/cuprite#install
   # no-sandbox must be disabled for CI / Github Actions
+  # disable smooth scrolling as it breaks long pages
   Capybara.register_driver :cuprite do |app|
     browser_options = {}.tap do |opts|
       opts['no-sandbox'] = nil if ENV['CI']
+      opts['disable-smooth-scrolling'] = true # <-- This is for old
+                                              # Chrome/Chromium versions
     end
   end
```

It was still not working like expected on a MacOS System using an ARM based CPU
from Apple. The tests failed like without this
[flag](https://developer.chrome.com/blog/browser-flags/).

**ATTENTION:** I've used browser control and browser automation in many
different projects outside of software testing and know, that [browser
flags](https://developer.chrome.com/blog/browser-flags/) and options may change
in behavior and name and get removed at any time.

As I was using [Chromium](https://www.chromium.org) in tests, I checked the
existence of this flag in Chromium:

![Chrome and Chromium Smooth scrolling flag](https://qameta.com/images/posts/chrome-chromium-smooth-scrolling-flag.png)

As you can see, this flag was renamed from **disable-smooth-scrolling** to
**smooth-scrolling**. I have to align it:

```diff
# test/application_system_test_case.rb

   # https://github.com/rubycdp/cuprite#install
   # no-sandbox must be disabled for CI / Github Actions
   Capybara.register_driver :cuprite do |app|
     browser_options = {}.tap do |opts|
       opts['no-sandbox'] = nil if ENV['CI']
+      # disable smooth scroling as it breaks on long pages
+      opts['smooth-scrolling'] = false
     end
   end
```

But there was another thing that is also [Operating System
(OS)](https://en.wikipedia.org/wiki/Operating_system) specific. This flag is
**unavailable** on [MacOS](https://en.wikipedia.org/wiki/MacOS). Such flags may
be unavailable even on a specific [CPU
architecutre](https://en.wikipedia.org/wiki/Processor_(computing)) for the same
OS. Check things in software, setup, documentation, and if possible in code to
really know it.

As this option was fine for my [CI
systems](https://en.wikipedia.org/wiki/Continuous_integration) using
[Linux](https://en.wikipedia.org/wiki/Linux) as OS, this was a
useful flag to have in the Capybara setup.

### Animations

As some parts of the page to test were using animations, I've searched for more
options and stumbled on this [stackoverflow](https://stackoverflow.com)
question:

* [Turn off animations in Capybara
  tests](https://stackoverflow.com/questions/19662287/turn-off-animations-in-capybara-tests)

I've tried the [most upvoted
answer](https://stackoverflow.com/a/60992271/364590) and the tests started
working again. The change was simple:

```diff
# test/application_system_test_case.rb

  # Use cuprite
   Capybara.default_driver = Capybara.javascript_driver = :cuprite

+  # Disable animations to speed up tests and avoid flakiness through animations
+  Capybara.disable_animation = true
+
   driven_by Capybara.javascript_driver
```

This feature was introduced in [Capybara
v3.2.0](https://github.com/teamcapybara/capybara/blob/master/History.md#version-320).
You can check the documentation here:
[disable\_animation=](https://www.rubydoc.info/gems/capybara/3.2.0/Capybara%2FSessionConfig:disable_animation=).

## Summary

By disabling animation through Capybara in Browser based tests should become
more stable - especially for heavily animated applications. It is also a big
help with randomly failing tests. Bootstrap is using animations to display
modals.

This was again a lesson for me to take more time and look at Changelogs/History
for new features or relevant changes, which may improve developer experience or
encounter new problems, which did not exist before.
