Find elements by data attributes
Asked Answered
A

2

26

I'm improving my tests with RSpec and capybara-webkit, trying to delete all the css and xpath selectors like

find('#edit_user > div:nth-child(7) > div > div > button').click

and I'm looking for the best option to replace them.

I was going to use the css class of the elements but some "pro" capybara tester said this is not the best option.

So my question is: can I use the dataattributes in my tests?
If I have an element

<button name="button" type="submit" class="button last" data-test="edit.update">Update/button>

will I be able to do

find('edit.update').click

?

And do you think it is a good idea? If you have more ideas/infos about this topic, feel free to comment!

Alaynaalayne answered 4/12, 2015 at 16:31 Comment(1)
See also Capybara.test_id=, added in 2018 by 5b76480e571.Colene
D
42

To locate elements by their data-* attribute, you need to use a CSS-selector or XPath.

For the CSS-selector:

find('button[data-test="edit.update"]').click

For XPath:

find('//button[@data-test="edit.update"]').click

Whether or not it is a good idea really depends on the application. You want to pick something that uniquely identifies the element. If "edit.update" is not going to be unique, it would not be a good choice to use. The class attribute would be fine if the button had a unique class, which "button" and "last" are not likely to be.

The best approach is really to use static id attributes as they should be unique within the page and are less likely to change. The find method also supports locating elements by id, which means you do not have to write CSS-selectors or XPath.

Develop answered 4/12, 2015 at 17:45 Comment(1)
I had a div with a tag name so this worked for me find('div[name="delete_user_0"]').clickDonothing
R
17

The answer given by Justin Ko is correct, I just wanted to add something slightly more advanced which can help with test readability in some situations. You can add your own "selectors" to Capybara, so if you really wanted to select things by a data-test attribute (not a great idea since you don't really want to be adding attributes just for testing) a lot you could do

Capybara.add_selector(:dt) do
  css { |v| "*[data-test=#{v}]" }
end

which would allow

find(:dt, 'edit.update')

this can make tests understandable while also limiting complicated css or path queries to a single place in your test code. You can then define a method such as

def find_by_dt(value)
 find(:dt, value)
end

if you prefer the look of find_by_dt...) to find(:dt, ...)

You can also add filters and descriptions to your own selections for more flexibility, better error descriptions, etc - see https://github.com/jnicklas/capybara/blob/master/lib/capybara/selector.rb for the built-in selectors provided by capybara

Robustious answered 4/12, 2015 at 20:45 Comment(2)
Why do you think it's not a good idea to add attributes just for testing?Dupe
@AndreiBotalov some feel that is just bad practice to add things just for testing. However, I've run into so many situations where changing one piece of code has rippling effects on the test code that I end up spending hours fixing tests because its based on some css or text. I completely agree with Kent Dodds article on data- attributes for testing here: blog.kentcdodds.com/… . In short - it makes your tests less brittle. Its all about tradeoffs.Cedillo

© 2022 - 2024 — McMap. All rights reserved.