Posted over 8 years ago. Visible to the public.

Synchronize a Selenium-controlled browser with Capybara

When you click a link or a press a button on a Selenium-controlled browser, the call will return control to your test before the next page is loaded. This can lead to concurrency issues when a Cucumber step involves a Selenium action and a Ruby call which both change the same resources.

Take the following step which signs in a user through the browser UI and then sets a flag on the user that was just signed in:

Copy
Given /^the user "([^"]*)" signed in (\d) days ago$/ do |name, days| visit new_session_path fill_in 'Username', :with => name fill_in 'Password', :with => 'secret' click_button 'Sign in' user = User.find_by_name(name) user.update_attribute :last_sign_in => days.days.ago end

Note that you should strive to do everything through the browser UI in Cucumber features, but occasionally a step like this is too convenient to pass up.

The problem with the step above is that there is no guarantee the form submission has completed in Selenium before Ruby updates the record behind the scenes. In this case you might lose the update because the sign in process also sets the #last_sign_in attributes to the current time. This will make you feature fail occasionally.

The solution is to have Selenium resynchronize with the controlled browser before you do the update from Ruby. This will ensure that the controlled browser has finished its job. You can use the following step to perform resynchronization:

Copy
When /^the browser is ready$/ do Then 'I should see ""' end

We can now rewrite the step from the example above to be free of concurrency issues:

Copy
Given /^the user "([^"]*)" signed in (\d) days ago$/ do |name, days| visit new_session_path fill_in 'Username', :with => name fill_in 'Password', :with => 'secret' click_button 'Sign in' When 'the browser is ready' user = User.find_by_name(name) user.update_attribute :last_sign_in => days.days.ago end

Note that Capybara's Selenium driver performs resynchronization before every action that goes through the driver. So you don't need to care about resynchronization if you are a good boy and do everything through the browser UI.

See also

Waiting for page loads and AJAX requests to finish with Capybara

makandra has been working exclusively with Ruby on Rails since 2007. Our laser focus on a single technology has made us a leader in this space.

Owner of this card:

Avatar
Henning Koch
Last edit:
almost 4 years ago
by Henning Koch
Keywords:
synchronize, synchronise, synchronization, synchronisation, resynchronization, resynchornisation
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Henning Koch to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more