admin管理员组

文章数量:1202803

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.

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.

Share Improve this question edited Oct 9, 2020 at 10:24 Lin Du 102k134 gold badges332 silver badges560 bronze badges asked Sep 20, 2020 at 17:18 Brandon DurhamBrandon Durham 7,71713 gold badges66 silver badges113 bronze badges 5
  • Because your Axios test double only has a create prop, no get. – jonrsharpe Commented Sep 20, 2020 at 17:20
  • But the create method is what creates the api which has the get and interceptors methods in the api file. How do I modify axios.get.mockResolvedValue for that shape? – Brandon Durham Commented Sep 20, 2020 at 17:31
  • 1 Sure, but you're not calling that in the test. – jonrsharpe Commented Sep 20, 2020 at 17:33
  • Calling axios.create.get.mockResolvedValue({ data: 'mock data' }); results in the same error. – Brandon Durham Commented Sep 21, 2020 at 15:39
  • axios.create.get is trying to access the get prop on the function, it doesn't call the function. – jonrsharpe Commented Sep 21, 2020 at 15:42
Add a comment  | 

3 Answers 3

Reset to default 13 +100

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();
});

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

This is how we can mock the same method with multiple conditions:

Import the Axios:

import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

Use the mockedAxios:

const mock = jest.spyOn(mockedAxios, 'post');
mock.mockImplementation((url): any => {
  if (url.indexOf('checkAddOnEligibility') > 0) {
    return { data: [{ validationMessage: { value: '' }, isValid: { value: true } }] };
  }
  return {
    data: [
      {
        thirdYearPremium: 48945,
        secondYearPremium: 30535,
        firstYearPremium: 2000,
      },
    ],
  };
});

本文标签: javascriptWhy am I unable to use mockResolvedValue hereStack Overflow