I’m currently working in a small team developing an application with a rich UI and massive usage of ReactJS components on the pages. To test the behavior of the pages we’re using Capybara (2.17) with Selenium as a web driver (3.8), and at some point, it appeared that our test suite is wildly inconsistent and has a dozen of flickering tests. Some of the test examples were failing with a rate near 30%, and taking into account we have about 600 feature tests, a great amount of CI builds were failing.

The most common reason for failures in our case was missing elements on the pages f.e. missing modal window’s selectors or missing popups.

A typical scenario example:

And a typical failure:

Capybara::ElementNotFound:

Unable to find visible css ".modal-content"

In the provided example there’s a JS listener on the link which opens the modal window on click event. It turned out that Capybara does not always fire the onClick events and therefore the modal window does not appear.

The reason behind that is the fact that web driver’s click() method is asynchronous and sometimes Capybara starts the code execution before JS finishes initializing its listeners. Ideally, we should wait till page load completes and start the test itself after, but currently, there are no known reliable ways to detect if the browser has finished loading the page.

For Poltergeist driver there’s a known workaround — trigger() method. It allows passing the event execution to PhantomJS which presumably executes it after all other page JS calls are finished.

Selenium web driver does not support trigger() method, but we can use raw JS.

The execute_script method will add click() function to the bottom of JS call stack and the click will be executed after other JS functions are finished except for the ones using async callbacks.

Final test example:

The provided solution helped to improve the test suite consistency and so far works fine.