【问题标题】:Expected one assertion to be called but received zero assertion calls. Why?期望调用一个断言,但接收到零个断言调用。为什么?
【发布时间】:2021-12-04 18:53:27
【问题描述】:

我正在编写一个rejectOnTimeout() 函数,如果该承诺未在ms 中完成,则该函数应返回一个带有timeout_error 值的被拒绝承诺,或者返回一个反映原始承诺行为的承诺。

我认为我得到的答案是正确的。但是我不明白错误Expected one assertion to be called but received zero assertion calls的含义。

在这种情况下我做错了什么?

const delay = require('delay');

/**
 * @param  {Promise} original promise 
 * @param  {Number}  ms for timeout
 * @return {Promise}
 */
const rejectOnTimeout = (promise, ms) => new Promise((resolve, reject) => {
  const start = Date.now();

  promise.finally(() => {
    const time = Date.now() - start;

    if (time <= ms) {
      resolve(promise);
    }
    reject('timeout_error');
  });
});

// Test 1 [PASSED]
rejectOnTimeout(Promise.resolve(10), 100)
  .then(data => console.log(data)) // 10
  .catch(err => console.error(err));

// Test 2 [PASSED]
rejectOnTimeout(Promise.reject(10), 100)
  .then(data => console.log(data))
  .catch(err => console.error(err)); // 10

// Test 3 [FAILED], REASON: Expected one assertion to be called but received zero assertion calls.
const delayed = delay(100, { value: 10 });

rejectOnTimeout(delayed, 50)
  .then(data => console.log(data))
  .catch(err => console.error(err)); // timeout_error

测试代码:

describe('rejectOnTimeout', () => {
    it('rejectOnTimeout, 01', async() => {
      expect.assertions(1);
      await expect(rejectOnTimeout(Promise.resolve(10), 100)).resolves.toBe(10);
    });

    it('rejectOnTimeout, 02', async() => {
      expect.assertions(1);
      await expect(rejectOnTimeout(Promise.reject(10), 100)).rejects.toBe(10);
    });

    it('rejectOnTimeout, 03', async() => {
      expect.assertions(1);
      const delayed = delay(100, { value: 10 });

      await expect(rejectOnTimeout(delayed, 50)).rejects.toBe('timeout_error');
    });

    it('rejectOnTimeout, 04', async() => {
      expect.assertions(1);
      const delayed = delay.reject(100, { value: 10 });

      await expect(rejectOnTimeout(delayed, 50)).rejects.toBe('timeout_error');
    });

    it('rejectOnTimeout, 05', async() => {
      expect.assertions(1);
      const delayed = delay(100, { value: 10 });

      await expect(rejectOnTimeout(delayed, 1000)).resolves.toBe(10);
    });

    it('rejectOnTimeout, 06', async() => {
      expect.assertions(1);
      const delayed = delay.reject(100, { value: 'error' });

      await expect(rejectOnTimeout(delayed, 1000)).rejects.toBe('error');
    });

【问题讨论】:

  • 我们也可以有测试代码吗?
  • 是的,我添加了它

标签: javascript promise jestjs


【解决方案1】:

当我将您的代码插入我的编辑器时,我遇到了另一个错误:

● rejectOnTimeout › rejectOnTimeout, 03

thrown: 10

问题是之前的测试向测试环境抛出了未经处理的拒绝,一切都爆炸了。将rejectOnTimeout 实现更改为此后,所有测试都通过了:

const rejectOnTimeout = (promise, ms) =>
  new Promise((resolve, reject) => {
    const start = Date.now();

    promise
      .catch((e) => reject(e))
      .finally(() => {
        const time = Date.now() - start;

        if (time <= ms) {
          resolve(promise);
        }
        reject("timeout_error");
      });
  });

Promise.finally 实际上并不处理拒绝,它只是触发 Promise 是拒绝还是解析。因此,虽然 rejectOnTimeout 中的新 Promise 可能正确完成,但底层的 Promise 参数并未得到处理。

内部捕获似乎可以保留您正在寻找的行为。如果 Promise 已经抛出错误,大概我们实际上并不关心是否有超时。 finally 中发生的事情也无关紧要,因为您无法在拒绝 Promise 后覆盖它的结果。

以下是我将如何实现此功能:

const rejectOnTimeout = (promise, ms) => {
   return new Promise((resolve, reject) => {
     setTimeout(() => reject("timeout_error"), ms);
     
     promise
       .catch((e) => reject(e))
       .finally(() => resolve(promise));
   });
}

【讨论】:

  • 谢谢,但试试这个:rejectOnTimeout(delayed, 50) 我得到 10 而不是 timeout_error
  • const 延迟 = delay.reject(100, { value: 10 });
  • 如果我们先处理finally(),再处理catch(),没有错误,但是在其他测试中出现错误
  • 我添加了其他测试
  • 好吧,老实说,我会考虑当前实现的预期行为。您的函数实际上并不像超时,因为它正在等待原始承诺完成,但它实际上不应该关心该承诺的作用。如果超时到期,它应该 early 拒绝。我认为您需要回头看看如何分离逻辑 - 在某处实际调用 setTimeout 可能是一个不错的起点。
猜你喜欢
  • 2018-02-25
  • 2020-08-24
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
相关资源
最近更新 更多