x-yuri
x-yuri

Reputation: 18843

How to wait for next page being loaded with Capybara and Selenium?

Let's suppose you want to submit a form to create a post, wait for it to be created, fetch the post from database and check if the image from the post is being displayed on the next page:

visit url
fill_in the_form
click_on 'Create'
post = Post.first
img = page.find '.post .image'
assert_equal post.file.thumb.url, URI(img[:src]).path

But this way, post will be nil more often than not. Since when you fetch it from database, it might not have been created yet. How do I make sure next page is loaded?

Upvotes: 3

Views: 5007

Answers (2)

x-yuri
x-yuri

Reputation: 18843

Unfortunately, you don't want to wait for page reload. Since, for instance, now post appears after page reload. In a while it might appear without full page reload. If you do, explain your circumstances, please.

I say unfortunately since if we ignore what was said above, if we really need to wait for page reload for some reason, the idea from the old answer is better than any other I've seen in the internets.

So, what you care is that post has appeared on the page. Which brings us to the following code:

test 'create post' do
  visit url
  fill_in the_form
  click_on 'Create'
  assert_selector '.post'
  post = Post.first
  img = page.find '.post .image'
  assert_equal post.file.thumb.url, URI(img[:src]).path
end

old answer

Inspired by these great article, link and comment. According to one of capybara's authors, this is the only legitimate use case for wait_until he's heard of in Capybara. Asserting on model objects, that is.

def wait_until
  Timeout.timeout(Capybara.default_max_wait_time) do
    sleep(0.1) until value = yield
    value
  end
end


def wait_for_page_reload
  id = find('html').native.ref
  yield
  wait_until { find('html').native.ref != id }
end

test 'create post' do
  visit url
  fill_in the_form
  wait_for_page_load do
    click_on 'Create'
  end
  post = Post.first
  img = page.find '.post .image'
  assert_equal post.file.thumb.url, URI(img[:src]).path
end

This is a bit hacky. But it works. It waits until html element's internal id changes.

Upvotes: -1

Thomas Walpole
Thomas Walpole

Reputation: 49870

find will wait up to Capybara.default_max_wait_time seconds for a matching element to appear on the screen. Therefore, to do what you're asking, check for content you expect to be on the next page before loading the item from the DB

visit url
fill_in the_form
click_on 'Create'
img = page.find '.post .image'
post = Post.first
assert_equal post.file.thumb.url, URI(img[:src]).path

If done in this order the page.find will wait for the element to appear on the page which guarantees the Post has already been saved so you can then load it.

Upvotes: 3

Related Questions