警告 - 未处理的承诺拒绝:发送后无法设置标头

时间:2017-07-28 03:58:41

标签: javascript node.js unit-testing header promise

我有一个这样的路由处理程序:

router.route('/sipprovider/:sipprovider_id/phonelist')
        .post((req, res) => {
            const body = req.body;
            if (typeof body.phones === 'undefined') {
                return res.status(400).json({
                    success: false,
                    error: { message: 'Invalid input' }
                });
            }
            if (!Array.isArray(body.phones) || body.phones.length === 0) {
                return res.status(400).json({
                    success: false,
                    error: { message: 'Invalid input' }
                });
            }
            let i = body.phones.indexOf('');
            while (i >= 0) {
                body.phones.splice(i, 1);
                i = body.phones.indexOf('');
            }
            body.phones.map((phone) => {
                if (typeof phone !== 'string') {
                    return res.status(400).json({
                        success: false,
                        error: { message: 'Invalid input' }
                    });
                }
            });
            const SipProvider = new SipProviderModel(db, logger);
            SipProvider.pushPhoneList(req.params.sipprovider_id, body.phones)
                .then((result) => {
                    if (result) {
                        return res.json({ success: true });
                    }
                    return res.status(404).json({
                        success: false,
                        error: { message: 'Sip provider not found' }
                    });
                })
                .catch((error) => res.status(400).json({
                    success: false,
                    error: { message: error }
                }));
        });
pushPhoneList的{​​{1}}函数是一个承诺。我写了几个测试:

SipProvider

所有这些都通过,但记录器在包含describe('POST', () => { let id; beforeEach(() => SipProvider.create(data).then((result) => id = result._id)); it('Should return 200 if successful', (done) => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .send({ phones: ['02873000050'] }) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.success).to.equal(true); return done(); }); }); it('Should return 200 if successful', (done) => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .send({ phones: ['02873000050', ''] }) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.success).to.equal(true); return done(); }); }); it('Should return 400 if input is invalid (undefined phones)', (done) => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .end((err, res) => { expect(res.status).to.equal(400); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Invalid input'); return done(); }); }); it('Should return 400 if input is invalid (not an array)', (done) => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .send({ phones: '02873000050' }) .end((err, res) => { expect(res.status).to.equal(400); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Invalid input'); return done(); }); }); it('Should return 400 if input is invalid (empty list)', (done) => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .send({ phones: [] }) .end((err, res) => { expect(res.status).to.equal(400); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Invalid input'); return done(); }); }); it('Should return 400 if input is invalid (not an array of string)', (done) => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .send({ phones: ['02873000050', {}] }) .end((err, res) => { expect(res.status).to.equal(400); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Invalid input'); return done(); }); }); it('Should return 404 if not found', (done) => { SipProvider.delete(id).then( () => { chai.request(app) .post('/sipprovider/' + id + '/phonelist') .set('Authorization', token) .send({ phones: ['02873000050'] }) .end((err, res) => { expect(res.status).to.equal(404); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Sip provider not found'); return done(); }); }); }); afterEach(() => SipProvider.delete(id)); }); 的最后一个测试中记录了一些警告

我还没有理解为什么路由处理程序中的最终catch块被调用。我想只有当promise函数被拒绝时才会出现catch

1 个答案:

答案 0 :(得分:3)

首先,在此代码中:

        body.phones.map((phone) => {
            if (typeof phone !== 'string') {
                return res.status(400).json({
                    success: false,
                    error: { message: 'Invalid input' }
                });
            }
        });

您最多可以多次拨打res.status()。这很容易导致"在发送后无法设置标头"问题。这里的问题是return仅从.map()回调返回。它不会阻止.map()中的其他回调,并且在该块执行后它不会阻止其余代码,这也会导致发送另一个响应。

您可以通过执行以下操作来解决此问题:

if (!body.phones.every(phone => typeof phone === 'string')) {
     return res.status(400).json({
         success: false,
         error: { message: 'Invalid input' }
     });
}

这将贯穿所有body.phones项,测试它们是否都是正确的类型,然后,在循环外,如果它们不是所有正确的类型,那么它将return 。这只会发送一个响应,并将从外部函数返回,停止进一步执行。