javascript - Warning - Unhandled promise rejection: Can't set headers after they are sent -
i have route handler this:
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 = body.phones.indexof(''); while (i >= 0) { body.phones.splice(i, 1); = 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
function of sipprovider
promise. , write several tests:
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 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 invalid (not 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 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 invalid (not 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)); });
all of them pass, logger records warnings in last test containing unhandledpromiserejectionwarning: unhandled promise rejection, can't set headers after sent
i haven't got why ultimate catch block in route handler gets called. thought when promise function gets rejected, catch occur
first off, in code:
body.phones.map((phone) => { if (typeof phone !== 'string') { return res.status(400).json({ success: false, error: { message: 'invalid input' } }); } });
you can end calling res.status()
multiple times. can cause "can't set headers after sent" problem. problem here return
returns .map()
callback. doesn't stop other callbacks in .map()
, doesn't prevent rest of code after block executing cause response sent.
you fix issue doing this:
if (!body.phones.every(phone => typeof phone === 'string')) { return res.status(400).json({ success: false, error: { message: 'invalid input' } }); }
this run through body.phones
items, test see if correct type , then, outside loop, if not correct type, return
. send 1 response , return outer function, stopping further execution.
Comments
Post a Comment