Which is better in PageObject model, using id, class, name to identify elements or using css to identify elements

28 views
Skip to first unread message

NaviHan

unread,
Mar 24, 2019, 2:15:53 AM3/24/19
to Watir General
I have seen in my project using css to identify elements using PageObject.
I always use attributes like id, class and name to identify elements.

Which is the better way and why?

Titus Fortner

unread,
Mar 24, 2019, 10:23:51 PM3/24/19
to Watir General
The Watir API is designed such that you shouldn't ever need to use CSS (or XPath). Especially with the latest versions where there is no performance penalty to nesting elements. Presumably a Hash of attribute or class key/value pairs is easier to read and parse than CSS selector annotation.

Another thing to consider if you have access to the underlying markup, is to use a unique custom attribute (I recommend `data-test`) for everything you want to interact with on a page for a test. ID is becoming less common because of single page applications, and class values are there for formatting the site, not for providing unique locators for elements for your tests.

NaviHan

unread,
Mar 24, 2019, 10:28:14 PM3/24/19
to Watir General
Thanks Titus.
But what if someone ask, why cant I use the css or xpath.
If you use them what is issue and how we avoid that with attributes like is, class or data-set?

NaviHan

unread,
Mar 26, 2019, 5:19:06 AM3/26/19
to Watir General
Hi Titus

Today I saw a team member defining elements like this

+  a(:start_shopping_link, :css => "a.start-shopping")
+  links(:product_names, :css => ".price-and-quick-add-button-wrapper a.name-link")
+  links(:product_thumbnails, :css => "a.thumb-link")
+  span(:remove_all_link, :css=> ".wishlist-remove-all span")

Heavy use of css.
I cant tell them why they should use css :-)

Could you please let me know the disadvantage here?


On Sunday, 24 March 2019 17:15:53 UTC+11, NaviHan wrote:

Justin Ko

unread,
Mar 26, 2019, 12:39:39 PM3/26/19
to Watir General
In most cases, it is simply a matter of personal preference. There is usually no technical difference between between using CSS/XPath vs attributes. To me, the most important thing is to be consistent as an organization so that code is consistent, which makes the code easier to read/maintain. I would push using attributes as easier to read and less error prone. However, I have worked with people coming from Capybara that feel that CSS expressions are easier to read/use.

That said, there is one place where using CSS/XPath is the better solution - creating a collection of nested elements without the same ancestors.

For example, let's say you have the following HTML:


<body>
 
<div class="price-and-quick-add-button-wrapper">
   
<a class="name-link">link A</a>
 
</div>
 
<div class="price-and-quick-add-button-wrapper">
   
<a class="name-link">link B</a>
 
</div>
</body>

Your current accessor, will match *2* links:


links(:product_names, :css => ".price-and-quick-add-button-wrapper a.name-link")

Unlike the CSS-locator, nesting Watir's element calls only looks in the first matching element. Therefore, you would only get *1* match if you tried:

links(:product_names) { div(class: "price-and-quick-add-button-wrapper").links(class: "name-link") }

To get the *2* links without CSS/XPath you would need to make some ugly iteration of elements, which is harder to read/write and worse with more levels of nesting:

links(:product_names) { divs(class: "price-and-quick-add-button-wrapper").map { |div| div.links(class: "name-link") }.flatten }

Of course, this assumes you're stuck with the HTML you have. The better answer would be to add more attributes so that you can locate the links directly (ie not deal with nesting).

- Justin

Titus Fortner

unread,
Mar 26, 2019, 3:05:55 PM3/26/19
to Watir General
The other reason to perhaps prefer css is that Page Object gem makes using nested elements harder.

span(:remove_all_link, :css=> ".wishlist-remove-all span")
I think would need to look like:

element(:wishlist_remove_all, :class => "wishlist-remove-all")
span(:remove_all_link){ wishlist_remove_all_element.span } 

Justin is there an easier way to do this in PO gem?

Justin Ko

unread,
Mar 26, 2019, 3:35:06 PM3/26/19
to Watir General
Generally, no, there is no easier way to deal with nested elements. Though if you don't need to access :wishlist_remove_all, you could just do:

span(:remove_all_link){ div(class: "wishlist-removal-all").span }

I don't think Page-Object is making it any harder than pure Watir.

Page-Object does provide some "convenience" for elements in frames, which we could extend to other elements:

iframe(id: 'frame_id') do |iframe|
  span
(:something, class: 'class', frame: iframe)
end

Justin

NaviHan

unread,
Mar 26, 2019, 8:45:39 PM3/26/19
to Watir General
Hi Justin

Thanks for the detailed explanation.

But cant we use collections here.

Instead of declaring links as

links(:product_names) { div(class: "price-and-quick-add-button-wrapper").links(class: "name-link") }

isnt
links(:product_name, :class => 'name-link')


better?
And then use

product_names_elements[0] and product_name_elemets[1] to access links?


On Sunday, 24 March 2019 17:15:53 UTC+11, NaviHan wrote:
Reply all
Reply to author
Forward
0 new messages