Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting inconsistent "Unable to find css" errors with Rspec + Capybara + Ember

What's Happening

In our Rspec + Capybara + selenium (FF) test suite we're getting A LOT of inconsistent "Capybara::ElementNotFound" errors.

The problem is they only happen sometimes. Usually they won't happen locally, they'll happen on CircleCi, where I expect the machines are much beefier (and so faster)?

Also the same errors usually won't happen when the spec is run in isolation, for example by running rspec with a particular line number:42.

Bare in mind however that there is no consistency. The spec won't consistently fail.

Our current workaround - sleep

Currently the only thing we can do is to litter the specs with 'sleeps'. We add them whenever we get an error like this and it fixes it. Sometimes we have to increase the sleep times which is making out tests very slow as you can imagine.

What about capybara's default wait time?

Doesn't seem to be kicking in I imagine as the test usually fails under the allocated wait time (5 seconds currently)

Some examples of failure.

Here's a common failure:

visit "/#/things/#{@thing.id}"
find(".expand-thing").click

This will frequently result in:

Unable to find css ".expand-thing"

Now, putting a sleep in between those two lines fixes it. But a sleep is too brute force. I might put a second, but the code might only need half a second.

Ideally I'd like Capybara's wait time to kick in because then it only waits as long as it needs to, and no longer.

Final Note

I know that capybara can only do the wait thing if the selector doesn't exist on the page yet. But in the example above you'll notice I'm visiting the page and the selecting, so the element is not on the page yet, so Capybara should wait.

What's going on?

like image 939
andy Avatar asked Oct 31 '22 22:10

andy


1 Answers

Figured this out. SO, when looking for elements on a page you have a few methods available to you:

first('.some-selector')
all('.some-selector') #returns an array of course
find('.some-selector')

.first and .all are super useful as they let you pick from non unique elements.

HOWEVER .first and .all don't seem to auto-wait for the element to be on the page.

The Fix

The fix then is to always use .find(). .find WILL honour the capybara wait time. Using .find has almost completely fixed my tests (with a few unrelated exceptions).

The gotcha of course is that you have to use more unique selectors as .find MUST only return a single element, otherwise you'll get the infamous Capybara::Ambiguous exception.

like image 173
andy Avatar answered Nov 15 '22 03:11

andy