1

I am testing the user management feature of my app on Rails 5 by cucumber and capybara. In the Users page, all users are listed and there is a "delete" link for each user. I have no idea about clicking the 4th user's delete in this page.

first(:link, "delete").click

I know this line above can select the first "delete", but what about those are not the first or the last?

<%= link_to "delete", user, method: :delete,
                            data: { confirm: "You sure?" } %>

This is how this link is implemented by erb.

Actually there is another question. As the code above, there is a JavaScript confirm popup after I click "delete". How to click that "OK" button? How do I confirm a javascript popup with Capybara? Answers here do not work.

Kita Lance
  • 33
  • 4
  • You need to scope your find to the correct section of the page -- How do you know it's the 4th user you want to click delete on? Use that info to scope to the correct place - Add the surrounding HTML to you question for more help on that (actual HTML not the erb template). – Thomas Walpole Apr 10 '19 at 21:05

2 Answers2

1

One option is to use all to find multiple matching elements and then index into them

all(:link, 'delete')[3].click # 0 based index so 3 is the fourth element

however depending on what exactly you're testing that can lead to fragile tests. If your requirement is to delete the user named "Joe Smith" and you had elements like

<div class="user">Bob Jones<a href=...>delete</a></div>
<div class="user">Joe Smith<a href=...>delete</a></div>
...

then you'd be better off scoping your click to the correct section of the page by doing something along the lines of

find('div.user', text: 'Joe Smith').click_link('delete')

Combining that with a system confirm would be

accept_confirm do
  find('div.user', text: 'Joe Smith').click_link('delete')
end

Note: accept_confirm only applies to system confirms (those opened by JS Window.confirm). If you have confirm "modals" from a JS widget library then you need to interact with them just like any other page content.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
1

Here's a similar approach but a bit different... ideally you would have posted a little more info on your spec and view but maybe this will help you.

Your links probably have a wrapper tag. If they don't add one. If they do add a unique id to each wrapper:

<% @user.each do |user| %>
  <div id="user_<%= user.id %>">
    <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
  </div>
  <div id="user_<%= user.id %>">
    <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
  </div>
  <div id="user_<%= user.id %>">
    <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
  </div>
<% end %>

Depending on how your building your spec data in your capybara tests you can do this:

it "clicks on a user", :js do
  let(:user4) { create(:user) }

  within("user_#{user4.id}") do
    accept_confirm { click_link("delete") }
  end
end

Or something like this:

it "clicks on a user", :js do
  let(:users) { create_list(:user, 4) }

  within("user_4") do
    accept_confirm { click_link("delete") }
  end
end

As Thomas mentioned you need to enable the javascript_driver for your test by adding the :js which will use selenium by default or other if you've configured it to.

dft
  • 625
  • 5
  • 15