jest expect().resolves和expect().rejects原理

假设存在如下代码

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取出返回值与预测值进行比较。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值