Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capybara is not waiting for ajax to finish

I'm working on a application which consist of a EmberJS frontend, which talk to a Rails server via REST. In my application goes through a wizard to create a job, so i would like to test if that job is created, this is my test.

  feature 'Processing step three', :js => true do
    background do
      to_step_2
      to_step_3
    end

    scenario 'Creating job', js: true do
      within '#login' do
        fill_in 'Email', with: @customer.email
        fill_in 'Password', with: @customer.password

        click_button 'Login'
      end

      expect { click_link 'Create job' }.to change(Job, :count).by(1)
    end
  end

So when the user has filled in everything, lastly they click on create job, just like my test describes. This works fine when i do it manually, but when i run my spec i get.

1) Creating a new job Processing step three Creating job
     Failure/Error: expect { click_link 'Create job' }.to change(Job, :count).by(1)
       count should have been changed by 1, but was changed by 0
     # ./spec/features/creating_a_new_job_spec.rb:103:in `block (3 levels) in <top (required)>'

Now if i look at my test log i can see, that capybara runs the count, before my job is inserted

Completed 200 OK in 36ms (Views: 6.0ms | ActiveRecord: 11.2ms)
Started POST "/api/jobs" for 127.0.0.1 at 2013-12-08 14:15:00 +0100
Processing by Api::JobsController#create as JSON
  Parameters: {"job"=>{"description"=>"This is a test description of the service i would like to receive.", "zip"=>"2400", "available_from"=>"24 - 12 - 2013", "available_next"=>false, "customer_id"=>"1", "service_id"=>"1", "service_field_id"=>"1"}}
Unpermitted parameters: zip
   (11.3ms)  SELECT COUNT(*) FROM "jobs"
   (1.2ms)  BEGIN
  SQL (2.5ms)  INSERT INTO "jobs" ("available_from", "available_next", "created_at", "customer_id", "description", "service_field_id", "service_id", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"  [["available_from", Tue, 24 Dec 2013 00:00:00 UTC +00:00], ["available_next", false], ["created_at", Sun, 08 Dec 2013 13:15:00 UTC +00:00], ["customer_id", 1], ["description", "This is a test description of the service i would like to receive."], ["service_field_id", 1], ["service_id", 0], ["updated_at", Sun, 08 Dec 2013 13:15:00 UTC +00:00]]
   (0.5ms)  COMMIT

How do i force Capybara to hold the sails a bit?

like image 946
MartinElvar Avatar asked Dec 08 '13 13:12

MartinElvar


1 Answers

The main problem, as you said, it's Capybara didn't wait. But the main reason is the test doesn't use a consistent style.

If using Capybara, the test acts like a real user, and you should expect some UI change instead of database change, for real user can't see what happens in db.

In this test, the db assertion is executed right away, even faster than the browser driver sending data to server, so the data is nil.

To fix,

  1. Remove the within block at first. This seems unimportant. If I remembered correctly, the expectation should better not in different block of the action. So do it for safety.

  2. Add UI expectation. Then Capybara will wait until the effect appears.

So,

scenario 'Creating job', js: true do
  fill_in 'Email', with: @customer.email
  fill_in 'Password', with: @customer.password
  click_button 'Login'
  # Assume your page will show user name after signing in
  expect(page).to have_content(@customer.name)
end

If you really want to test db change, you can add that expectation after UI expectation, but I don't recommend that.

like image 94
Billy Chan Avatar answered Oct 16 '22 08:10

Billy Chan