如何使用 Jest 和酶模拟 axios.CancelToken
How to mock axios.CancelToken using Jest and enzyme
我正在尝试对以下模块进行单元测试,但出现以下错误。有人可以在这里分享关于如何模拟 axios.CancelToken()
的任何想法吗?或者如何测试这部分?
service.js
let myCancelToken
export async function myTestFuncService (name) {
if (myCancelToken) {
myCancelToken.cancel()
}
myCancelToken = axios.CancelToken.source()
try {
return axios.get(`mypath/${name}`, {
cancelToken: myCancelToken.token
})
} catch (e) {
return e
}
}
service.test.js
import * as myModule from './service.js'
import axios from 'axios'
jest.mock('axios')
it('test myTestFuncService', async () => {
const testData = {
data: {
response: 'some test data'
}
}
axios.get.mockImplementationOnce(() => Promise.resolve(testData))
await expect(
myModule.myTestFuncService('ABC')
).resolves.toBe(testData)
})
错误:
TypeError: Cannot set property 'cancel' of undefined
您可以使用 jest.spyOn()
模拟 axios.CancelToken.source()
和 axios.get()
方法。
另外,由于你在模块的范围内定义了变量myCancelToken
,所以在请求模块并执行myTestFuncService
方法后,myCancelToken
会被赋值一个值,下次请求模块时,它将从 request.cache
中获取并影响后面的测试用例。因此,您需要使用jest.resetModules()
清除模块的缓存,以确保不同的测试用例使用“新鲜”模块。
例如
service.js
:
import axios from 'axios';
let myCancelToken;
export async function myTestFuncService(name) {
if (myCancelToken) {
myCancelToken.cancel();
}
myCancelToken = axios.CancelToken.source();
try {
return await axios.get(`mypath/${name}`, {
cancelToken: myCancelToken.token,
});
} catch (e) {
return e;
}
}
service.test.js
:
describe('68673646', () => {
let mod;
let axios;
beforeEach(() => {
jest.resetModules();
mod = require('./service');
axios = require('axios').default;
});
afterEach(() => {
jest.restoreAllMocks();
});
test('should get name', async () => {
const cancelTokenSource = { cancel: jest.fn(), token: { reason: { message: 'user canceled' } } };
jest.spyOn(axios.CancelToken, 'source').mockReturnValueOnce(cancelTokenSource);
jest.spyOn(axios, 'get').mockResolvedValueOnce('teresa teng');
await mod.myTestFuncService('ABC');
expect(axios.get).toBeCalledWith('mypath/ABC', { cancelToken: cancelTokenSource.token });
expect(axios.CancelToken.source).toBeCalledTimes(1);
});
test('should cancel if cancel token exists', async () => {
const cancelTokenSource = { cancel: jest.fn(), token: { reason: { message: 'user canceled' } } };
jest.spyOn(axios.CancelToken, 'source').mockReturnValue(cancelTokenSource);
jest.spyOn(axios, 'get').mockResolvedValue('teresa teng');
await mod.myTestFuncService('ABC');
expect(axios.get).toBeCalledWith('mypath/ABC', { cancelToken: cancelTokenSource.token });
expect(axios.CancelToken.source).toBeCalledTimes(1);
await mod.myTestFuncService('DEF');
expect(cancelTokenSource.cancel).toBeCalledTimes(1);
expect(axios.get).toBeCalledWith('mypath/DEF', { cancelToken: cancelTokenSource.token });
});
});
测试结果:
PASS examples/68673646/service.test.js (7.34 s)
68673646
✓ should get name (6360 ms)
✓ should cancel if cancel token exists (7 ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 87.5 | 100 | 100 | 87.5 |
service.js | 87.5 | 100 | 100 | 87.5 | 14
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 7.82 s, estimated 8 s
我正在测试 cancelToken 是否可以像这样卸载组件:
test('Should stop pending request in case the component is unmounted', async () => {
const { result, unmount } = renderHook(() =>
// hook goes here
);
expect(result.current.cancelTokenSource.token.reason).not.toBeDefined();
unmount();
expect(result.current.cancelTokenSource.token.reason).toBeDefined();
});
在 cancelToken
被取消后,原因字段被添加到对象中,这让我们可以像这样测试取消。
我们不会模拟令牌本身,但在某些情况下这也可能是一种方式。
我正在尝试对以下模块进行单元测试,但出现以下错误。有人可以在这里分享关于如何模拟 axios.CancelToken()
的任何想法吗?或者如何测试这部分?
service.js
let myCancelToken
export async function myTestFuncService (name) {
if (myCancelToken) {
myCancelToken.cancel()
}
myCancelToken = axios.CancelToken.source()
try {
return axios.get(`mypath/${name}`, {
cancelToken: myCancelToken.token
})
} catch (e) {
return e
}
}
service.test.js
import * as myModule from './service.js'
import axios from 'axios'
jest.mock('axios')
it('test myTestFuncService', async () => {
const testData = {
data: {
response: 'some test data'
}
}
axios.get.mockImplementationOnce(() => Promise.resolve(testData))
await expect(
myModule.myTestFuncService('ABC')
).resolves.toBe(testData)
})
错误:
TypeError: Cannot set property 'cancel' of undefined
您可以使用 jest.spyOn()
模拟 axios.CancelToken.source()
和 axios.get()
方法。
另外,由于你在模块的范围内定义了变量myCancelToken
,所以在请求模块并执行myTestFuncService
方法后,myCancelToken
会被赋值一个值,下次请求模块时,它将从 request.cache
中获取并影响后面的测试用例。因此,您需要使用jest.resetModules()
清除模块的缓存,以确保不同的测试用例使用“新鲜”模块。
例如
service.js
:
import axios from 'axios';
let myCancelToken;
export async function myTestFuncService(name) {
if (myCancelToken) {
myCancelToken.cancel();
}
myCancelToken = axios.CancelToken.source();
try {
return await axios.get(`mypath/${name}`, {
cancelToken: myCancelToken.token,
});
} catch (e) {
return e;
}
}
service.test.js
:
describe('68673646', () => {
let mod;
let axios;
beforeEach(() => {
jest.resetModules();
mod = require('./service');
axios = require('axios').default;
});
afterEach(() => {
jest.restoreAllMocks();
});
test('should get name', async () => {
const cancelTokenSource = { cancel: jest.fn(), token: { reason: { message: 'user canceled' } } };
jest.spyOn(axios.CancelToken, 'source').mockReturnValueOnce(cancelTokenSource);
jest.spyOn(axios, 'get').mockResolvedValueOnce('teresa teng');
await mod.myTestFuncService('ABC');
expect(axios.get).toBeCalledWith('mypath/ABC', { cancelToken: cancelTokenSource.token });
expect(axios.CancelToken.source).toBeCalledTimes(1);
});
test('should cancel if cancel token exists', async () => {
const cancelTokenSource = { cancel: jest.fn(), token: { reason: { message: 'user canceled' } } };
jest.spyOn(axios.CancelToken, 'source').mockReturnValue(cancelTokenSource);
jest.spyOn(axios, 'get').mockResolvedValue('teresa teng');
await mod.myTestFuncService('ABC');
expect(axios.get).toBeCalledWith('mypath/ABC', { cancelToken: cancelTokenSource.token });
expect(axios.CancelToken.source).toBeCalledTimes(1);
await mod.myTestFuncService('DEF');
expect(cancelTokenSource.cancel).toBeCalledTimes(1);
expect(axios.get).toBeCalledWith('mypath/DEF', { cancelToken: cancelTokenSource.token });
});
});
测试结果:
PASS examples/68673646/service.test.js (7.34 s)
68673646
✓ should get name (6360 ms)
✓ should cancel if cancel token exists (7 ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 87.5 | 100 | 100 | 87.5 |
service.js | 87.5 | 100 | 100 | 87.5 | 14
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 7.82 s, estimated 8 s
我正在测试 cancelToken 是否可以像这样卸载组件:
test('Should stop pending request in case the component is unmounted', async () => {
const { result, unmount } = renderHook(() =>
// hook goes here
);
expect(result.current.cancelTokenSource.token.reason).not.toBeDefined();
unmount();
expect(result.current.cancelTokenSource.token.reason).toBeDefined();
});
在 cancelToken
被取消后,原因字段被添加到对象中,这让我们可以像这样测试取消。
我们不会模拟令牌本身,但在某些情况下这也可能是一种方式。