React testing library follows a guiding principle which is quoted below:
The more your tests resemble the way your software is used, the more confidence they can give you.
It's a little vague, and might be interpreted differently but to reword it for us, possibly this would be fitting:
The more your tests resemble the customer's needs and wants, the more confident you become in your application's implementation.
- Jest, testing platform library
- @testing-library/react: light wrapper around ReactDOM that promotes good testing practices.
- @testing-library/jest-dom/extend-expect, custom jest matchers that extend the above to test the state of the DOM
- Stay as close to production testing: Use react, and not a third party tool to render the DOM before it is tested on.
- Search a rendered DOM search via
getByText
andqueryByText
in a way that best suits it's implementation, and is also easy to spot when changes have been made. - Manageable single use case testing: Break down the tests into as smallest and most manageable single responsibility cases as possible.
describe('HotelDetails', () => {
it('should render the hotel name', () => {
const { queryByText } = render(<HotelDetails {...defaultProps} />);
const hotelName = queryByText('Marriot Hotel');
expect(hotelName).toBeInTheDocument();
});
it('should render the hotel name but not the message button there is no messageHTML', () => {
const { queryByText } = render(<HotelDetails {...defaultProps} messageHTML={undefined} />);
const hotelName = queryByText('Marriot Hotel');
const messageHotel = queryByText('Message hotel');
expect(hotelName).toBeInTheDocument();
expect(messageHotel).not.toBeInTheDocument();
});
});
Render (using react) the full component. From here we can query parts of the rendered object and see if they are present.
In this example, we can render (using react) the full object with one of the prop inputs as undefined to see if the rendered object performs in the correct way.
getby* queries return the first matching node for a query, and throw an error if no elements match or if more than one match is found (use getAllBy instead).
- If you need to test a returned object, use
getByText
- In the example below you can see that a click event needs to happen, therefore
getByText
must be used to get the object.
it('should render listing of important price details and breakdown', () => {
const { queryByText, getByText } = render(
<Provider {...mockStores}>
<Pricing {...defaultProps} />
</Provider>
);
const additionalPricingInfo = getByText('Additional pricing information');
fireEvent.click(additionalPricingInfo);
const additionalFeesContent = queryByText(defaultProps.additionalInfoContent);
});
queryBy* queries return the first matching node for a query, and return null if no elements match. This is useful for asserting an element that is not present. This throws if more than one match is found (use queryAllBy instead).
- if you’re checking to see if something exists use
queryByText
. - In the example below you can see that a no action needs to be performed on the variable
seatAssigned
soqueryByText
is the best method.
it('should render economy class with no seats selected', () => {
const { queryByText } = render(<AssignedSeats seatInfo={seatInfo} cabinClass={cabinClass} />);
const seatAssigned = queryByText('No seats selected');
const cabin = queryByText('Economy / Coach (Y)');
expect(seatAssigned).toBeInTheDocument();
expect(cabin).toBeInTheDocument();
});
- enzyme shallow rendering, testing platform library
From the above documenation:
Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components.
The biggest case against snapshot testing is that reading the changes on a failed snapshot is much harder to read and harder to debug.
It’s often hard to see what changed by looking at the snapshot failure diff: did the snapshot fail because of your intended changes or because you’ve introduced a bug?
On a big project a simple change can lead to failures in dozens of snapshots in different parts of the codebase. Understanding each failure takes a lot of time, so often developers just update snapshots without looking at them at all, especially if it’s not their code.
Snapshot testing provides a false sense of security, something that has been very present in our pwa. It has lead to an overinflated test coverage percentage.
- Why I stopped using snapshot testing with Jest
- What’s wrong with snapshot tests
- Jest, testing platform library
- @testing-library/react: light wrapper around ReactDOM that promotes good testing practices
- @testing-library/jest-dom/extend-expect, custom jest matchers that extend the above to test the state of the DOM