Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I unable to use mockResolvedValue here?

I’m unclear on how to mock my api response when using the following setup.

I have the following test:

import React from 'react';
import { cleanup, render, wait } from '@testing-library/react';
import axios from 'axios';
import Condition from './index.jsx';

jest.mock('axios', () => {
  return {
    create: jest.fn(() => ({
      get: jest.fn().mockResolvedValue({ data: {} }),
      interceptors: {
        request: { use: jest.fn(), eject: jest.fn() },
        response: { use: jest.fn(), eject: jest.fn() },
      },
    })),
  };
});


afterEach(cleanup);

test('fetches and displays data', async () => {
  axios.get.mockResolvedValue({ data: 'mock data' });
  const { container } = render(<Condition {...props} />);
  await wait(() => expect(container.textContent).toContain('Current milestone'));
  expect(container).toBeDefined();
});

… and the following api helper:

import axios from 'axios';

const api = axios.create({
  baseURL: window.apiPath,
  withCredentials: true,
});

api.interceptors.request.use(config => {
  const newConfig = Object.assign({}, config);
  newConfig.headers.Accept = 'application/json';

  return newConfig;
}, error => Promise.reject(error));

export default api;

My Condition component uses the following function to fetch data when it mounts:

const fetchAsync = async endpoint => {
  const result = await api.get(endpoint);
  setSuffixOptions(result.data.data);
  console.log('result.data.data', result.data.data);
};

The axios.get.mockResolvedValue({ data: 'mock data' }); line in the test causes the following error:

    TypeError: Cannot read property 'mockResolvedValue' of undefined

      124 |
      125 | test('fetches and displays data', async () => {
    > 126 |   axios.get.mockResolvedValue({ data: 'mock data' });
          |             ^
      127 |   const { container } = render(<Condition {...props} />);
      128 |   await wait(() => expect(container.textContent).toContain('Current milestone'));
      129 |   expect(container).toBeDefined();

Should I be using a different method for mocking the response?

EDIT Calling axios.create.get.mockResolvedValue({ data: 'mock data' }); results in the same error.

like image 343
Brandon Durham Avatar asked Sep 20 '20 17:09

Brandon Durham


People also ask

How do you mock a promise in Jest?

In order to mock asynchronous code in Jest, more specifically Promises, you can use the mockResolvedValue function. This will mock the return value of the Promise to be 42. In order to test a Promise in Jest, you need to turn your it block into async in order to use the await keyword in front of an expect statement.

How do you mock a file in Jest?

In Jest, Node. js modules are automatically mocked in your tests when you place the mock files in a __mocks__ folder that's next to the node_modules folder. For example, if you a file called __mock__/fs. js , then every time the fs module is called in your test, Jest will automatically use the mocks.

What is the use of Jest spyOn?

The spyOn function is one of the most powerful utility functions in Jest. It allows you to spy on a function, observe interactions, and mock them accordingly. But to spy on a named import in Jest isn't straightforward due to the arguments that the function accepts.


2 Answers

To mock your api response, you can use jest.spyOn in combination with mockImplementation, e.g. as follows:

import api from './api';

const mock = jest.spyOn(api,"get");
mock.mockImplementation(() => Promise.resolve({ data: {} }));

In the example above, the api.get method is replaced to emulate a successful call returning { data: 'mock data' }.

It can be placed in your test function as follows:

test('fetches and displays data', async () => {
    const mock = jest.spyOn(api, "get");
    mock.mockImplementation(() => Promise.resolve({ data: {} }));
    const { container } = render(<Condition {...props} />);
    await wait(() => expect(container.textContent).toContain('Current milestone'));
    expect(container).toBeDefined();
});
like image 88
colourCoder Avatar answered Oct 16 '22 19:10

colourCoder


The better way is to mock the ./api helper module rather than axios module. Because you are testing the component which imports ./api as its direct dependency. For the component, the axios module is indirect dependency. If you want to test ./api helper, then you should mock axios module, because now, it becomes a direct dependency for ./api.

E.g.

index.tsx:

import React, { useEffect, useState } from 'react';
import api from './api';

function Condition(props) {
  const [options, setSuffixOptions] = useState();
  const fetchAsync = async (endpoint) => {
    const result = await api.get(endpoint);
    setSuffixOptions(result.data);
    console.log('result.data', result.data);
  };
  useEffect(() => {
    fetchAsync('http://localhost:3000/api');
  });

  return <div>{options}</div>;
}

export default Condition;

index.test.tsx:

import React from 'react';
import Condition from './';
import { render, wait } from '@testing-library/react';
import api from './api';
import { mocked } from 'ts-jest/utils';

jest.mock('./api', () => {
  return { get: jest.fn() };
});

describe('63981693', () => {
  test('fetches and displays data', async () => {
    mocked(api.get).mockResolvedValue({ data: 'mock data' });
    const props = {};
    const { container } = render(<Condition {...props} />);
    await wait(() => expect(container.textContent).toContain('mock data'));
    expect(api.get).toBeCalledWith('http://localhost:3000/api');
    expect(container).toBeDefined();
  });
});

We don't care about the implementation of the ./api module because we have mocked it.

unit test result with coverage report:

 PASS  src/stackoverflow/63981693/index.test.tsx (12.377s)
  63981693
    ✓ fetches and displays data (68ms)

  console.log src/stackoverflow/63981693/index.tsx:1461
    result.data mock data

  console.log src/stackoverflow/63981693/index.tsx:1461
    result.data mock data

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |      100 |      100 |      100 |      100 |                   |
 index.tsx |      100 |      100 |      100 |      100 |                   |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        14.873s, estimated 18s
like image 21
slideshowp2 Avatar answered Oct 16 '22 18:10

slideshowp2