Why you should make your tests fail
Learn why making your tests fail is actually a good idea.
Let's face it, most of us developers don't necessarily love writing tests. We sometimes end up rushing through them, and once we see that green tick next to a passing test, we're generally pretty happy to move on. However, an enemy is lurking amongst us.
False positive test
The enemy I'm talking about here is otherwise known as a false positive test. Let's take a look at what this beast looks like.
Here we have a select
element with some countries as options:
<select>
<option value="">Select a country</option>
<option value="US">United States</option>
<option value="IE">Ireland</option>
<option value="AT">Austria</option>
</select>
Here's my test:
it('should allow user to change country', () => {
render(<App />)
userEvent.selectOptions(
screen.getByRole('combobox'),
screen.getByRole('option', { name: 'Ireland' } ),
)
expect(screen.getByRole('option', { name: 'Ireland' })).toBeInTheDocument();
})
The test passes, isn't that great? โ I'm afraid not. ๐ญ Let's see why after we intentionally make it fail.
Making your test fail
Here's a real example of a false positive test situation I ran into recently:
it('should allow user to change country', () => {
render(<App />)
userEvent.selectOptions(
screen.getByRole('combobox'),
screen.getByRole('option', { name: 'Ireland' } ),
)
// Changed expected country from "Ireland" to "Austria" - this should fail.
expect(screen.getByRole('option', { name: 'Austria' })).toBeInTheDocument();
})
I was expecting the check for "Austria" to fail because it wasn't the selected country, and I was pretty surprised to see that it was still passing. Looks like we have just identified a false positive test.
Let us take a step back. The purpose of my test is to ensure that when changing a country, it is indeed the now selected option. However, after debugging for while I eventually realised that the test above only checks that the country "Ireland" exists, instead of checking if it's selected.
Here's how I eventually fixed it:
it('should allow user to change country', () => {
render(<App />)
userEvent.selectOptions(
screen.getByRole('combobox'),
screen.getByRole('option', { name: 'Ireland' } ),
)
// Now checking if the option is selected
expect(screen.getByRole('option', { name: 'Ireland' }).selected).toBe(true);
})
Now, I am correctly checking that the option is selected and all is good. I wouldn't have found this unless I intentionally made my test fail, so I'm glad my persistence has paid off and I avoided a potential bug.
Final thoughts
I've been burnt enough times in the past by false positive tests that I have vouched to always intentionally make my tests fail before moving on to the next one. Since doing this, I've gotten a lot more confident in my tests knowing that they'll only pass in the correct circumstances.
That's about all I have to share with you today. Let me know in the comments if you found this article useful. ๐
Want to follow along?
I mainly write about real tech topics I face in my everyday life as a Frontend Developer. If this appeals to you then feel free to follow me on Twitter: https://twitter.com/cmacdonnacha
Bye for now ๐