0
votes

_customers_table.html.erb

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Phone number</th>
      <th>Description</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @customers.each do |customer| %>
      <tr>
        <td><%= customer.name %></td>
        <td><%= customer.phone_number %></td>
        <td><%= customer.description %></td>
        <td><%= link_to customer.status.humanize, toggle_status_customer_path(customer), class: "move-to-black" %></td>
        <td><%= link_to 'Show', customer %></td>
        <td><%= link_to 'Edit', edit_customer_path(customer) %></td>
        <td><%= link_to 'Destroy', customer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>


creating_customer_spec.rb

require 'rails_helper'

describe "creating new customer", type: :feature do
  let(:customer) { customer = FactoryBot.create(:customer) }

  it 'should create new customer' do
    visit '/customers/new'
    fill_in 'Name', with: customer.name
    fill_in 'Phone number', with: customer.phone_number
    click_button 'Create Customer'
    expect(page).to have_content "#{customer.name}"
  end

  it 'should change customer status' do
    visit '/'
    click_on customer.status.humanize
    expect(customer).to have_status "move_to_white_list"
  end
end


The first example 'should create new customer' pass but I get error with the second one 'should change customer status'

Capybara::ElementNotFound:
       Unable to find link or button "Move to black list"

The element exists and you can see it on the image. I would really appreciate if someone can help.enter image description here

I changed the second example, now it works.This is my mistake I didn’t explain it well, the “black list” table is on a different view and when the status changes, it moves to another page so actualy it's not possible to find it there.

    require 'rails_helper'

describe "creating new customer", type: :feature do
  let!(:customer) { customer = FactoryBot.create(:customer) }

  it 'should create new customer' do
    visit '/customers/new'
    fill_in 'Name', with: customer.name
    fill_in 'Phone number', with: customer.phone_number
    click_button 'Create Customer'
    expect(page).to have_content "#{customer.name}"
  end

  it 'should change customer status' do
    visit '/customers'
    click_on customer.status.humanize
    expect(page).to have_content "Customer #{customer.name} moved to black list"

    visit '/black_list'
    expect(customer.reload.status).to eq "move_to_white_list"
  end
end
1
Have you maybe tried click_link instead of click_on in your test? - Clepsyd
I can't see your "create customer" element there - Horacio
@Clepsyd click_on is an alias for click_link_or_button so using just click_link wouldn't make any difference. - Thomas Walpole

1 Answers

0
votes

You have a number of issues here. Firstly you're going to the page before the customer instance has been created, which means it won't be shown on the page. This is because let lazily evaluates - see https://relishapp.com/rspec/rspec-core/v/3-8/docs/helper-methods/let-and-let - and will only create the customer the first time customer is called in the test.

visit '/' # <= no customer instance exists here
click_on customer.status.humanize # <= customer instance actually created here

You can fix that by using the non lazily evaluated version let! which will always create a customer instance, or by calling customer before calling visit

Secondly, your test is modifying the customer instance in the DB, but never reloading the instance you have in memory (so the new status would never be seen)

expect(customer.reload).to have_status "move_to_white_list"

Thirdly, If you're using a driver that supports asynchronous behavior (any driver other than rack-test) there is no guarantee any side effects caused by the action methods (click_on, etc) will have completed before the method call returns. That means your expectation will most likely get called before the customer instances status has changed. To fix that the have_status matcher would need to be written to have retrying behavior (like all the Capybara provided matchers have) and to have the reloading behavior in the matcher too. This is a major reason why it's generally not a good idea to be verifying DB changes in system/feature tests, and instead stick to verifying changes in the UI.