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

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

03 Jan 2013