Andy Harvey
Andy Harvey

Reputation: 12663

How to test Ajax responses with Capybara?

I have an ajaxified link in a Rails app that, when clicked, results in changes to the DOM.

I'm using Capybara to test for this DOM change. The test is failing, but in the browser this user interaction results in the expected DOM change.

I suspect the test is not waiting for the ajax request to complete. However, I had understood that expect(page).to have_selector does wait until said element exists.

What am I doing wrong, and what is the correct way to test this interaction?

The code is as follows:

#objects/show.html.erb
...
<div class='like-container'>
  <%= render partial: "shared/like_button" %>
</div>
...


#shared/like_button
<% if current_user.likes? @likable %>
  <%= link_to 'Unlike', 
    unlike_path(#params),
    id:"#{@likable.class.name.underscore }_#{ @likable.id }_like", 
    class: "unlike-btn",
    method: :delete, 
    remote: true 
    %>
<% else %>
  <%= link_to 'Like', 
    like_path(#params), 
    id: "#{@likable.class.name.underscore }_#{ @likable.id }_like",
    class: "like-btn",
    method: :post, 
    remote: true 
    %>
<% end %>


#likes/create.js
$('#<%= @likable.class.name.underscore %>_<%= @likable.id %>_like').replaceWith('<%= j render partial: "shared/like_button" %>');


#likes/destroy.js 
$('#<%= @likable.class.name.underscore %>_<%= @likable.id %>_like').replaceWith('<%= j render partial: "shared/like_button" %>');


#user_likes_object_spec.rb
feature 'likes object' do
  before :each do
    @object = create :object
    @user   = create :user
    login_as @user
    visit object_path @object
  end

  scenario 'it creates and then destroys like when clicked', js: true do
    expect(page).to have_link "Like", href: like_path(#params)
    click_link 'Like'
    # the test is failing on the following line
    # Failure/Error: expect(page).to have_selector("a.unlike-btn")
    # expected to find css "a.unlike-btn" but there were no matches
    expect(page).to have_selector("a.unlike-btn")
    click_link 'Unlike'
    expect(page).to have_selector("a.like-btn")
  end
end

Why isn't expect(page).to have_selector("a.unlike-btn") waiting until this DOM element exists?

Upvotes: 1

Views: 2803

Answers (1)

SirUncleCid
SirUncleCid

Reputation: 187

This article explains setting a default wait time by putting:

Capybara.default_max_wait_time = 10

into your RSpec config file.

This article explains actually waiting for the DOM to completely update.

Upvotes: 3

Related Questions