【问题标题】:Jest TypeScript Error axios_1.default.post.mockImplementation is not a function开玩笑 TypeScript 错误 axios_1.default.post.mockImplementation is not a function
【发布时间】:2020-10-27 18:25:55
【问题描述】:

查看下方更新:

注意:

使用 axios-mock-adapter,除非有人可以指出我可以测试 toHaveBeenCalledWith 的示例。

我还想避免创建 ̶_̶_̶m̶o̶c̶k̶_̶_̶ __mocks__ ( 文件夹,以模拟整个模块。


错误:

我所有的测试都通过了, 但我仍然收到这种类型的错误。

TypeError: axios_1.default.post.mockImplementation is not a function

      28 | const axiosPost = jest.fn(() => ({ success: true }));
      29 | jest.mock('axios');
    > 30 | (axios as jest.Mocked<any>).post.mockImplementation(
         |                                           ^
      31 |   jest.fn().mockImplementation(axiosPost),
      32 | );

代码:

文件: __tests__/index.ts

import axios from 'axios';

// ...

// Before Tests
const axiosPost = jest.fn();
jest.mock('axios');
(axios as jest.Mocked<typeof axios>).post.mockImplementation(
  jest.fn().mockImplementation(axiosPost),
);

// ...

beforeEach(() => {
  jest.clearAllMocks();
});

// Test Performed & Passes
/**
 * Validates send email request
 */
test('test - sendEmail - hello@email.com, some@email.com, my subject, hello there!', async () => {
  // Setup
  const from = 'hello@email.com';
  const to = 'some@email.com';
  const subject = 'my subject';
  const body = 'hello there!';
  const basicAuth = Buffer.from(`api:secret`).toString('base64');

  process.env.MAILGUN_API_URL = 'url';
  process.env.MAILGUN_DOMAIN = 'domain';
  process.env.MAILGUN_SECRET_KEY = 'secret';

  // Pre Expectations
  expect(formData).not.toHaveBeenCalled();
  expect(axiosPost).not.toHaveBeenCalled();

  // Init
  const result = await sendEmail(from, to, subject, body);

  // Post Expectations
  // Form Data
  expect(formData).toHaveBeenCalledTimes(1);
  expect(formDataAppend).toHaveBeenCalledTimes(4);
  expect(formDataAppend.mock.calls[0][0]).toEqual('from');
  expect(formDataAppend.mock.calls[0][1]).toEqual(from);
  expect(formDataAppend.mock.calls[1][0]).toEqual('to');
  expect(formDataAppend.mock.calls[1][1]).toEqual(to);
  expect(formDataAppend.mock.calls[2][0]).toEqual('subject');
  expect(formDataAppend.mock.calls[2][1]).toEqual(subject);
  expect(formDataAppend.mock.calls[3][0]).toEqual('html');
  expect(formDataAppend.mock.calls[3][1]).toEqual(body);
  expect(formDataGetHeaders).toHaveBeenCalledTimes(1);

  // Axios
  expect(axiosPost).toHaveBeenCalledTimes(1);
  expect(axios.post).toHaveBeenCalledWith(
    'url/domain/messages',
    { append: formDataAppend, getHeaders: formDataGetHeaders },
    {
      headers: {
        Authorization: `Basic ${basicAuth}`,
        'Content-Type': 'multipart/form-data',
      },
    },
  );
  expect(result).toStrictEqual({ success: true });
});

更新

根据@estus-flaskrecommendation and direction,我修改了代码以模拟axios 作为包含post 的返回对象,并且不测试jest.fn(),而是使用spyOn

修改文件: __tests__/index.ts

// Mocks
// ========================================================
//  ̶c̶o̶n̶s̶t̶ ̶a̶x̶i̶o̶s̶P̶o̶s̶t̶ ̶=̶ ̶j̶e̶s̶t̶.̶f̶n̶(̶)̶;̶
jest.mock('axios', () => {
  return Object.assign(jest.fn(), {
    post: jest.fn().mockReturnValue({ success: true }),
  });
});

// ...

/**
 * Validates send email request
 */
test('test - sendEmail - hello@email.com, some@email.com, my subject, hello there!', async () => {
  // Setup
  const spyOnAxiosPost = jest.spyOn(axios, 'post');

  // ...
  // Pre Expectations
  expect(formData).not.toHaveBeenCalled();
  //  ̶e̶x̶p̶e̶c̶t̶(̶a̶x̶i̶o̶s̶P̶o̶s̶t̶)̶.̶n̶o̶t̶.̶t̶o̶H̶a̶v̶e̶B̶e̶e̶n̶C̶a̶l̶l̶e̶d̶(̶)̶;̶
  expect(spyOnAxiosPost).not.toBeCalled();

  // Init
  const result = await sendEmail(from, to, subject, body);

  // Post Expectations
  // ...
  // Axios
  //  ̶e̶x̶p̶e̶c̶t̶(̶a̶x̶i̶o̶s̶P̶o̶s̶t̶)̶.̶t̶o̶H̶a̶v̶e̶B̶e̶e̶n̶C̶a̶l̶l̶e̶d̶T̶i̶m̶e̶s̶(̶1̶)̶;̶
  expect(spyOnAxiosPost).toBeCalledTimes(1);
  // ...
  expect(result).toStrictEqual({ success: true });
});

【问题讨论】:

    标签: node.js typescript unit-testing jestjs ts-jest


    【解决方案1】:

    axios 没有完全被 Jest 自动模拟处理,因为 axios 是一个函数而不是一个对象,它的方法像 axios.post 被忽略了。

    __mocks__(不是__mock__)的使用对于手动模拟是可选的。它们可以就地模拟,尽管使用 __mocks__ 进行重用是有意义的:

    jest.mock('axios', () => {
      return Object.assign(jest.fn(), {
        get: jest.fn(),
        post: jest.fn(),
        ...
      });
    });
    

    axios-mock-adaptertoHaveBeenCalledWith 没有问题,因为使用带有自定义适配器的真实 Axios 允许监视方法(但不是 axios() 函数本身):

    jest.spyOn(axios, 'post');
    

    【讨论】:

    • 感谢您的指导和回答。我用上面的答案更新了问题。我仍然觉得 Jest 对我来说就像一个迷宫,但我真的很感谢你的帮助。
    • 明确地说,它要么是 jest.mock 要么是 spyOn。当你使用真正的 Axios 时需要 spyOn(使用 axios-mock-adapter,因为你不想在测试中以任何方式发出真正的请求)。
    • 唯一真正帮助我的答案:)))))))
    猜你喜欢
    • 1970-01-01
    • 2018-03-19
    • 2016-10-09
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 2017-02-26
    相关资源
    最近更新 更多