为什么我的jest.mock中的Promise reject()转到then()而不是catch()? [英] Why is the Promise reject() in my jest.mock going to a then() rather than a catch()?

查看:282
本文介绍了为什么我的jest.mock中的Promise reject()转到then()而不是catch()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个文件, getItemInfo.js 进行API调用, getItemInfo.test.js 这是各自的Jest测试文件。

I have two files, getItemInfo.js to make API calls and getItemInfo.test.js which is the respective Jest test file.

在测试文件中,我模拟由节点模块 request-promise 触发的http调用。

On the test file, I am mocking the http calling triggered by node module request-promise.

问题出在第二个代码块上,由 ********* 包围。
基本上为什么 reject()错误仍然会转到第二个单元中的 then()块测试?

The question is on the second code block, surrounded by *********'s. Basically why is the reject() error still going to a then() block in the second unit test?

// getItemInfo.js

const rp = require('request-promise');

const getItemInfo = (id) => {
    const root = 'https://jsonplaceholder.typicode.com/posts/';
    const requestOptions = {
        uri: `${root}/${id}`,
        method: 'GET',
        json: true
    }

    return rp(requestOptions)
    .then((result) => {
        return result;
    })
    .catch((err) => {
        return err;
    });
};

module.exports = {
    getItemInfo: getItemInfo
};

这是我的Jest单元测试文件。

And here is my Jest unit test file.

// getItemInfo.test.js
const ItemService = require('./getItemInfo');

jest.mock('request-promise', () => (options) => {
    const id = Number.parseInt(options.uri.substring(options.uri.lastIndexOf('/') + 1));

    return new Promise((resolve, reject) => {
        if (id === 12) {
            return resolve({
                id: id,
                userId: 1,
                title: '',
                body: ''
            });
        } else {
            return reject('something went wrong'); // <-- HERE IS THE REJECT
        }
    })
});

describe('getItemInfo', () => {
    it('can pass', done => {
        const TEST_ID = 12
        ItemService.getItemInfo(TEST_ID).then((result) => {
            console.log('result:',result);
            expect(result.id).toBe(TEST_ID);
            expect(result.userId).toBeDefined();
            expect(result.title).toBeDefined();
            expect(result.body).toBeDefined();
            done();
        });
    });

    it('can fail', (done) => {
        const TEST_ID = 13;
        ItemService.getItemInfo(TEST_ID)
        .catch((err) => {
            // *************
            // This "catch" block never runs
            // even if the jest.mock above Promise.rejects
            // Why is that???
            // *************
            console.log('catch():', err);
            done();
        })
        .then((result) => {
            // this block runs instead.
            // and it returns "then: something went wrong"
            console.log('then():', result);
            done();
        });
    });
});

这是单位测试的输出。该命令只是 jest 。最后一行应该从 catch()语句运行,而不是然后()

This is the unit test's output. The command is simply jest. The last line should be run from the catch() statement, not the then():

PASS  ./getItemInfo.test.js
 getItemInfo
   ✓ can pass (9ms)
   ✓ can fail (1ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.703s, estimated 1s
Ran all test suites.
----------------|----------|----------|----------|----------|----------------|
File            |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
----------------|----------|----------|----------|----------|----------------|
All files       |      100 |      100 |      100 |      100 |                |
getItemInfo.js |      100 |      100 |      100 |      100 |                |
----------------|----------|----------|----------|----------|----------------|
 console.log getItemInfo.test.js:25
   result: { id: 12, userId: 1, title: '', body: '' }

 console.log getItemInfo.test.js:48
   then(): something went wrong

我是什么做错了?

推荐答案


为什么我的jest.mock中的Promise reject()转到了那么()而不是catch()?

Why is the Promise reject() in my jest.mock going to a then() rather than a catch()?

你的 .catch() handler将被拒绝的promise转换为已解析的promise,因此只调用外部的 .then()处理程序。

Your .catch() handler is converting a rejected promise into a resolved promise and thus only the outer .then() handler is called.

当您使用 .catch()时,如下所示:

When you use .catch() like this:

.catch((err) => {
    return err;
});

并且不要重新抛出错误或返回被拒绝的承诺,然后拒绝被视为已处理且返回的承诺将被解决,而不是被拒绝。这就像使用try / catch一样。在catch处理程序中,异常会被处理,除非你再次抛出它。

and do not rethrow the error or return a rejected promise, then the rejection is considered "handled" and the returned promise becomes resolved, not rejected. This is just like using a try/catch. In a catch handler, the exception is handled unless you throw it again.

你可以在这个简单的片段中看到:

You can see that in this simple snippet:

new Promise((resolve, reject) => {
    reject(new Error("reject 1"));
}).catch(err => {
    // returning a normal value here (anything other than a rejected promise)
    // causes the promise chain to flip to resolved
    return err;
}).then(val => {
    console.log("Promise is now resolved, not rejected");
}).catch(err => {
    console.log("Don't get here");
});

其中任何一个都没有理由:

There's really no reason for either of these:

.then((result) => {
    return result;
})
.catch((err) => {
    return err;
});

您可以删除它们。 .then()处理程序只是多余的代码而 .catch()处理程序会拒绝并将其转换为已解决的承诺。

You can just remove both of them. The .then() handler is just superfluous code and the .catch() handler eats the rejection and turns it into a resolved promise.

如果要保留 .catch()处理程序,但允许拒绝传播向上,然后你需要重新抛出。

If you want to keep the .catch() handler, but allow the rejection to propagate upwards, then you need to rethrow.

.catch((err) => {
    console.log(err);
    throw err;       // keep promise rejected so reject will propagate upwards
});

这篇关于为什么我的jest.mock中的Promise reject()转到then()而不是catch()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆