TestCafe – using one Selector to specify multiple elements

Do you ever have a test where you need to do something with an element on a page, but that element changes slightly in different situations?

For example:
– the visible element has a different CSS selector in desktop, tablet, or mobile views?
– or the element has a different CSS locator on different websites that you are testing?

You would like to write a test using just one object and not have to deal with multiple object definitions and additional “if/then” conditional logic.

This “one weird trick” shows how you can define a single element object in TestCafe that works with multiple locators to find visible objects on a page. 🙂


Let’s say that you are using TestCafe to write an automated test for a webpage. You find the CSS for a search button and define a “searchButton” element:

const searchButton = Selector('div.header-desktop > button');

Later, when you resize the webpage to a mobile viewport size, you see that the visible search button changes to a different element:

const searchButton = Selector('div.header-mobile > button');

So, you could write code that has two different selectors – one for desktop and one for mobile:

const desktopSearchButton = Selector('div.header-desktop > button');
const mobileSearchButton = Selector('div.header-mobile > button');

But then in your test, you would need to write separate logic to handle the different viewports and use the appropriate element:

// pseudo-code
if (desktop) {
  // make call using desktopSearchButton
} else {
  // make call using 'mobileSearchButton'
}

For some situations, you might need to do that. Other times, wouldn’t it be nice if you could have a single Selector that would specify multiple elements? (And yes, in this simple example, you could write a single CSS selector that covers both objects, but just stay with me for a minute…)

So what’s the magic?? A comma (for CSS). Yes, seriously.

If you open Chrome DevTools, element page and press Command+F or Control+F, you could search the page and find your desktop CSS selector:

div.header-desktop > button

or your mobile CSS selector

div.header-mobile > button

But with a comma, you can search for and find both elements:

div.header-desktop > button, div.header-mobile > button

Okay – so the comma in CSS selector definition is definitely not rocket science, but it’s something I don’t use very often (and honestly, just plain forgot 🤦). So, we could create an element like this:

const searchButton = Selector('div.header-desktop > button, div.header-mobile > button');

Great, that finds both elements, but if you are on a responsive website, your page will often contain both elements. We don’t want to find both elements; we only want to find the visible element. We can do that with TestCafe’s ‘filterVisible()’ function:

const searchButton = Selector('div.header-desktop > button, div.header-mobile > button').filterVisible();

Okay – that works great! But that statement can get a bit unwieldy, especially if your CSS selectors are long:

const removeProductLink = Selector('div.product-info > div.row div.line-item-pickup div.product-actions a.remove-product, div.d-md-none div.product-actions a.remove-product').filterVisible();

Yikes, that’s a monster line of code! With long selectors like that:
– it’s hard to find the comma and see where one selector stops and the next selector starts
– we end up with code that line wraps and is generally hard to read.
To avoid that, I like to separate the selector strings from the element object definition. I also like to define each selector as a separate string in an array object:

const searchCSS = [
  'div.header-desktop > button',
  'div.header-mobile > button'
];

That makes each selector easy to find and read (which greatly helps when you need to add other selectors or make changes!). Then, for the element object definition:

const searchButton = Selector(searchCSS.join()).filterVisible();

With TestCafe’s ‘Selector()’ object, we need one long string separated by commas, right? Well the ‘Array.prototype.join()’ function concatenates all of the array strings and separates them with a comma – which is just what we want! The end result?

// define CSS strings
const searchCSS = [
  'div.header-desktop > button',
  'div.header-mobile > button'
];

// define page elements
const searchButton = Selector(searchCSS.join()).filterVisible();

// make calls using 'searchButton' element

We now have a single Selector object that supports multiple CSS selectors in a readable & maintainable format. 🎉

Will this work for every situation? No, definitely not! It’s only useful when you need to find the visible elements that match one (or more) of your defined CSS selector strings on the pages that you are testing. And THAT depends upon:
– the pages you are running tests against
– the CSS selectors that you define
– and your use-cases

Hopefully, this gives you another tool in your TestCafe bag-of-tricks. Good luck!

Software automation engineer in Portland, OR. LinkedIn: jantonypdx, Twitter: jantony_pdx
Posts created 10

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top