Writing Unit Test Cases with Jest in JavaScript Projects

Writing Unit Test Cases with Jest in JavaScript Projects

Introduction

Unit testing is a crucial part of modern software development. It ensures that your code is working as expected, helps you identify and fix bugs, and makes it easier to refactor and maintain your codebase. Jest is a popular and powerful JavaScript testing library that makes it easy to write and run unit tests for your projects. In this tutorial, we'll show you how to set up Jest in a JavaScript project and write effective unit tests.

Setting Up Jest

First, you need to install Jest as a development dependency in your project:

  1. npm install --save-dev jest

Next, add the following scripts to your `package.json` file:

  1. {
  2. "scripts": {
  3. "test": "jest",
  4. "test:watch": "jest --watch"
  5. }
  6. }

Now, you can run your tests using `npm test` or `npm run test:watch` to run tests in watch mode.

Writing Your First Test

Let's say you have a simple utility function that adds two numbers together:

  1. // utils.js
  2. export const add = (a, b) => a + b;

To write a test for this function, create a new file with the same name as your module, followed by ".test.js". In our case, it would be `utils.test.js`. Inside this file, import the `add` function and write your first test:

  1. // utils.test.js
  2. import { add } from './utils';
  3.  
  4. test('adds 1 + 2 to equal 3', () => {
  5. expect(add(1, 2)).toBe(3);
  6. });

Here, we're using Jest's `test` function to define a new test case. The first argument is a string describing the test, and the second argument is a function containing the test logic. We use `expect` to define our expected result and `toBe` to compare it with the actual result.

Run your tests with `npm test`, and you should see the following output:

  1. PASS ./utils.test.js
  2. ✓ adds 1 + 2 to equal 3 (3 ms)

Testing with Matchers

Jest provides a variety of matchers that allow you to assert different aspects of your code. Here are some common matchers:

  • `toBe`: Strict equality (===) comparison
  • `toEqual`: Deep equality comparison for objects and arrays
  • `toBeTruthy`/`toBeFalsy`: Test if a value is truthy or falsy
  • `toContain`: Test if an array or iterable contains a specific item
  • `toHaveLength`: Test the length of an array or string
  • `toThrow`: Test if a function throws an error

Let's see some examples:

  1. // utils.test.js
  2. import { add } from './utils';
  3.  
  4. test('adds 1 + 2 to equal 3', () => {
  5. expect(add(1, 2)).toBe(3);
  6. });
  7.  
  8. test('adds -1 + -2 to equal -3', () => {
  9. expect(add(-1, -2)).toBe(-3);
  10. });
  11.  
  12. test('returns NaN when adding non-numeric values', () => {
  13. expect(add('a', 'b')).toBeNaN();
  14. });

Organizing Tests with describe

Jest provides the `describe` function to help you organize your tests into logical groups. This can make your test suite easier to read and maintain. The `describe` function takes two arguments: a string describing the group, and a function containing the related tests.

Let's update our `utils.test.js` file to use `describe`:

  1. // utils.test.js
  2. import { add } from './utils';
  3.  
  4. describe('add', () => {
  5. test('adds 1 + 2 to equal 3', () => {
  6. expect(add(1, 2)).toBe(3);
  7. });
  8.  
  9. test('adds -1 + -2 to equal -3', () => {
  10. expect(add(-1, -2)).toBe(-3);
  11. });
  12.  
  13. test('returns NaN when adding non-numeric values', () => {
  14. expect(add('a', 'b')).toBeNaN();
  15. });
  16. });

Now, when running your tests, Jest will display the group name in the output:

  1. PASS ./utils.test.js
  2. add
  3. ✓ adds 1 + 2 to equal 3 (3 ms)
  4. ✓ adds -1 + -2 to equal -3 (1 ms)
  5. ✓ returns NaN when adding non-numeric values (1 ms)

Asynchronous Tests

Jest also supports testing asynchronous code. You can use `async/await`, callbacks, or promises in your tests. Here's an example of testing an asynchronous function using `async/await`:

  1. // api.js
  2. export const fetchData = async () => {
  3. const response = await fetch('https://api.example.com/data');
  4. const data = await response.json();
  5. return data;
  6. };
  7.  
  8. // api.test.js
  9. import { fetchData } from './api';
  10.  
  11. describe('fetchData', () => {
  12. test('returns data from the API', async () => {
  13. const data = await fetchData();
  14. expect(data).toBeDefined();
  15. expect(data.length).toBeGreaterThan(0);
  16. });
  17. });

In this example, we're using the `async` keyword in our test function and `await` to wait for the `fetchData` function to resolve. Jest will automatically handle the promise and report the test result once the promise is resolved.

Mocking Functions

Jest allows you to mock functions, which can be useful when testing code that depends on external services or modules. To mock a function, use the `jest.fn()` function:

  1. // utils.js
  2. export const fetchData = async () => {
  3. const response = await fetch('https://api.example.com/data');
  4. const data = await response.json();
  5. return data;
  6. };
  7.  
  8. // utils.test.js
  9. import { fetchData } from './utils';
  10.  
  11. describe('fetchData', () => {
  12. test('returns data from the API', async () => {
  13. const mockData = [{ id: 1, name: 'John Doe' }];
  14. global.fetch = jest.fn(() =>
  15. Promise.resolve({
  16. json: () => Promise.resolve(mockData),
  17. })
  18. );
  19.  
  20. const data = await fetchData();
  21. expect(data).toEqual(mockData);
  22. });
  23. });

In this example, we're mocking the `fetch` function to return a predefined response. This way, we can test our code without making actual API calls.

Conclusion

In this tutorial, we've explored how to set up Jest in a JavaScript project, write unit tests using different matchers, organize tests with `describe`, test asynchronous code, and mock functions. Jest is a powerful and flexible testing library that can help you improve the quality and maintainability of your code. By incorporating Jest into your development process, you can ensure that your code is reliable, robust, and ready for production.

We use cookies to improve your browsing experience. By continuing to use this website, you consent to our use of cookies. Learn More