Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capybara should have_content is not waiting long enough

So I am writing an acceptance test using capybara. The scenario was to connect our newsletter system to external mail service.

We will get redirected to our external service page to request access to the external mail service. And we will be redirected back to our system page when succeed.

When "I grant authorization" do
  fill_in "username", :with => "myapp"
  fill_in "password", :with => "secret"
  click_button "Allow Access"
end

Then "I should see 'Connection Established'" do
  page.should have_content "Connection Established"
end

And "I should see that I'm connected to Sample External Service" do
  page.should have_content "Connection Established: Sample External Service"
  page.should have_content "Deactivate Sample External Service syncing"
end

But if I am not using sleep before the page.should have_content "Connection Established". The spec will fail. From what I know, using sleep is not the best practice, because it will make our test run slow.

How to make it waiting until it got redirected back to our system

like image 977
Kris MP Avatar asked Apr 18 '19 11:04

Kris MP


3 Answers

There are 3 ways to adjust the maximum amount of time Capybaras methods will wait for their expectations to be true/elements to exist

Capybara.default_max_wait_time = <seconds> - This is the global setting which should be set high enough for the vast majority of your method calls

Capybara.using_wait_time(<seconds>) do ... end - This temporarily changes default_max_wait_time inside the block and then returns it to its original setting when done. This makes sense when you have a number of methods you want to call with a new wait time, or you need to call a helper method with the wait time set to a different value.

:wait option - All Capybara finder and expectation methods accept a :wait option which will change the maximum wait time for that method call. This makes sense to use when you have a specific case that requires a bit more waiting than normal

# This will wait up to 10 seconds for the content to exist in the page
page.should have_content "Connection Established: Sample External Service", wait: 10 

Note: In the future when posting questions it is generally helpful if you provide the full exact error message you get as part of your question.

like image 145
Thomas Walpole Avatar answered Oct 03 '22 23:10

Thomas Walpole


You can use capybara_watcher gem, it is an elegant way of waiting for the pege to have a change in its content. Check it out on RubyGems.org

Example:

wait_until_content_has "Connection Established" do |text|
  page.should have_content text
end

The perks of using this is that the sleep time is the actual time the page takes to have a change and you can configure it to exit after the second you choose if the page didn't change.

like image 26
Ricardo Villagrana Avatar answered Oct 03 '22 23:10

Ricardo Villagrana


For page transitions, I like to wait for the URL to change first, and then wait for content on the page. It gives you a more specific error if the redirect fails, and it naturally splits the long wait into two chunks. With two opportunities to hit default_max_wait_time, the timeout is potentially doubled without actually changing it. If it's still not enough, you can always pass a custom timeout into have_current_path with the wait: parameter.

expect(page).to have_current_path("externalservice.com")
expect(page).to have_content("Connection Established")

There might be a page.should equivalent, but I think the official guidance is to move to the expect syntax, since the should syntax was deprecated.

like image 45
Nathaniel C Avatar answered Oct 04 '22 00:10

Nathaniel C