DEV Community

Cover image for How to leverage Jest in your JavaScript codebase: A guide to Snapshot Testing
LordCodex
LordCodex

Posted on

How to leverage Jest in your JavaScript codebase: A guide to Snapshot Testing

Table of Contents

Outline

What is jest

  • Features
  • How does it work?
  • What does it do?

Snapshot testing

  • Implementing Snapshot testing with jest
  • Updating Reference Snapshot
  • Implementing Inline Snapshots

Conclusion

Outline

There are big challenges that come with testing robust features in production, especially when working with a large codebase. However, When these features are not extensively tested thoroughly, They result in bugs occurring in production. Bugs are very hard to spot. But with unit and comprehensive testing, they can be prevented! In this article, you will learn how you can leverage jest to test functions and components in a JavaScript codebase. Also, you will learn how to implement snapshot testing for your web application.

Prerequisites

  • You must have Node.Js installed on your system at least version 14 or higher.
  • You must be familiar with the basic concepts of JavaScript and React.Js.

Jest

Jest is a delightful javascript framework that helps you as a developer test your javascript codebase easily. However, It is a technology that works with different project types like react, babel, typescript, angular, and vue due to its flexibility.

Features of Jest

  • Zero Config: Jest doesn’t require any config, which makes it easier to set up in any project.
  • Isolated: jest runs tests in a parallelized format, causing them to run simultaneously and at the same time bringing about faster execution and improved performance.

  • Great Api: The Jest Library offers a set of Apis and assertions that focus on test simplicity.

  • Snapshot testing: With jest, you can check for any unexpected change of a UI component and compare it to a reference snapshot file.

snapshot-file

  • Fast and safe: With its parallelized nature, jest makes running tests fast and secure.

  • Code Coverage: Jest can also provide extensive test reports of an entire project by just simply adding the —flag coverage. No additional setup is required

code-coverage

  • Easy Mocking: You can use the MockApi from jest to inspect some specific calls and then the parameters passed to the function.

How does it work

Jest offers a set of APIs and built-in functions that make testing operations easier to carry out. They include “Expect”, “toBe” and many more! Additionally, these functions enable us to provide assertions and determine behaviors for our javascript code. Let's see how we can apply them.

A Basic Example

In this first example, create a file called sum.js. Inside the file, create a javascript function that adds two numbers and then export it as a module.

//sum.js file
function sum(a, b) {
  return a + b;
}
module.exports = sum;
Enter fullscreen mode Exit fullscreen mode

After it is exported, create a test file and name it sum.test.js; the test file is where you will utilize jest to test the function.

//sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
Enter fullscreen mode Exit fullscreen mode

Inside a typical test file, built-in functions are imported for test accessibility; however, these functions make assertions about how our code should behave. In the code above, we first call the test function. Then we specify the function expectation by providing the expected value of the sum function.

After that, add this to your package.json

{
  "scripts": {
    "test": "jest"
  }
}
Enter fullscreen mode Exit fullscreen mode

Then type this command on your terminal to run your test:

npm test

After the test is run successfully, you will see this on your terminal:

test-success

Congratulations, you have just run your first test!!

Another Example

Let's consider another example. In this example, create a multiply.js file. Inside the file, create a javascript function that multiplies two numbers as shown in the code below.

//multiply.js file

function multiply(a, b) {
  return a * b;
}
module.exports = multiply;
Enter fullscreen mode Exit fullscreen mode

Next, create a test file where you will use jest to test

//multiply.test.js
const multiply = require('./multiply');

test('multiply 1 and 2 to equal 2', () => {
  expect(multiply(1, 2)).toBe(2);
});
Enter fullscreen mode Exit fullscreen mode

Inside the code provided above, we first import the multiply file. Then, we run the test cases for the imported javascript function which in this case is multiply.js. After that, we call the test function and then specify the function expectation by providing the expected value of the multiply function.

Snapshot Testing:

It is a form of testing that checks for an unexpected change in the render of a UI component. The test case renders the UI component, takes a snapshot, and then compares the output to the reference snapshot file that was created by Jest on the initial test. If two snapshots don’t match each other, the test fails. This could either be caused by an unexpected change in the render of the UI component or the reference snapshot having an old implementation that was meant to be updated.

Implementing Snapshot testing with jest

Let's consider react as a project example for testing. In React, there is something known as the dom renderer. This is a tool that does the work of rendering the whole application. However, if we are looking to test the render of the UI component, there will not be a need to render the whole application, but only the UI component for performance reasons. To Render only the UI component that we will implement with snapshot testing, we will use a test renderer! The test renderer creates a lightweight serializable representation of the react tree, preventing the rendering of the entire dom, and allowing the test to be executed faster.

The code below illustrates the implementation of the test renderer with snapshot testing.

import renderer from 'react-test-renderer';
import Link from '../Link';

it('renders correctly', () => {
const tree = renderer
.create(Hashnode)
.toJSON();
expect(tree).toMatchSnapshot();
});

From the code above, the test renderer creates a serializable value for our Link Component (which represents the “react tree”) and matches it with the reference snapshot file.

On the initial test run, this is how the created reference snapshot looks like:

exports[renders correctly 1] = `
<a
className="normal"
href="http://www.hashnode.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}

Hashnode

`;

After it is created, the snapshot artifact gets committed alongside code changes and code review. Therefore, On subsequent test runs, jest compares the rendering output with the previous snapshot to check for an unexpected change.

Updating Reference Snapshot

There are different reasons why they can be failed test cases for the rendering of the UI. It could either be due to an unmatched snapshot or an Intentional change in UI implementation. Now, let's talk about the intentional change in the UI implementation.

Let’s take this as an example. Here, we update the href address for the Link component as shown in the code below:

import renderer from 'react-test-renderer';
import Link from '../Link';

it('renders correctly', () => {
const tree = renderer
.create(Devto)
.toJSON();
expect(tree).toMatchSnapshot();
});

However, when we decide to run a test, the test is expected to fail because the href address in the rendered output doesn’t match the one in the previous snapshot.

The test output can be shown in the image below:

Snapshot_failed

So, to resolve this, we are expected to update the snapshot artifact by simply running jest with a flag that tells jest to update the previous snapshot:

Implementing Inline Snapshots

With Jest, you can create inline snapshots for your source code without having to go to an external file with the .snap extension. Inline snapshots are kinda similar to external snapshots, But they generate automatic inline snapshots when you perform subsequent tests.

A Basic Example

In this example; write the test function that tests the render of the ui component or tree as shown in the code below:

it('renders correctly', () => {
const tree = renderer
.create(Example Site)
.toJSON();
expect(tree).toMatchInlineSnapshot();
});

However, when we run the test; the generated snapshot is automatically saved alongside the code changes. Therefore, the generated snapshot is then written as an argument inside the toMatchInlineSnapshot function.

inline-match

The next time you decide to run the test, the rendered output of the tree gets compared to the generated snapshot inside the toMatchInlineSnapshot function.

Conclusion

I hope you now understand what snapshot testing in jest is all about and how it can be implemented in a javascript codebase. If you are looking to learn more about Jest, you can check out their documentation here. Happy Coding!!

Top comments (2)

Collapse
 
wolzcodelife profile image
Joel Adewole

Wow! This is comprehensive 👌

Collapse
 
devmirx profile image
LordCodex

Thank you