How to wait for next page being loaded with Capybara and Selenium?
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.
Wait for an image to load using Capybara SitePrism
img elements have a complete property that indicates whether the image is loaded or not. Therefore something along the lines of
start = Time.now
while true
break if find('img.some_class')['complete']
if Time.now > start + 5.seconds
fail "Image still not loaded"
end
sleep 0.1
end
would wait up to 5 seconds for the image to finish loading, assuming the img element is already on the page.
This could also be implemented as a custom selector with something along the lines of
Capybara.add_selector(:loaded_image) do
css { |locator_class| "img.#{locator_class}" }
filter(:loaded, default: true, boolean: true) { |node, value| not(value ^ node['complete']) }
end
which could then be called as
find(:loaded_image, 'some_class')
*** Note: I haven't actually tried the custom selector code, but it should be close enough to provide guidance
Wait until page is loaded with Selenium WebDriver for Python
The webdriver
will wait for a page to load by default via .get()
method.
As you may be looking for some specific element as @user227215 said, you should use WebDriverWait
to wait for an element located in your page:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
browser = webdriver.Firefox()
browser.get("url")
delay = 3 # seconds
try:
myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement')))
print "Page is ready!"
except TimeoutException:
print "Loading took too much time!"
I have used it for checking alerts. You can use any other type methods to find the locator.
EDIT 1:
I should mention that the webdriver
will wait for a page to load by default. It does not wait for loading inside frames or for ajax requests. It means when you use .get('url')
, your browser will wait until the page is completely loaded and then go to the next command in the code. But when you are posting an ajax request, webdriver
does not wait and it's your responsibility to wait an appropriate amount of time for the page or a part of page to load; so there is a module named expected_conditions
.
selenium-webdriver and wait for page to load
This is how the Selenium docs () suggest:
require 'rubygems'
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get "http://google.com"
element = driver.find_element :name => "q"
element.send_keys "Cheese!"
element.submit
puts "Page title is #{driver.title}"
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { driver.title.downcase.start_with? "cheese!" }
puts "Page title is #{driver.title}"
driver.quit
If that is not an option you can try the suggestion from this SO post though it would require some Javascript on top of the Ruby/Rails.
It seems that wait.until
is being/has been phased out. The new suggested process it to look for the page to have an element you know will be there:
expect(page).to have_selector '#main_div_id'
Selenium wait until document is ready
Try this code:
driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
The above code will wait up to 10 seconds for page loading. If the page loading exceeds the time it will throw the TimeoutException
. You catch the exception and do your needs. I am not sure whether it quits the page loading after the exception thrown. i didn't try this code yet. Want to just try it.
This is an implicit wait. If you set this once it will have the scope until the Web Driver instance destroy.
See the documentation for WebDriver.Timeouts
for more info.
Related Topics
What's the Difference Between Rspec's Subject and Let? When Should They Be Used or Not
How to Pass Arguments to Define_Method
How Does This Ruby Injection Magic Work
Remove from the Array Elements That Are Repeated
Interpretation as a Local Variable Overrides Method Name
How to Make 'Whenever' Gem Work on Windows
Inserting an Array Using Sequel Gem in Postgresql
Ruby on Rails Send_File Doesn't Work Until I Refresh the Page
How to Drop Columns Using Rails Migration
Add Space After Commas Only If It Doesn't Already
Ruby: Inject Issue When Turning Array into Hash
Remove Duplicate Elements from Array in Ruby
Exponentiation in Ruby 1.8.7 Returns Wrong Answers
Ruby Inject with Initial Being a Hash
How to Get a Backtrace from a Systemstackerror: Stack Level Too Deep