Upgrading to Capybara 2
Hey guys,
Recently upgraded a Rails 3 project at work to Capybara 2 from 1.1.2. Ran into a few minor bumps along the way and which I’ve shared below and hopefully it helps others choosing to upgrade.
Useful links:
Most of this work was backwards compatible. I was able to push multiple fixes, keeping close to master and leaving the gem upgrade as the last commit.
The 4 biggest changes for us
- wait_until
- All methods which find or manipulate fields or buttons now ignore them when they are disabled
- find now raises an error if more than one element was found. Meaning every selector should be unique or use first instead (which won’t wait like find does)
- undefined method ‘visit’. We had a few Rspec-Capybara tests which had to be moved into spec/features.
wait_until
We have a large collection of features and a lot of those were using wait_until. Updating all our features to not use it was a large task so to keep moving I decided write a monkey patch which gives us access to a wait_until block. The idea being that we can than weed our features off the old behaviour one at a time instead of a big bang approach.
class Capybara::Session
def wait_until(timeout = Capybara.default_wait_time)
Timeout.timeout(timeout) do
sleep(0.1) until value = yield
value
end
end
end
find vs first
There were a lot of places in the code where we would use find instead of first. Most of these were easy to change but sometimes we needed to wait for the page and first wouldn’t cut it. To get around this I created a find_first method which would try to find it and if there were more than one just return the first (exactly what the old find did). This was another patch which was fixed up later with better use of selectors.
def find_first(locator)
element = nil
begin
element = find(locator)
rescue Capybara::Ambiguous
element = first(locator)
end
return element
end
EDIT: It turns out that you can just use all(selector).first
because find
uses all
under the hood anyway.
checking for disabled elements
We had a step to ensure the button was disabled which had to be changed. Below is the before and after. If there is a better way of doing this let me know!
-Then /^the "([^\"]*)" button is disabled$/ do |title|
- find_button(title)["disabled"].should_not == nil
-end
+Then /^the delete button is disabled$/ do
+ first(".place_action input[type=\"submit\"][value=\"Delete →\"]")[:disabled].should == "true"
+end
rack_server witin driver
We have a step which was getting rack server mappings and port number from Capybara rack_server accessor. They were changed to the following respectively.
#from
Capybara::current_session.driver.rack_server.app.instance_variable_get(:@mapping)
#to
Capybara::current_session.driver.app.instance_variable_get(:@mapping)
#from
page.driver.rack_server.port
#to (Not backwards compatible)
page.server.port
The biggest chunk of work was fixing up the hundereds (exaggeration) of ambiguous errors that we were getting. Thankfully each fix was easily backported so I didn’t end up with a massive change set locally or sitting on an ever aging branch.
Hope this helps people with their upgrade
-Matt