TypeError: Cannot read properties of undefined (reading 'then') - axios post nodejs jest

TypeError: Cannot read properties of undefined (reading 'then') - axios post nodejs jest

我正在尝试使用 jest 为 axios post 请求编写单元测试。 这是我的实际功能 -

exports.getAccessToken = function (urlToCall, scope, basicAuthToken) {
  return new Promise(function (resolve, reject) {
    let axios = require("axios");
    let qs = require("qs");
    let data = qs.stringify({
      grant_type: "client_credentials",
      scope: scope,
    });
    let config = {
      method: "post",
      url: urlToCall,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Authorization: "Basic " + basicAuthToken,
      },
      data: data,
    };

    axios(config)
      .then(function (response) {
        resolve(response.data);
      })
      .catch(function (error) {
        console.log(
          "error occurred while getting access token for the scope - ",
          scope,
          " and the error is - ",
          error
        );
      });
  });
};

这是我的单元测试代码-

const processUtils = require('../src/utils/process-utils')
const axios = require('axios')
jest.mock("axios")
describe("when getAccessToken API is successful", () => {
    test('should return access token', async () => {
        const expectedResponse = JSON.stringify({
            "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxZDY2OTF",
            "issued_token_type": "token-type:access_token",
            "token_type": "Bearer",
            "expires_in": 3600,
            "scope": "consumer_profile:read:"
        })
        axios.post.mockResolvedValueOnce(() => Promise.resolve(expectedResponse))
        // axios.post.mockImplementationOnce(() => Promise.resolve(expectedResponse));

        let urlToCall = 'https://somehost.com/access_token/v1'
        let scope = jest.fn
        let basicAuthToken = jest.fn

        const response = await processUtils.getAccessToken(urlToCall, scope, basicAuthToken)

        expect(mockAxios.post).toHaveBeenCalledWith(urlToCall)
        expect(response).toEqual(expectedResponse)
    });
});

这是 运行 开玩笑时抛出的错误 -

TypeError: Cannot read properties of undefined (reading 'then')

> axios(config)
    .then(function (response) {
       resolve(response.data);
    })

https://i.stack.imgur.com/NZiVp.png 我是节点和笑话的新手。有人可以指出我在这里缺少的东西吗?

问题是因为您的代码没有直接调用 axios 模块实例上的 post 函数,而是通过 config 隐式调用函数,而您的测试模拟正在寻找直接 axios.post 调用。有两种方法可以解决此问题。

  1. 将隐式 post 调用更改为显式调用:

发件人:

axios(config).then(function (response) {

收件人:

axios.post(config.url, config.data, { headers: config.headers }).then(function (response) {

这将使用 axios.post.mockResolvedValueOnce 调用的结果。

  1. 在测试套件设置中模拟 axios post 调用:

发件人:

jest.mock("axios")

jest.mock("axios", () => {
  const expectedResponse = JSON.stringify({
    "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxZDY2OTF",
    "issued_token_type": "token-type:access_token",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "consumer_profile:read:"
  });
  return () => new Promise((resolve) => resolve(expectedResponse));
})

这将通过 partial 模拟模拟隐式 post 调用,但是您将无法直接访问 post 方法,因此您将无法听到它的呼叫。

另外一个小注意,axios.post.mockResolvedValueOnce(() => Promise.resolve(expectedResponse))会在调用then时将一个函数传递给response参数。我觉得你需要用什么mockedAxios.post.mockResolvedValueOnce(expectedResponse)。此外,expectedResponse 应包含在 data 属性 中,如下所示:

const expectedResponse = JSON.stringify({
  "data": {
    "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxZDY2OTF",
    "issued_token_type": "token-type:access_token",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "consumer_profile:read:"
  }
});
I'm trying to post the solution so that it helps someone.
Solution was found based on Ovidijus Parsiunas responses too.
Actual function - 

exports.getAccessToken = function (urlToCall, scope, basicAuthToken) {
  return new Promise(function (resolve, reject) {
    let axios = require("axios");
    let qs = require("qs");
    let data = qs.stringify({
      grant_type: "client_credentials",
      scope: scope,
    });
    const requestHeaders = {
      "Content-Type": "application/x-www-form-urlencoded",
      Authorization: "Basic " + basicAuthToken,
    };
    // axios(config)
    axios
      .post(urlToCall, data, {
        headers: requestHeaders,
      })
      .then(function (response) {
        resolve(response.data);
      })
      .catch(function (error) {
        console.log(
          "error occurred while getting access token for the scope - ",
          scope,
          " and the error is - ",
          error
        );
      });
  });
};

My unit test case - 

const processUtils = require('../src/utils/process-utils')
const axios = require('axios')
jest.mock("axios", () => ({
  post: jest.fn(() => {
    const expectedResponse = {
      access_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxZDY2OTF",
      issued_token_type: "token-type:access_token",
      token_type: "Bearer",
      expires_in: 3600,
      scope: "consumer_profile:read:",
    };
    // return () => new Promise((resolve) => resolve(expectedResponse));
    return expectedResponse;
  }),
}));
describe("when getAccessToken API is successful", () => {
  it("should return access token", async () => {
    const expectedResponse = {
      data: {
        access_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxZDY2OTF",
        issued_token_type: "token-type:access_token",
        token_type: "Bearer",
        expires_in: 3600,
        scope: "consumer_profile:read:",
      },
    };

    axios.post.mockResolvedValueOnce(expectedResponse);

    let urlToCall =
      "https://somehost.com/access_token/v1";
    let scope = jest.fn();
    let basicAuthToken = jest.fn();

    const response = await processUtils.getAccessToken(
      urlToCall,
      scope,
      basicAuthToken
    );
    console.log("response - ", response);
    expect(response).toEqual(expectedResponse.data);
  });