In my previous post, we laid the foundation for our testing journey in React and added our first test, along with creating a component to make the tests pass. While that was a great start, we want our tests to be more resilient and efficient.
We can achieve this by making some essential changes:
describe
scopebeforeEach
to execute code that needs to be run in all test, such as adding the container to the document body.
container
declaration to the describe
scope...
describe("Product", () => {
let container;
...
});
...
To streamline our testing process, we can make use of beforeEach to execute code that needs to run before each test. This is handy for actions like adding the container to the document body, ensuring that a common setup is automatically performed for all tests.
...
describe("Product", () => {
let container;
beforeEach(() => {
container = document.createElement("div");
document.body.replaceChildren(container);
});
// ...
});
...
Another valuable practice in testing is to extract repetitive code into helper methods. Since we're rendering our component in a similar manner in all tests, it's prudent to create a rendering function that can be reused for any component.
This approach not only enhances code clarity but also reduces redundancy.
const render = component => act(()=> ReactDOM.createRoot(container).render(component));
Now we can replace all call to the ReactDOM render method with our defined render
helper method.
Here is what our test looks like now:
...
describe("Product", () => {
let container;
const render = (component) => act(() => ReactDOM.createRoot(container).render(component));
beforeEach(() => {
container = document.createElement("div");
document.body.replaceChildren(container);
});
it("renders the title", () => {
const product = {
title: "iPhone 14 Pro",
};
render(<Product product={product} />);
expect(document.body.textContent).toContain("iPhone 14 Pro");
});
it("renders the title", () => {
const product = {
title: "Samsung",
};
render(<Product product={product} />);
expect(document.body.textContent).toContain("Samsung");
});
});
...
The above steps help us emphasize the part of the tests that are important to us put the repeating code in helper methods and place some variables in a higher scope.
Before we wrap up, here's a pro tip: you can make your testing workflow even smoother by running your tests automatically whenever changes are made. With Jest, you can enable the --watchAll option, which allows your tests to auto-run without manually triggering npm run test each time you make a code modification.
Add the --watchAll option to your jest
script in the package.json file, like so:
{
"scripts": {
"test": "jest --watchAll"
}
}
This small addition simplifies your development process and ensures your tests are always up to date with your code changes.
In this follow-up article, we've added advanced testing techniques to enhance the resilience and efficiency of our tests. We employed a common setup with beforeEach and created helper methods for repetitive tasks, therefore streamlining our testing process and maintaining cleaner, more efficient code.
Lastly, with Jest's Watch Mode, we can automate our test runs, making your development workflow even more convenient. Applying these practices will help you build robust, reliable React applications and save time in the long run.