Capybara better practices

Today I Learned: Capybara better practices Never re-invent the wheel Capybara feature specs can be frustrating because it’s difficult to get them to pass 100% of the time. This post will teach you how to avoid a certain race condition, using only built-in Capybara methods. Often times, it’s easy to wonder why your specs run so slow […]

Today I Learned: Capybara better practices

Never re-invent the wheel

Capybara feature specs can be frustrating because it’s difficult to get them to pass 100% of the time. This post will teach you how to avoid a certain race condition, using only built-in Capybara methods.

Often times, it’s easy to wonder why your specs run so slow or why your spec is blinky. Most of the times it is because we’ve used something that just works( or maybe not). You could, of course, take a few minutes to read about it before using it, but since you’re probably as lazy as me, here’s a blog post explaining it.

For example, let’s imagine you are writing a spec that clicks on something, waits for a background task to be completed which updates a certain field, and then finally validates that field. (Oofff…lots of steps.) There are many ways to write this spec:

# spec/features/user_page_spec.rb
describe UserPage do
it "validates text on the form"
click "validate"
expect(find('.sample_form_text').text).to eq('validated text')
end
end

The above spec works just fine, but it can be blinky. How?

Let's set some assumptions early before I go ahead:

Capybara.default_max_wait_time = 5. I have the set the default_max_wait_time of capybara to 5 seconds.

Now let’s go through each step. First, you click on validate on the page and the background task gets triggered. Now it’s going to try to find the text on the class: sample_form_text and validate it with validated text. In most cases, this works fine. But this call find('.sample_form_text').textis almost instantaneous. So if the background task takes some time to fill the page with the text, the spec is going to fail. How can we fix this?

One method I like is from this post, https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara

# spec/support/wait_for_ajax.rb
module WaitForAjax
  def wait_for_ajax
    Timeout.timeout(Capybara.default_max_wait_time) do
    loop until finished_all_ajax_requests?
  end
end
  def finished_all_ajax_requests?
    page.evaluate_script(‘jQuery.active’).zero?
  end
end
RSpec.configure do |config|
  config.include WaitForAjax, type: :feature
end

So you can use the background task as shown below:

click "validate"
wait_for_ajax
expect(find('.sample_form_text').text).to eq('validated text')

Another option is to use something capybara already provides. Shown below:

Before:
click "validate"
expect(find('.sample_form_text').text).to eq('validated text')
After:
click "validate"
expect(find('.sample_form_text', text: expected_text)).to have_content(expected_text)

By default, the find with text option waits for the text to be available and that fixes the blinkiness.

Hope this helped! We’ll be back soon with another edition of Today I Learned

References:


Capybara better practices was originally published in LendingHome Tech on Medium, where people are continuing the conversation by highlighting and responding to this story.

Source: LendingHome