How to Write Good Test Selectors

Over the years I’ve written a lot of automation tests - some good, some flakey. Choosing the right selector is key to building non-flakey tests.

Here are my top tips:

Tip 1 — Choose the right selector

Here’s a list of selectors in order of preference:

1. Custom attribute

Always use custom attributes that are specifically added for the purpose of automation. These are isolated and unlikely to change, resulting in non-flakey tests. Data-cy in Cypress is a great example of this.

cy.get('[data=cy="submit"]')

EDIT: 1.5 Accessibility-focused selectors

Zachary mentioned in the comments about a shift towards accessibility-focused selectors which better simulate user interactions with the page. More details here.

const input = screen.getByLabelText('Username');

2. ID

IDs are good as they are at least unique. However they are open to change and could break your tests if a developer changes the ID without realising it’s linked to a test.

cy.get('#submit')

3. CSS

CSS selectors can change frequently, but they can work if you use good selectors (see Tip 2 below). Cypress doesn’t recommend using these so it might be better to speak to your developer about adding a custom attribute.

cy.get('.submit')

4. XPath

Never use XPath. These are extremely flakey and if anything in the DOM changes, your test will break:

cy.get('/html/body/div[1]/div/form/span')

Tip 2 — Use better CSS selectors

Often I see people working their way down the DOM tree using CSS selectors. This may work today, but is highly likely to break down the line. But there are still some ways to make them less flakey:

1. Finding elements within elements

Do some research on how CSS selectors work. W3School has some great resources.

A common mistake is writing a CSS selector like this:

cy.get('.tableStyle > .rowStyle > .divStyle > .buttonStyle')

Yes, it helps you select the specific button within a table. But if anything between the table and the button changes (the row or div), your test will fail.

Instead try find the button anywhere within the table like this:

cy.get('.tableStyle .buttonStyle')

Much less flakey.

Understanding how to find elements within elements using selectors is key:

2. Use selectors to filter out elements

Use selectors like :disabled, :nth-child(n) or :checked to filter down and find the specific elements you need.

This can be much cleaner to find the element(s) you’re looking for, rather than looping through elements in code.

Tip 3 — Work with developers

It sounds simple, but working with developers is key to writing better selectors and automation.

If you use a tool like Cypress, which is JavaScript based, why not make use of the JavaScript experts around you to help improve your code.

If you can’t find an element, rather than struggling and using a flakey selector, work with you developer to get a custom or better attribute added.

You’ll thank yourself later!

--

--

--

QA Lead, taking on the world of software testing, one bug at a time!

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Getting Started With React Router

Choosing The Right Chart Library

https://concept-tees.myspreadshop.com/rock+out+white+print-A5cb558aa1cbf3a6d436d381a

Most useful methods from Moment.js

How to update your Gatsby Site to Google Analytics v4 — migration guide

Measuring Web Worker Performance

https://youtu.be/NXO0g76vn_Y

Redirecting all http requests to https in node js

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Robbie Falck

Robbie Falck

QA Lead, taking on the world of software testing, one bug at a time!

More from Medium

The power of emotion driven testing

How to set up a Cypress 10 test automation project?

Top Software testing trends to look out for in 2022

Software Testing Strategy for QA Localization — Part 2