I love Capybara, it makes integration testing a breeze. However, one of the decisions made for Capybara 2.0 confuses an annoys me. In Capybara 1.x you could do the following:
fill_in 'Password', :with => '123456'
fill_in 'Password confirmation', :with => '123456'
And everything worked. In Capybara 2.0 this does not work. Capybara will notice two labels that contain ‘Password’ and complain about an ambiguous locator. The suggested work around is to attach meta data to the input element and use that for the selector. There are two reasons why I don’t like this. First, I am doing Ember development now and I have no control of the ID, it is generated by the framework. Second, I believe that the integration test should be recreating the steps (as much as possible) as if a user were actually using the app. Something like:
fill_in '[data-name="password"]', :with => '123456'
fill_in '[data-name="password_confirmation"]', :with => '123456'
Doesn’t sit right with me. Users are looking at the text, not the selectors.
I get that apps have the ability to show different languages but that doesn’t conern me, I don’t need
to test if the Rails i18n
works or not. I just care about asserting the happy and sad
paths in my app.
So, to fix this problem simply add the
following code into your test_helper.rb
module XPath::HTML
protected
def locate_field(xpath, locator)
locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:placeholder).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.equals(locator)].attr(:for))]
locate_field += descendant(:label)[string.n.contains(locator)].descendant(xpath)
locate_field[~attr(:disabled)]
end
end
And you should be all set!