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 element has a different CSS selector in desktop, tablet, or mobile views?
– or the element has a different CSS locator on different locales (e.g. US vs CA versions)?
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.
Here’s how you can define a single variable in TestCafe that works with multiple selector locators to find objects on different versions of the 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) { click(desktopSearchButton) } else { click(mobileSearchButton) }
For some situations, you might need to do that, but other times, wouldn’t it be nice if you could have a single variable that could specify multiple elements?
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 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!