Jest TypeScript 错误 axios_1.default.post.mockImplementation 不是函数
Jest TypeScript Error axios_1.default.post.mockImplementation is not a function
查看以下更新:
注:
我不使用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-flask's 我修改了代码以模拟 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 });
});
axios
不完全由 Jest 自动模拟处理,因为 axios
是一个函数而不是一个对象,它的方法如 axios.post
被忽略。
使用 __mocks__
(不是 __mock__
)对于手动模拟是可选的。它们可以就地模拟,尽管使用 __mocks__
进行重用是有意义的:
jest.mock('axios', () => {
return Object.assign(jest.fn(), {
get: jest.fn(),
post: jest.fn(),
...
});
});
axios-mock-adapter
和 toHaveBeenCalledWith
没有问题,因为使用带有自定义适配器的真实 Axios 允许监视方法(但不是 axios()
函数本身):
jest.spyOn(axios, 'post');
查看以下更新:
注:
我不使用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-flask's 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 });
});
axios
不完全由 Jest 自动模拟处理,因为 axios
是一个函数而不是一个对象,它的方法如 axios.post
被忽略。
使用 __mocks__
(不是 __mock__
)对于手动模拟是可选的。它们可以就地模拟,尽管使用 __mocks__
进行重用是有意义的:
jest.mock('axios', () => {
return Object.assign(jest.fn(), {
get: jest.fn(),
post: jest.fn(),
...
});
});
axios-mock-adapter
和 toHaveBeenCalledWith
没有问题,因为使用带有自定义适配器的真实 Axios 允许监视方法(但不是 axios()
函数本身):
jest.spyOn(axios, 'post');