假设存在如下代码
export default function fetchData(fn) {
return Axios.get('http://www.dell-lee.com/react/api/demo.json')
}
接口返回的数据为
{
"success": true
}
那么对于测试代码
test('fetchData', async () => {
await expect(fetchData()).resolves.toMatchObject({data:{ success: true}})
})
执行逻辑大致等同于
test('fetchData', async () => {
await fetchData().then(res => expect(res).toMatchObject({ data: { success: true } }));
})
以上两种测试代码只是在接口返回状态不为200时,测试用例报错提醒略有差异。
下面来具体看一下expect方法的执行逻辑。
expect方法返回expectation对象,该对象的方法为各种匹配器方法,以及加上.not/.resolves/.reject前缀的匹配器方法。
const expect = (actual, ...rest) => {
/// ...
const allMatchers = (0, _jestMatchersObject.getMatchers)();
const expectation = {
not: {},
rejects: {
not: {}
},
resolves: {
not: {}
}
};
const err = new JestAssertionError();
Object.keys(allMatchers).forEach(name => {
const matcher = allMatchers[name];
const promiseMatcher = getPromiseMatcher(name, matcher) || matcher;
expectation[name] = makeThrowingMatcher(matcher, false, '', actual);
expectation.not[name] = makeThrowingMatcher(matcher, true, '', actual);
expectation.resolves[name] = makeResolveMatcher(
name,
promiseMatcher,
false,
actual,
err
);
expectation.resolves.not[name] = makeResolveMatcher(
name,
promiseMatcher,
true,
actual,
err
);
expectation.rejects[name] = makeRejectMatcher(
name,
promiseMatcher,
false,
actual,
err
);
expectation.rejects.not[name] = makeRejectMatcher(
name,
promiseMatcher,
true,
actual,
err
);
});
return expectation;
};
当我们调用.resolves.toMatchObject方法,其实就是执行makeResolveMatcher 方法的返回值函数。
makeResolveMatcher闭包内的函数其实就干了两件事。
1. 如果fetchData返回值actual不是一个promise,抛出异常。
2. 调用actual.then。如果走了成功的回调,那么就调用toMatchObject匹配器;如果走失败的回调就抛出异常。
const makeResolveMatcher = (matcherName, matcher, isNot, actual, outerErr) => (
...args
) => {
const options = {
isNot,
promise: 'resolves'
};
if (!isPromise(actual)) {
throw new JestAssertionError(
matcherUtils.matcherErrorMessage(
matcherUtils.matcherHint(matcherName, undefined, '', options),
`${matcherUtils.RECEIVED_COLOR('received')} value must be a promise`,
matcherUtils.printWithType(
'Received',
actual,
matcherUtils.printReceived
)
)
);
}
const innerErr = new JestAssertionError();
return actual.then(
result =>
makeThrowingMatcher(matcher, isNot, 'resolves', result, innerErr).apply(
null,
args
),
reason => {
outerErr.message =
matcherUtils.matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received promise rejected instead of resolved\n` +
`Rejected to value: ${matcherUtils.printReceived(reason)}`;
return Promise.reject(outerErr);
}
);
};
.rejects.toMatchObject的执行逻辑也类似。
makeResolveMatcher闭包内的函数其实就干了两件事。
1. 如果fetchData返回值actual不是一个promise,抛出异常。
2. 调用actual.then。如果走了成功的回调就抛出异常;如果走失败的回调,那么就调用toMatchObject匹配器。
const makeRejectMatcher = (matcherName, matcher, isNot, actual, outerErr) => (
...args
) => {
const options = {
isNot,
promise: 'rejects'
};
if (!isPromise(actual)) {
throw new JestAssertionError(
matcherUtils.matcherErrorMessage(
matcherUtils.matcherHint(matcherName, undefined, '', options),
`${matcherUtils.RECEIVED_COLOR('received')} value must be a promise`,
matcherUtils.printWithType(
'Received',
actual,
matcherUtils.printReceived
)
)
);
}
const innerErr = new JestAssertionError();
return actual.then(
result => {
outerErr.message =
matcherUtils.matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received promise resolved instead of rejected\n` +
`Resolved to value: ${matcherUtils.printReceived(result)}`;
return Promise.reject(outerErr);
},
reason =>
makeThrowingMatcher(matcher, isNot, 'rejects', reason, innerErr).apply(
null,
args
)
);
};
总结
所以所谓.resolves和.rejects其实就是一种简化写法,jest帮我们调用.then取出返回值与预测值进行比较。