I try to write my code with a TDD view, i meet the same problem all time, what should i test, and what i should not test, the goal is to make a navigation bar based on react-bootstrap with TDD, my component will be just a wrapper with less property to make it easy, i begin with the brand child component of Navbar in react-bootstrap. The ultimate goal is that the test reflect what the user should to test, for example that the brand logo img with the good src and alt properties is present in the Navigation.
Are these kind of tests interesting or to avoid?
My test
import React from 'react';
import { render } from '@testing-library/react';
import BrandNav from './BrandNav';
test('testing brand navigation', () => {
const altProp = 'message to show if image unavailable',
srcProp = 'relativeFilePath',
host = window.location;
const { getByAltText } = render(<BrandNav alt={altProp} src={srcProp} />);
const brandLogo = getByAltText(altProp);
expect(brandLogo.src).toEqual(`${host}${srcProp}`);
});
My component
import React from 'react';
import { Navbar } from 'react-bootstrap';
const BrandNav = ({ alt, src }) => {
return (
<Navbar.Brand>
<img alt={alt} src={src} />
</Navbar.Brand>
);
};
export default BrandNav;
React tests fall broadly into 2 categories:
Your test falls into the first category, because it makes sure you're passing props correctly to the underlying HTML element. It's generally more valuable when you're passing props through more than one layer, but this is a fine test to have. It's pretty basic, but it shouldn't get in the way, and it makes sense to write a test like this as part of the TDD process.
If you find that a test is getting in the way more than it's helping, you can always remove it.
An example of the second type of test would be something like this:
// BrandNav.js
const BrandNav = ({ alt, src, textOnly }) => {
return (
<Navbar.Brand>
{textOnly ? <span>My Brand</span> : <img alt={alt} src={src} />}
</Navbar.Brand>
);
};
//BrandNav.test.js
test('shows only image when textOnly is FALSE', () => {
const altProp = 'message to show if image unavailable';
const srcProp = 'relativeFilePath';
const { getByAltText, queryByText } = render(
<BrandNav
alt={altProp}
src={srcProp}
textOnly={false}
/>
);
const brandLogo = getByAltText(altProp);
expect(brandLogo.src).toMatch(srcProp);
expect(queryByText('My Brand')).toBeFalsy();
});
test('shows only text when textOnly is TRUE', () => {
const altProp = 'message to show if image unavailable';
const srcProp = 'relativeFilePath';
const { queryByAltText, queryByText } = render(
<BrandNav
alt={altProp}
src={srcProp}
textOnly
/>
);
expect(queryByAltText(altProp)).toBeFalsy();
expect(queryByText('My Brand')).toBeTruthy();
});
Again, this is pretty simple, but as the logic gets more complex it will tell you your component is still working correctly, and would definitely make sense if you're building your components test-first.
EDIT: Some other factors to consider when trying to decide how many tests you should write (which might help answer your second question):
1. How widely will this project be used? If it's a personal project, you probably don't need as many tests. If you're writing a library that will be used by other people, you will want much higher test coverage. For example, react-bootstrap
has lots of simple tests in their GitHub repo. They want to know if anything breaks, down to the smallest unit, since many people rely on their components working properly. You can also see that they have tests which cover some of the things you're asking about ("test brand is present"), so you wouldn't need to write tests to cover that.
2. How familiar are you with writing tests in general? If you're just learning to write tests, I think there's value in writing simple tests like this for a few reasons:
A. You'll get more familiarity with the testing library B. You'll probably end up writing a few too many tests, feeling that pain point, and know which tests you can avoid in the future.
Tests are useful for more than just coverage. I can't find it right now, but there's a memorable quote in another StackOverflow post, something to the effect of: "The benefit of TDD is not to have a bunch of tests. That's a nice side effect. The benefit of TDD is to have code that's more cleanly designed."
The more experience you get writing tests, the more you'll know what to avoid. To paraphrase Kent Beck (The author of Test Driven Development by Example), "I don't always write tests for very small steps, but when things get weird it's nice to know that I can."