简体   繁体   中英

Rspec Capybara test with ajax call not updating record

I have a form where when a user submits an ajax form with a single name field, a record is created that belongs to a Template object. This all works fine manually, but for some reason when I test this via rspec its telling me that the association was not created. Why isn't the template object updated here?

describe "edit page" do
  before(:each) do
    visit edit_admin_template_path(template)
  end

  context "form sections", js: true do  
    it "allows admin to create one" do
      find("#btn-add-section").click
      within('#new_form_section') do
        fill_in 'Name', with: "Personal Info"
        click_button "Create Section"
      end
      expect(template.form_sections.length).to eq(1)
    end
  end
end

This is the failure that I am getting

Failure/Error: expect(template.form_sections.length).to eq(1)

   expected: 1
        got: 0

   (compared using ==)

UPDATE: just noticed this in the rspec output

An error occurred in an after hook
    ActionView::Template::Error: undefined method `form_sections' for nil:NilClass

so its telling me that the template object does not exist, then its able to compare it afterwards?

UPDATE 2: So it appears that the issue is waiting for the ajax call to complete in capybara, before expecting. I added this to the spec and it now works, obviously I need to refacotr this to something better like a helper

it "allows admin to create one" do
  find("#btn-add-section").click
  within('#new_form_section') do
    fill_in 'Name', with: "Personal Info"
    click_button "Create Section"
  end
  sleep(10) #this waits for the request to complete
  expect(template.form_sections.length).to eq(1)
end

The key is telling RSpec to wait for the ajax call to complete before doing any expectations. This is a great post on the solution that I used:

Thoughtbot: Automatically Wait for AJAX with Capybara

Just in case others stumble upon this, rather than using sleep you could test based on the UI itself. Capybara will wait for that element to reload, if you use have_css or find matchers, like this:

expect(page).to have_css("#form-page-two", visible: :visible) #this will force test to wait for ajax call

Capybara.automatic_reload must not be set to false. (defaults to true)

This strategy will reduce the run time of your test suite; if the test only took 2 or 3 seconds to load it will only wait that long (not 10).

However, it can be frustrating to write because of intermittent failures. To avoid this you may need to bump up the wait time setting.

Capybara.default_max_wait_time = 10

https://github.com/teamcapybara/capybara#asynchronous-javascript-ajax-and-friends

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM