diff --git a/tests/e2e/default/contacts/edit.wdio-spec.js b/tests/e2e/default/contacts/edit.wdio-spec.js index 2f7dd5972ad..c9c7ff74f06 100644 --- a/tests/e2e/default/contacts/edit.wdio-spec.js +++ b/tests/e2e/default/contacts/edit.wdio-spec.js @@ -1,3 +1,4 @@ +const cloneDeep = require('lodash/cloneDeep'); const loginPage = require('@page-objects/default/login/login.wdio.page'); const commonPage = require('@page-objects/default/common/common.wdio.page'); const placeFactory = require('@factories/cht/contacts/place'); @@ -16,7 +17,7 @@ describe('Edit ', () => { const offlineUserContact = personFactory.build({ name: CONTACT_NAME, parent: healthCenter }); const onlineUserContact = personFactory.build({ parent: healthCenter }); - healthCenter.contact = offlineUserContact; + healthCenter.contact = cloneDeep(offlineUserContact); const offlineUser = userFactory.build({ username: 'offline_user', diff --git a/tests/e2e/default/logging/logging.wdio-spec.js b/tests/e2e/default/logging/logging.wdio-spec.js index b5a309c62c5..4288d53ae9a 100644 --- a/tests/e2e/default/logging/logging.wdio-spec.js +++ b/tests/e2e/default/logging/logging.wdio-spec.js @@ -41,7 +41,6 @@ describe('audit log', () => { continuous: false }; const requestOptions = { - resolveWithFullResponse: true, path: '/_replicator', method: 'POST', body diff --git a/tests/e2e/default/pwa/manifest.wdio-spec.js b/tests/e2e/default/pwa/manifest.wdio-spec.js index fc88697b135..a6b1b8d137e 100644 --- a/tests/e2e/default/pwa/manifest.wdio-spec.js +++ b/tests/e2e/default/pwa/manifest.wdio-spec.js @@ -31,7 +31,7 @@ describe('manifest.json', () => { try { await utils.deleteDoc('branding'); } catch (err) { - if (err.statusCode === 404) { + if (err.status === 404) { return; // already not there - success! } throw err; @@ -53,7 +53,7 @@ describe('manifest.json', () => { try { return await utils.getDoc('branding'); } catch (e) { - if (e.statusCode === 404) { + if (e.status === 404) { return { _id: 'branding' }; } throw e; diff --git a/tests/e2e/default/sms/rapidpro.wdio-spec.js b/tests/e2e/default/sms/rapidpro.wdio-spec.js index fd5816a026c..9d3c378a324 100644 --- a/tests/e2e/default/sms/rapidpro.wdio-spec.js +++ b/tests/e2e/default/sms/rapidpro.wdio-spec.js @@ -75,7 +75,7 @@ describe('RapidPro SMS Gateway', () => { }); throw new Error('should have thrown'); } catch (err) { - expect(err.responseBody).to.eql({ code: 403, error: 'No incoming key configured' }); + expect(err.body).to.eql({ code: 403, error: 'No incoming key configured' }); } }); @@ -91,7 +91,7 @@ describe('RapidPro SMS Gateway', () => { }); throw new Error('should have thrown'); } catch (err) { - expect(err.responseBody).to.eql({ code: 403, error: 'Missing authorization token' }); + expect(err.body).to.eql({ code: 403, error: 'Missing authorization token' }); } }); @@ -108,7 +108,7 @@ describe('RapidPro SMS Gateway', () => { }); throw new Error('should have thrown'); } catch (err) { - expect(err.responseBody).to.eql({ code: 403, error: 'Incorrect token' }); + expect(err.body).to.eql({ code: 403, error: 'Incorrect token' }); } }); @@ -125,7 +125,7 @@ describe('RapidPro SMS Gateway', () => { }); throw new Error('should have thrown'); } catch (err) { - expect(err.responseBody).to.eql({ code: 403, error: 'Missing authorization token' }); + expect(err.body).to.eql({ code: 403, error: 'Missing authorization token' }); } }); @@ -143,7 +143,7 @@ describe('RapidPro SMS Gateway', () => { }); throw new Error('should have thrown'); } catch (err) { - expect(err.responseBody).to.eql({ code: 400, error: 'Message was not saved' }); + expect(err.body).to.eql({ code: 400, error: 'Message was not saved' }); } }); diff --git a/tests/e2e/default/transitions/create-user-for-contacts.replace-user.wdio-spec.js b/tests/e2e/default/transitions/create-user-for-contacts.replace-user.wdio-spec.js index 8597e8b2b7b..a67c72d1c3d 100644 --- a/tests/e2e/default/transitions/create-user-for-contacts.replace-user.wdio-spec.js +++ b/tests/e2e/default/transitions/create-user-for-contacts.replace-user.wdio-spec.js @@ -109,7 +109,7 @@ describe('Create user for contacts', () => { path: '/medic/login', body: { user: username, password, locale: 'en' }, method: 'POST', - simple: false, + resolveWithFullResponse: true, noAuth: true, }; return utils.request(opts); @@ -118,7 +118,7 @@ describe('Create user for contacts', () => { const assertUserPasswordChanged = async (user) => { // Cannot login because user's password has been automatically reset const resp0 = await submitLoginRequest(user); - expect(resp0.statusCode).to.equal(401); + expect(resp0.status).to.equal(401); // Update user's password to something we know await utils.request({ @@ -129,7 +129,7 @@ describe('Create user for contacts', () => { // Can login with new password const resp1 = await submitLoginRequest({ ...user, password: DISABLED_USER_PASSWORD }); - expect(resp1.statusCode).to.equal(302); + expect(resp1.status).to.equal(302); }; const assertNewUserSettings = (newUserSettings, newContact, originalUser) => { @@ -799,7 +799,7 @@ describe('Create user for contacts', () => { expect(updatedOriginalContact.user_for_contact).to.be.undefined; // Can still login as original user const resp1 = await submitLoginRequest(ONLINE_USER); - expect(resp1.statusCode).to.equal(302); + expect(resp1.status).to.equal(302); // New user not created const newUserSettings = await utils.getUserSettings({ contactId: replacementContactId }); expect(newUserSettings).to.be.empty; diff --git a/tests/integration/.mocharc-base.js b/tests/integration/.mocharc-base.js index 99223dd2f61..068a4b04fb7 100644 --- a/tests/integration/.mocharc-base.js +++ b/tests/integration/.mocharc-base.js @@ -7,7 +7,9 @@ const deepEqualInAnyOrder = require('deep-equal-in-any-order'); chai.use(chaiExclude); chai.use(chaiAsPromised); chai.use(deepEqualInAnyOrder); +chai.use(require('chai-shallow-deep-equal')); global.expect = chai.expect; +global.chai = chai; module.exports = { allowUncaught: false, diff --git a/tests/integration/api/controllers/all-docs.spec.js b/tests/integration/api/controllers/all-docs.spec.js index f67f88b71cd..3df2c65bbd8 100644 --- a/tests/integration/api/controllers/all-docs.spec.js +++ b/tests/integration/api/controllers/all-docs.spec.js @@ -206,7 +206,6 @@ describe('all_docs handler', () => { const request = { method: 'POST', body: { keys }, - headers: { 'Content-Type': 'application/json' } }; return utils diff --git a/tests/integration/api/controllers/bulk-docs.spec.js b/tests/integration/api/controllers/bulk-docs.spec.js index d20c07a09a9..10cf7bb7fc6 100644 --- a/tests/integration/api/controllers/bulk-docs.spec.js +++ b/tests/integration/api/controllers/bulk-docs.spec.js @@ -286,13 +286,13 @@ describe('bulk-docs handler', () => { }).then(result => { chai.expect(result.length).to.equal(8); chai.expect(result[0]).excluding('_rev').to.deep.equal(docs[0]); - chai.expect(result[1]).to.deep.nested.include({ 'responseBody.error': 'not_found' }); + chai.expect(result[1]).to.deep.nested.include({ 'body.error': 'not_found' }); chai.expect(result[2]).excluding('_rev').to.deep.equal(existentDocs[2]); chai.expect(result[3]).excluding('_rev').to.deep.equal(existentDocs[3]); chai.expect(result[4]).excluding('_rev').to.deep.equal(existentDocs[0]); chai.expect(result[5]).excluding('_rev').to.deep.equal(docs[5]); - chai.expect(result[6]).to.deep.nested.include({ 'responseBody.error': 'not_found' }); + chai.expect(result[6]).to.deep.nested.include({ 'body.error': 'not_found' }); chai.expect(result[7]).excluding( ['_rev', '_id']).to.deep.equal(docs[7]); return sUtils.waitForSentinel(ids).then(() => sUtils.getInfoDocs(ids)); @@ -757,12 +757,12 @@ describe('bulk-docs handler', () => { chai.expect(results.length).to.equal(8); chai.expect(results[0]).excluding('_rev').to.deep.equal(docs[0]); - chai.expect(results[1]).to.deep.nested.include({ 'responseBody.error': 'not_found' }); + chai.expect(results[1]).to.deep.nested.include({ 'body.error': 'not_found' }); chai.expect(results[2]).excluding('_rev').to.deep.equal(existentDocs[2]); chai.expect(results[3]).excluding('_rev').to.deep.equal(existentDocs[3]); chai.expect(results[4]).excluding('_rev').to.deep.equal(existentDocs[0]); chai.expect(results[5]).excluding('_rev').to.deep.equal(docs[5]); - chai.expect(results[6]).to.deep.nested.include({ 'responseBody.error': 'not_found' }); + chai.expect(results[6]).to.deep.nested.include({ 'body.error': 'not_found' }); chai.expect(results[7]).excluding(['_rev', '_id']).to.deep.equal(docs[7]); }); }); @@ -804,7 +804,7 @@ describe('bulk-docs handler', () => { chai.expect(result[0]).to.include({ id: 'denied_report', error: 'forbidden' }); } else { // CouchDB interprets this as an attachment POST request - chai.expect(result).to.deep.nested.include({ 'responseBody.error': 'method_not_allowed' }); + chai.expect(result).to.deep.nested.include({ 'body.error': 'method_not_allowed' }); } }); }); @@ -862,9 +862,9 @@ describe('bulk-docs handler', () => { }) .then(results => { chai.expect(results[0]).to.deep.equal(docs[0]); - chai.expect(results[1]).to.include({ statusCode: 404 }); + chai.expect(results[1]).to.include({ status: 404 }); chai.expect(results[2]).to.deep.equal(docs[2]); - chai.expect(results[3]).to.include({ statusCode: 404 }); + chai.expect(results[3]).to.include({ status: 404 }); }); }); diff --git a/tests/integration/api/controllers/bulk-get.spec.js b/tests/integration/api/controllers/bulk-get.spec.js index cc23e31f647..d8d60701217 100644 --- a/tests/integration/api/controllers/bulk-get.spec.js +++ b/tests/integration/api/controllers/bulk-get.spec.js @@ -504,7 +504,7 @@ describe('bulk-get handler', () => { if (result.results) { chai.expect(result.results.length).to.equal(0); } else { - chai.expect(result.responseBody).to.equal('Server error'); + chai.expect(result.body).to.equal('Server error'); } }); }); diff --git a/tests/integration/api/controllers/changes.spec.js b/tests/integration/api/controllers/changes.spec.js index 9daab7da414..1c6d2791c32 100644 --- a/tests/integration/api/controllers/changes.spec.js +++ b/tests/integration/api/controllers/changes.spec.js @@ -214,8 +214,8 @@ describe('changes handler', () => { }) .then(response => { expect(response.headers).to.be.ok; - expect(response.headers['content-type']).to.equal('application/json'); - expect(response.headers.server).to.be.ok; + expect(response.headers.get('content-type')).to.equal('application/json'); + expect(response.headers.get('server')).to.be.ok; }); }); }); @@ -316,7 +316,7 @@ describe('changes handler', () => { if (result.results) { return assertChangeIds(result, ...changesIDs, bobUserId); } - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.body.error).to.equal('forbidden'); }); }); }); diff --git a/tests/integration/api/controllers/contacts-by-phone.spec.js b/tests/integration/api/controllers/contacts-by-phone.spec.js index 286f3c9e616..3ead3ec99c3 100644 --- a/tests/integration/api/controllers/contacts-by-phone.spec.js +++ b/tests/integration/api/controllers/contacts-by-phone.spec.js @@ -185,8 +185,8 @@ describe('Contacts by phone API', () => { .request(noAuthRequestOptions) .then(() => chai.assert.fail('Should not allow unauthenticated requests')) .catch(err => { - chai.expect(err.statusCode).to.equal(401); - chai.expect(err.error).to.deep.include({ code: 401, error: 'unauthorized' }); + chai.expect(err.status).to.equal(401); + chai.expect(err.body).to.deep.include({ code: 401, error: 'unauthorized' }); }); }); @@ -197,8 +197,8 @@ describe('Contacts by phone API', () => { .request(noAuthRequestOptions) .then(() => chai.assert.fail('Should not allow unauthenticated requests')) .catch(err => { - chai.expect(err.statusCode).to.equal(401); - chai.expect(err.error).to.deep.include({ code: 401, error: 'unauthorized' }); + chai.expect(err.status).to.equal(401); + chai.expect(err.body).to.deep.include({ code: 401, error: 'unauthorized' }); }); }); }); @@ -210,8 +210,8 @@ describe('Contacts by phone API', () => { .request(offlineRequestOptions) .then(() => chai.assert.fail('Should not allow offline users')) .catch(err => { - chai.expect(err.statusCode).to.equal(403); - chai.expect(err.error).to.deep.include({ code: 403, error: 'forbidden' }); + chai.expect(err.status).to.equal(403); + chai.expect(err.body).to.deep.include({ code: 403, error: 'forbidden' }); }); }); @@ -222,8 +222,8 @@ describe('Contacts by phone API', () => { .request(offlineRequestOptions) .then(() => chai.assert.fail('Should not allow offline users')) .catch(err => { - chai.expect(err.statusCode).to.equal(403); - chai.expect(err.error).to.deep.include({ code: 403, error: 'forbidden' }); + chai.expect(err.status).to.equal(403); + chai.expect(err.body).to.deep.include({ code: 403, error: 'forbidden' }); }); }); }); @@ -234,8 +234,8 @@ describe('Contacts by phone API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`phone` parameter is required and must be a valid phone number' }); @@ -248,8 +248,8 @@ describe('Contacts by phone API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`phone` parameter is required and must be a valid phone number' }); @@ -284,7 +284,7 @@ describe('Contacts by phone API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should 404 when not found')) .catch(result => { - chai.expect(result.error).to.deep.equal({ error: 'not_found', reason: 'no matches found' }); + chai.expect(result.body).to.deep.equal({ error: 'not_found', reason: 'no matches found' }); }); }); @@ -309,8 +309,8 @@ describe('Contacts by phone API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`phone` parameter is required and must be a valid phone number' }); @@ -323,8 +323,8 @@ describe('Contacts by phone API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail with incorrect params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`phone` parameter is required and must be a valid phone number' }); @@ -369,7 +369,7 @@ describe('Contacts by phone API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should 404 when not found')) .catch(result => { - chai.expect(result.error).to.deep.equal({ error: 'not_found', reason: 'no matches found' }); + chai.expect(result.body).to.deep.equal({ error: 'not_found', reason: 'no matches found' }); }); }); diff --git a/tests/integration/api/controllers/db-doc.spec.js b/tests/integration/api/controllers/db-doc.spec.js index 45b042fd03e..28bb8bca911 100644 --- a/tests/integration/api/controllers/db-doc.spec.js +++ b/tests/integration/api/controllers/db-doc.spec.js @@ -273,7 +273,7 @@ describe('db-doc handler', () => { return utils.getDoc('db_doc_delete'); }) .catch(err => { - chai.expect(err.responseBody.error).to.equal('not_found'); + chai.expect(err.body.error).to.equal('not_found'); }); }); @@ -344,10 +344,10 @@ describe('db-doc handler', () => { chai.expect(results[3]) .to.deep.include(patients.find(patient => patient._id === 'fixture:offline:clinic:patient')); - chai.expect(results[4]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[5]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[6]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[7]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[4]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[5]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[6]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[7]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -422,7 +422,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -456,7 +456,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -496,7 +496,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -655,7 +655,7 @@ describe('db-doc handler', () => { if (patientsToDelete[idx]._id.startsWith('temp:offline')) { chai.expect(result).to.deep.include(patientsToDelete[idx]); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }) @@ -668,7 +668,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc, idx); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}, idx); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}, idx); } }); }) @@ -683,7 +683,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc, idx); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}, idx); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}, idx); } }); }) @@ -700,7 +700,7 @@ describe('db-doc handler', () => { chai.expect(result).to.deep.include(reportScenarios[idx].doc); chai.expect(result._deleted).to.equal(true); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -776,7 +776,7 @@ describe('db-doc handler', () => { .then(results => { // cannot read patients results.forEach(result => { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }) .then(() => Promise.all(reportScenarios.map(scenario => utils.requestOnTestDb( @@ -788,7 +788,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }) @@ -801,7 +801,7 @@ describe('db-doc handler', () => { .then(results => { // cannot read deleted patients results.forEach(result => { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }) .then(() => Promise.all(reportScenarios.map(scenario => utils.requestOnTestDb( @@ -813,7 +813,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}, idx); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}, idx); } }); }) @@ -828,7 +828,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include(reportScenarios[idx].doc); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }) @@ -845,7 +845,7 @@ describe('db-doc handler', () => { chai.expect(result).to.deep.include(reportScenarios[idx].doc); chai.expect(result._deleted).to.equal(true); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1024,9 +1024,9 @@ describe('db-doc handler', () => { chai.expect(results[2]._revs_info.length).to.deep.equal(results[2]._revisions.ids.length); chai.expect(results[2]._revs_info[0]).to.deep.equal({ rev: revs.allowed_attach[1], status: 'available' }); - chai.expect(results[3].statusCode).to.deep.equal(403); - chai.expect(results[4].statusCode).to.deep.equal(403); - chai.expect(results[5].statusCode).to.deep.equal(403); + chai.expect(results[3].status).to.deep.equal(403); + chai.expect(results[4].status).to.deep.equal(403); + chai.expect(results[5].status).to.deep.equal(403); }); }); @@ -1076,9 +1076,9 @@ describe('db-doc handler', () => { ])) .then(results => { chai.expect(results[0]).to.deep.include(allowedTask); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); chai.expect(results[2]).to.deep.include(allowedTarget); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }) .then(() => Promise.all([ utils.requestOnTestDb(_.defaults({ path: '/fixture:user:offline' }, supervisorRequestOptions)), @@ -1097,13 +1097,13 @@ describe('db-doc handler', () => { // supervisor can see the user's contact chai.expect(results[0]._id).to.equal('fixture:user:offline'); // supervisor can't see the user's user-settings document - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); // supervisor has replication depth of 2 - chai.expect(results[2]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[2]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); // supervisor can't see the any user's tasks - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[4]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[4]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); // supervisor can see both targets chai.expect(results[5]).to.deep.include(allowedTarget); @@ -1137,7 +1137,7 @@ describe('db-doc handler', () => { .then(() => utils.requestOnTestDb(_.defaults({ path: `/${doc._id}` }, offlineRequestOptions)).catch(err => err)) .then(result => { // user can't see the unallocated report without permissions - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }) .then(() => utils.updateSettings(settings, { ignoreReload: true })) .then(() => utils.requestOnTestDb(_.defaults({ path: `/${doc._id}` }, offlineRequestOptions)).catch(err => err)) @@ -1253,7 +1253,7 @@ describe('db-doc handler', () => { chai.expect(result).excluding('_rev').to.deep.equal(originalDoc); } else { // a private report, expect an error - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1282,8 +1282,8 @@ describe('db-doc handler', () => { ]) .then(([allowed, denied, forbidden]) => { chai.expect(allowed).to.include({ id: 'allowed_doc_post', ok: true, }); - chai.expect(denied).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(forbidden).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(denied).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(forbidden).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); return Promise.all([ utils.getDoc('allowed_doc_post'), @@ -1292,7 +1292,7 @@ describe('db-doc handler', () => { }) .then(([allowed, denied]) => { chai.expect(allowed).to.deep.include(allowedDoc); - chai.expect(denied.statusCode).to.deep.equal(404); + chai.expect(denied.status).to.deep.equal(404); const ids = ['allowed_doc_post', 'denied_doc_post']; return sentinelUtils.waitForSentinel(ids).then(() => sentinelUtils.getInfoDocs(ids)); @@ -1385,7 +1385,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include({ ok: true, id: reportScenarios[idx].doc._id }); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1419,7 +1419,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include({ ok: true, id: reportScenarios[idx].doc._id }); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1469,9 +1469,9 @@ describe('db-doc handler', () => { ]) .then(results => { chai.expect(results[0]).to.deep.include({ ok: true, id: 'task1' }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); chai.expect(results[2]).to.deep.include({ ok: true, id: 'target1' }); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -1534,12 +1534,12 @@ describe('db-doc handler', () => { }) .then(results => { chai.expect(results[0]).to.include({ ok: true, id: 'n_put_1' }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); chai.expect(results[2]).to.include({ ok: true, id: 'a_put_1', }); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[4]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[5]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[4]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[5]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); const ids = ['a_put_1', 'a_put_2', 'd_put_1', 'd_put_2', 'n_put_1', 'n_put_2']; @@ -1607,10 +1607,10 @@ describe('db-doc handler', () => { .catch(err => err))); }) .then(results => { - chai.expect(results[0]).to.deep.nested.include({ statusCode: 409, 'responseBody.error': 'conflict'}); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[2]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 409, 'responseBody.error': 'conflict'}); + chai.expect(results[0]).to.deep.nested.include({ status: 409, 'body.error': 'conflict'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[2]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 409, 'body.error': 'conflict'}); }); }); @@ -1685,7 +1685,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include({ ok: true, id: reportScenarios[idx].doc._id }); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1719,7 +1719,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include({ ok: true, id: reportScenarios[idx].doc._id }); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1758,7 +1758,7 @@ describe('db-doc handler', () => { if (reportScenarios[idx].allowed) { chai.expect(result).to.deep.include({ ok: true, id: reportScenarios[idx].doc._id }); } else { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); } }); }); @@ -1812,9 +1812,9 @@ describe('db-doc handler', () => { }) .then(results => { chai.expect(results[0]).to.deep.include({ ok: true, id: 'task1' }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); chai.expect(results[2]).to.deep.include({ ok: true, id: 'target1' }); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -1843,7 +1843,7 @@ describe('db-doc handler', () => { ])) .then(results => { chai.expect(results[0]).to.deep.include({ id: 'allowed_del', ok: true }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); return Promise.all([ utils.getDoc('allowed_del').catch(err => err), @@ -1852,7 +1852,7 @@ describe('db-doc handler', () => { }) .then(results => { chai.expect(results[0]).to.deep.include({ - statusCode: 404, responseBody: { error: 'not_found', reason: 'deleted' } + status: 404, body: { error: 'not_found', reason: 'deleted' } }); chai.expect(results[1]).to.deep.include({ _id: 'denied_del', @@ -1915,10 +1915,10 @@ describe('db-doc handler', () => { .then(results => { chai.expect(results[0]).to.equal('my attachment content'); chai.expect(results[1]).to.deep.include( - { statusCode: 404, responseBody: { error: 'bad_request', reason: 'Invalid rev format' }} + { status: 404, body: { error: 'bad_request', reason: 'Invalid rev format' }} ); chai.expect(results[2]).to.deep.include( - { statusCode: 403, responseBody: { error: 'forbidden', reason: 'Insufficient privileges' }} + { status: 403, body: { error: 'forbidden', reason: 'Insufficient privileges' }} ); return Promise.all([ @@ -1945,19 +1945,19 @@ describe('db-doc handler', () => { }) .then(results => { // allowed_attach is allowed, but missing attachment - chai.expect(results[0].responseBody).to.deep.equal({ + chai.expect(results[0].body).to.deep.equal({ error: 'not_found', reason: 'Document is missing attachment', }); // allowed_attach is allowed and has attachment chai.expect(results[1]).to.equal('my attachment content'); // allowed_attach is not allowed and has attachment - chai.expect(results[2].responseBody.error).to.equal('forbidden'); + chai.expect(results[2].body.error).to.equal('forbidden'); // denied_attach is not allowed, but missing attachment - chai.expect(results[3].responseBody.error).to.equal('forbidden'); + chai.expect(results[3].body.error).to.equal('forbidden'); // denied_attach is not allowed and has attachment - chai.expect(results[4].responseBody.error).to.equal('forbidden'); + chai.expect(results[4].body.error).to.equal('forbidden'); // denied_attach is allowed and has attachment chai.expect(results[5]).to.equal('my attachment content'); @@ -1987,9 +1987,9 @@ describe('db-doc handler', () => { ]); }) .then(results => { - chai.expect(results[0]).to.deep.nested.include({ statusCode: 404, 'responseBody.error': 'bad_request' }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[2]).to.deep.nested.include({ statusCode: 404, 'responseBody.error': 'bad_request' }); + chai.expect(results[0]).to.deep.nested.include({ status: 404, 'body.error': 'bad_request' }); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[2]).to.deep.nested.include({ status: 404, 'body.error': 'bad_request' }); chai.expect(results[3]).to.equal('my attachment content'); }); }); @@ -2050,8 +2050,8 @@ describe('db-doc handler', () => { chai.expect(results[0]).to.equal('my attachment content'); chai.expect(results[1]).to.equal('my attachment content'); - chai.expect(results[2]).to.deep.nested.include({ statusCode: 404, 'responseBody.error': 'bad_request' }); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[2]).to.deep.nested.include({ status: 404, 'body.error': 'bad_request' }); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); return Promise.all([ utils.getDoc('allowed_attach_1'), @@ -2078,18 +2078,18 @@ describe('db-doc handler', () => { }) .then(results => { // allowed_attach is allowed, but missing attachment - chai.expect(results[0].responseBody).to.deep.equal({ + chai.expect(results[0].body).to.deep.equal({ error: 'not_found', reason: 'Document is missing attachment', }); // allowed_attach is allowed and has attachment chai.expect(results[1]).to.equal('my attachment content'); // allowed_attach is not allowed and has attachment - chai.expect(results[2].responseBody.error).to.equal('forbidden'); + chai.expect(results[2].body.error).to.equal('forbidden'); // denied_attach is not allowed, but missing attachment - chai.expect(results[3].responseBody.error).to.equal('forbidden'); + chai.expect(results[3].body.error).to.equal('forbidden'); // denied_attach is not allowed and has attachment - chai.expect(results[4].responseBody.error).to.equal('forbidden'); + chai.expect(results[4].body.error).to.equal('forbidden'); // denied_attach is allowed and has attachment chai.expect(results[5]).to.equal('my attachment content'); }); @@ -2127,7 +2127,7 @@ describe('db-doc handler', () => { )) .then(results => { chai.expect(results[0]).to.deep.include({ ok: true, id: 'a_with_attachments' }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); return Promise.all([ utils.requestOnTestDb({ path: '/a_with_attachments' }), @@ -2145,7 +2145,7 @@ describe('db-doc handler', () => { chai.expect(results[2]._attachments).to.be.undefined; chai.expect(results[2]._id).to.equal('d_with_attachments'); - chai.expect(results[3].responseBody.error).to.equal('not_found'); + chai.expect(results[3].body.error).to.equal('not_found'); }); }); }); @@ -2164,7 +2164,7 @@ describe('db-doc handler', () => { type: 'person', parent: { _id: 'fixture:offline', parent: { _id: 'PARENT_PLACE' } }, }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -2218,11 +2218,11 @@ describe('db-doc handler', () => { }) .then(results => { chai.expect(results[0]).to.deep.include({ ok: true, id: 'n_put_1' }); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); chai.expect(results[2]).to.deep.include({ ok: true, id: 'a_put_1' }); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[4]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[5]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[4]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[5]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -2306,7 +2306,7 @@ describe('db-doc handler', () => { .catch(err => err), ])) .then(results => { - chai.expect(results.every(result => result.statusCode === 403 || result.statusCode === 404)).to.equal(true); + chai.expect(results.every(result => result.status === 403 || result.status === 404)).to.equal(true); }); }); @@ -2347,7 +2347,7 @@ describe('db-doc handler', () => { return utils.requestOnTestDb(offlineRequestOptions).catch(err => err); }) .then(result => { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); return utils.getDoc('fb1'); }) .then(result => { @@ -2368,9 +2368,9 @@ describe('db-doc handler', () => { .then(results => { chai.expect(results[0]._id).to.equal('_design/medic-client'); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[2]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[2]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -2392,10 +2392,10 @@ describe('db-doc handler', () => { .catch(err => err), ]) .then(results => { - chai.expect(results[0]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[1]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[2]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); - chai.expect(results[3]).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(results[0]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[1]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[2]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); + chai.expect(results[3]).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); @@ -2425,7 +2425,7 @@ describe('db-doc handler', () => { ]) .then(results => { results.forEach(result => { - chai.expect(result).to.deep.nested.include({ statusCode: 403, 'responseBody.error': 'forbidden'}); + chai.expect(result).to.deep.nested.include({ status: 403, 'body.error': 'forbidden'}); }); }); }); diff --git a/tests/integration/api/controllers/hydration.spec.js b/tests/integration/api/controllers/hydration.spec.js index df74fee36da..a32e9668a40 100644 --- a/tests/integration/api/controllers/hydration.spec.js +++ b/tests/integration/api/controllers/hydration.spec.js @@ -269,8 +269,8 @@ describe('Hydration API', () => { .request(noAuthRequestOptions) .then(() => chai.assert.fail('Should not allow unauthenticated requests')) .catch(err => { - chai.expect(err.statusCode).to.equal(401); - chai.expect(err.error).to.deep.include({ code: 401, error: 'unauthorized' }); + chai.expect(err.status).to.equal(401); + chai.expect(err.body).to.deep.include({ code: 401, error: 'unauthorized' }); }); }); @@ -281,8 +281,8 @@ describe('Hydration API', () => { .request(noAuthRequestOptions) .then(() => chai.assert.fail('Should not allow unauthenticated requests')) .catch(err => { - chai.expect(err.statusCode).to.equal(401); - chai.expect(err.error).to.deep.include({ code: 401, error: 'unauthorized' }); + chai.expect(err.status).to.equal(401); + chai.expect(err.body).to.deep.include({ code: 401, error: 'unauthorized' }); }); }); }); @@ -294,8 +294,8 @@ describe('Hydration API', () => { .request(offlineRequestOptions) .then(() => chai.assert.fail('Should not allow offline users')) .catch(err => { - chai.expect(err.statusCode).to.equal(403); - chai.expect(err.error).to.deep.include({ code: 403, error: 'forbidden' }); + chai.expect(err.status).to.equal(403); + chai.expect(err.body).to.deep.include({ code: 403, error: 'forbidden' }); }); }); @@ -306,8 +306,8 @@ describe('Hydration API', () => { .request(offlineRequestOptions) .then(() => chai.assert.fail('Should not allow offline users')) .catch(err => { - chai.expect(err.statusCode).to.equal(403); - chai.expect(err.error).to.deep.include({ code: 403, error: 'forbidden' }); + chai.expect(err.status).to.equal(403); + chai.expect(err.body).to.deep.include({ code: 403, error: 'forbidden' }); }); }); }); @@ -318,8 +318,8 @@ describe('Hydration API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`doc_ids` parameter must be a json array.' }); @@ -332,8 +332,8 @@ describe('Hydration API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`doc_ids` parameter must be a json array.' }); @@ -480,8 +480,8 @@ describe('Hydration API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`doc_ids` parameter must be a json array.' }); @@ -494,8 +494,8 @@ describe('Hydration API', () => { .request(onlineRequestOptions) .then(() => chai.assert.fail('Should fail when no params')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); - chai.expect(err.error).to.deep.equal({ + chai.expect(err.status).to.equal(400); + chai.expect(err.body).to.deep.equal({ error: 'bad_request', reason: '`doc_ids` parameter must be a json array.' }); diff --git a/tests/integration/api/controllers/login.spec.js b/tests/integration/api/controllers/login.spec.js index dc9be54a07e..c14a19c86be 100644 --- a/tests/integration/api/controllers/login.spec.js +++ b/tests/integration/api/controllers/login.spec.js @@ -20,10 +20,10 @@ const loginWithData = data => { const opts = { path: '/medic/login?aaa=aaa', method: 'POST', - simple: false, + resolveWithFullResponse: true, noAuth: true, body: data, - followRedirect: false, + redirect: 'manual', headers: { 'X-Forwarded-For': randomIp() }, }; return utils.request(opts); @@ -33,10 +33,9 @@ const loginWithTokenLink = (token = '') => { const opts = { path: `/medic/login/token/${token}`, method: 'POST', - simple: false, resolveWithFullResponse: true, noAuth: true, - followRedirect: false, + redirect: 'manual', body: {}, headers: { 'X-Forwarded-For': randomIp() }, }; @@ -44,16 +43,16 @@ const loginWithTokenLink = (token = '') => { }; const expectLoginToWork = (response) => { - chai.expect(response).to.include({ statusCode: 302 }); - chai.expect(response.headers['set-cookie']).to.be.an('array'); - chai.expect(response.headers['set-cookie'].find(cookie => cookie.startsWith('AuthSession'))).to.be.ok; - chai.expect(response.headers['set-cookie'].find(cookie => cookie.startsWith('userCtx'))).to.be.ok; + chai.expect(response).to.include({ status: 302 }); + chai.expect(response.headers.getSetCookie()).to.be.an('array'); + chai.expect(response.headers.getSetCookie().find(cookie => cookie.startsWith('AuthSession'))).to.be.ok; + chai.expect(response.headers.getSetCookie().find(cookie => cookie.startsWith('userCtx'))).to.be.ok; chai.expect(response.body).to.equal('/'); }; const expectLoginToFail = (response) => { - chai.expect(response.headers['set-cookie']).to.be.undefined; - chai.expect(response.statusCode).to.equal(401); + chai.expect(response.headers.getSetCookie()).to.deep.equal([]); + chai.expect(response.status).to.equal(401); }; const getUser = (user) => { @@ -135,7 +134,7 @@ describe('login', () => { it('should fail with invalid url', () => { return setupTokenLoginSettings() .then(() => loginWithTokenLink()) - .then(response => chai.expect(response).to.deep.include({ statusCode: 401 })); + .then(response => chai.expect(response).to.deep.include({ status: 401 })); }); it('should fail with invalid data', () => { diff --git a/tests/integration/api/controllers/person.spec.js b/tests/integration/api/controllers/person.spec.js index d35b93d179d..fa21dc6f22e 100644 --- a/tests/integration/api/controllers/person.spec.js +++ b/tests/integration/api/controllers/person.spec.js @@ -1,8 +1,6 @@ const utils = require('@utils'); const placeFactory = require('@factories/cht/contacts/place'); const personFactory = require('@factories/cht/contacts/person'); -const { getRemoteDataContext, Person, Qualifier } = require('@medic/cht-datasource'); -const { expect } = require('chai'); const userFactory = require('@factories/cht/users/users'); describe('Person API', () => { @@ -47,7 +45,6 @@ describe('Person API', () => { roles: ['chw'] })); const allDocItems = [contact0, contact1, contact2, place0, place1, place2, patient]; - const dataContext = getRemoteDataContext(utils.getOrigin()); const personType = 'person'; const e2eTestUser = { '_id': 'e2e_contact_test_id', @@ -96,16 +93,13 @@ describe('Person API', () => { }); describe('GET /api/v1/person/:uuid', async () => { - const getPerson = Person.v1.get(dataContext); - const getPersonWithLineage = Person.v1.getWithLineage(dataContext); - it('returns the person matching the provided UUID', async () => { - const person = await getPerson(Qualifier.byUuid(patient._id)); + const person = await utils.request(`/api/v1/person/${patient._id}`); expect(person).excluding(['_rev', 'reported_date']).to.deep.equal(patient); }); it('returns the person with lineage when the withLineage query parameter is provided', async () => { - const person = await getPersonWithLineage(Qualifier.byUuid(patient._id)); + const person = await utils.request({ path: `/api/v1/person/${patient._id}`, qs: { with_lineage: true } }); expect(person).excludingEvery(['_rev', 'reported_date']).to.deep.equal({ ...patient, parent: { @@ -124,8 +118,8 @@ describe('Person API', () => { }); it('returns null when no person is found for the UUID', async () => { - const person = await getPerson(Qualifier.byUuid('invalid-uuid')); - expect(person).to.be.null; + await expect(utils.request('/api/v1/person/invalid-uuid')) + .to.be.rejectedWith('404 - {"code":404,"error":"Person not found"}'); }); [ @@ -143,13 +137,11 @@ describe('Person API', () => { }); describe('GET /api/v1/person', async () => { - const getPage = Person.v1.getPage(dataContext); const limit = 4; - const cursor = null; const invalidContactType = 'invalidPerson'; it('returns a page of people for no limit and cursor passed', async () => { - const responsePage = await getPage(Qualifier.byContactType(personType)); + const responsePage = await utils.request({ path: `/api/v1/person`, qs: { type: personType } }); const responsePeople = responsePage.data; const responseCursor = responsePage.cursor; @@ -158,8 +150,11 @@ describe('Person API', () => { }); it('returns a page of people when limit and cursor is passed and cursor can be reused', async () => { - const firstPage = await getPage(Qualifier.byContactType(personType), cursor, limit); - const secondPage = await getPage(Qualifier.byContactType(personType), firstPage.cursor, limit); + const firstPage = await utils.request({ path: `/api/v1/person`, qs: { type: personType, limit } }); + const secondPage = await utils.request({ + path: `/api/v1/person`, + qs: { type: personType, cursor: firstPage.cursor, limit } + }); const allPeople = [...firstPage.data, ...secondPage.data]; @@ -230,17 +225,18 @@ describe('Person API', () => { }); }); - describe('Person.v1.getAll', async () => { - it('fetches all data by iterating through generator', async () => { - const docs = []; - - const generator = Person.v1.getAll(dataContext)(Qualifier.byContactType(personType)); - - for await (const doc of generator) { - docs.push(doc); - } - - expect(docs).excluding(['_rev', 'reported_date']).to.deep.equalInAnyOrder(expectedPeople); - }); - }); + // todo rethink this once datasource works with authentication #9701 + // describe('Person.v1.getAll', async () => { + // it('fetches all data by iterating through generator', async () => { + // const docs = []; + // + // const generator = Person.v1.getAll(dataContext)(Qualifier.byContactType(personType)); + // + // for await (const doc of generator) { + // docs.push(doc); + // } + // + // expect(docs).excluding(['_rev', 'reported_date']).to.deep.equalInAnyOrder(expectedPeople); + // }); + // }); }); diff --git a/tests/integration/api/controllers/place.spec.js b/tests/integration/api/controllers/place.spec.js index d80ed338461..962144d403f 100644 --- a/tests/integration/api/controllers/place.spec.js +++ b/tests/integration/api/controllers/place.spec.js @@ -1,8 +1,6 @@ const utils = require('@utils'); const placeFactory = require('@factories/cht/contacts/place'); const personFactory = require('@factories/cht/contacts/person'); -const { getRemoteDataContext, Place, Qualifier } = require('@medic/cht-datasource'); -const { expect } = require('chai'); const userFactory = require('@factories/cht/users/users'); describe('Place API', () => { @@ -62,7 +60,6 @@ describe('Place API', () => { }, roles: ['chw'] })); - const dataContext = getRemoteDataContext(utils.getOrigin()); const expectedPlaces = [place0, clinic1, clinic2]; before(async () => { @@ -76,16 +73,13 @@ describe('Place API', () => { }); describe('GET /api/v1/place/:uuid', async () => { - const getPlace = Place.v1.get(dataContext); - const getPlaceWithLineage = Place.v1.getWithLineage(dataContext); - it('returns the place matching the provided UUID', async () => { - const place = await getPlace(Qualifier.byUuid(place0._id)); + const place = await utils.request(`/api/v1/place/${place0._id}`); expect(place).excluding(['_rev', 'reported_date']).to.deep.equal(place0); }); it('returns the place with lineage when the withLineage query parameter is provided', async () => { - const place = await getPlaceWithLineage(Qualifier.byUuid(place0._id)); + const place = await utils.request({ path: `/api/v1/place/${place0._id}`, qs: { with_lineage: true } }); expect(place).excludingEvery(['_rev', 'reported_date']).to.deep.equal({ ...place0, contact: contact0, @@ -101,8 +95,8 @@ describe('Place API', () => { }); it('returns null when no place is found for the UUID', async () => { - const place = await getPlace(Qualifier.byUuid('invalid-uuid')); - expect(place).to.be.null; + await expect(utils.request('/api/v1/place/invalid-uuid')) + .to.be.rejectedWith('404 - {"code":404,"error":"Place not found"}'); }); [ @@ -120,13 +114,11 @@ describe('Place API', () => { }); describe('GET /api/v1/place', async () => { - const getPage = Place.v1.getPage(dataContext); const limit = 2; - const cursor = null; const invalidContactType = 'invalidPlace'; it('returns a page of places for no limit and cursor passed', async () => { - const responsePage = await getPage(Qualifier.byContactType(placeType)); + const responsePage = await utils.request({ path: `/api/v1/place`, qs: { type: placeType } }); const responsePlaces = responsePage.data; const responseCursor = responsePage.cursor; @@ -136,8 +128,11 @@ describe('Place API', () => { }); it('returns a page of places when limit and cursor is passed and cursor can be reused', async () => { - const firstPage = await getPage(Qualifier.byContactType(placeType), cursor, limit); - const secondPage = await getPage(Qualifier.byContactType(placeType), firstPage.cursor, limit); + const firstPage = await utils.request({ path: `/api/v1/place`, qs: { type: placeType, limit } }); + const secondPage = await utils.request({ + path: `/api/v1/place`, + qs: { type: placeType, cursor: firstPage.cursor, limit } + }); const allPeople = [...firstPage.data, ...secondPage.data]; @@ -208,17 +203,18 @@ describe('Place API', () => { }); }); - describe('Place.v1.getAll', async () => { - it('fetches all data by iterating through generator', async () => { - const docs = []; - - const generator = Place.v1.getAll(dataContext)(Qualifier.byContactType(placeType)); - - for await (const doc of generator) { - docs.push(doc); - } - - expect(docs).excluding(['_rev', 'reported_date']).to.deep.equalInAnyOrder(expectedPlaces); - }); - }); + // todo rethink this once datasource works with authentication #9701 + // describe('Place.v1.getAll', async () => { + // it('fetches all data by iterating through generator', async () => { + // const docs = []; + // + // const generator = Place.v1.getAll(dataContext)(Qualifier.byContactType(placeType)); + // + // for await (const doc of generator) { + // docs.push(doc); + // } + // + // expect(docs).excluding(['_rev', 'reported_date']).to.deep.equalInAnyOrder(expectedPlaces); + // }); + // }); }); diff --git a/tests/integration/api/controllers/places.spec.js b/tests/integration/api/controllers/places.spec.js index 3d0862b4ef6..d607da09363 100644 --- a/tests/integration/api/controllers/places.spec.js +++ b/tests/integration/api/controllers/places.spec.js @@ -205,7 +205,7 @@ describe('Places API', () => { return utils.request(onlineRequestOptions) .then(() => fail('Call should fail as contact type is not a person')) .catch(err => { - chai.expect(err.responseBody.error).to.equal('Wrong type, this is not a person.'); + chai.expect(err.body.error).to.equal('Wrong type, this is not a person.'); }); }); @@ -220,7 +220,7 @@ describe('Places API', () => { return utils.request(onlineRequestOptions) .then(() => fail('Call should fail as contact does not exist')) .catch(err => { - chai.expect(err.responseBody.error).to.equal('Failed to find person.'); + chai.expect(err.body.error).to.equal('Failed to find person.'); }); }); diff --git a/tests/integration/api/controllers/records.spec.js b/tests/integration/api/controllers/records.spec.js index 97c2434cee5..bcea32cfd9a 100644 --- a/tests/integration/api/controllers/records.spec.js +++ b/tests/integration/api/controllers/records.spec.js @@ -46,9 +46,6 @@ describe('Import Records', () => { .then(() => utils.request({ method: 'POST', path: '/api/v2/records', - headers: { - 'Content-type': 'application/json' - }, body: { _meta: { form: 'TEST', @@ -94,9 +91,6 @@ describe('Import Records', () => { .then(() => utils.request({ method: 'POST', path: '/api/v2/records', - headers: { - 'Content-type': 'application/json' - }, body: { _meta: { form: 'TEST' @@ -134,9 +128,6 @@ describe('Import Records', () => { .then(() => utils.request({ method: 'POST', path: '/api/v2/records', - headers: { - 'Content-type': 'application/json' - }, body: { _meta: { form: 'TEST', diff --git a/tests/integration/api/controllers/settings.spec.js b/tests/integration/api/controllers/settings.spec.js index c4bda666dc9..643a2ba01a9 100644 --- a/tests/integration/api/controllers/settings.spec.js +++ b/tests/integration/api/controllers/settings.spec.js @@ -29,7 +29,6 @@ describe('Settings API', () => { path: uri, method: 'PUT', body: updates, - headers: { 'Content-Type': 'application/json' } }); }; @@ -124,7 +123,6 @@ describe('Settings API', () => { path: '/api/v1/settings', method: 'PUT', body: updates, - headers: { 'Content-Type': 'application/json' }, qs, }); }; diff --git a/tests/integration/api/controllers/users.spec.js b/tests/integration/api/controllers/users.spec.js index cea1f61b179..a129526f3ab 100644 --- a/tests/integration/api/controllers/users.spec.js +++ b/tests/integration/api/controllers/users.spec.js @@ -1,10 +1,6 @@ -const constants = require('@constants'); -const https = require('https'); const utils = require('@utils'); const uuid = require('uuid').v4; const querystring = require('querystring'); -const chai = require('chai'); -chai.use(require('chai-shallow-deep-equal')); const sentinelUtils = require('@utils/sentinel'); const placeFactory = require('@factories/cht/contacts/place'); const personFactory = require('@factories/cht/contacts/person'); @@ -29,10 +25,10 @@ describe('Users API', () => { const opts = { path: '/login', method: 'POST', - simple: false, + resolveWithFullResponse: true, noAuth: true, body: { user: user.username, password: user.password }, - followRedirect: false, + redirect: 'manual', headers: { 'X-Forwarded-For': randomIp() }, }; @@ -40,12 +36,12 @@ describe('Users API', () => { .requestOnMedicDb(opts) .then(response => { chai.expect(response).to.include({ - statusCode: 302, + status: 302, body: '/', }); - chai.expect(response.headers['set-cookie']).to.be.an('array'); - chai.expect(response.headers['set-cookie'].find(cookie => cookie.startsWith('AuthSession'))).to.be.ok; - chai.expect(response.headers['set-cookie'].find(cookie => cookie.startsWith('userCtx'))).to.be.ok; + chai.expect(response.headers.getSetCookie()).to.be.an('array'); + chai.expect(response.headers.getSetCookie().find(cookie => cookie.startsWith('AuthSession'))).to.be.ok; + chai.expect(response.headers.getSetCookie().find(cookie => cookie.startsWith('userCtx'))).to.be.ok; }); }; @@ -53,7 +49,7 @@ describe('Users API', () => { const opts = { path: '/login', method: 'POST', - simple: false, + resolveWithFullResponse: true, noAuth: true, body: { user: user.username, password: user.password }, headers: { 'X-Forwarded-For': randomIp() }, @@ -62,7 +58,7 @@ describe('Users API', () => { return utils .requestOnMedicDb(opts) .then(response => { - chai.expect(response).to.deep.include({ statusCode: 401, body: { error: 'Not logged in' } }); + chai.expect(response).to.deep.include({ status: 401, body: { error: 'Not logged in' } }); }); }; @@ -119,61 +115,33 @@ describe('Users API', () => { await utils.request({ path: '/_users', method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, body: _usersUser }); await utils.saveDocs(medicData); - return new Promise((resolve, reject) => { - const options = { - hostname: constants.API_HOST, - path: '/_session', - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - auth: `${username}:${password}` - }; - - // Use http service to extract cookie - const req = https.request(options, res => { - if (res.statusCode !== 200) { - return reject(new Error(`Expected 200 from _session authing, but got ${res.statusCode}`)); - } - - // Example header: - // AuthSession=cm9vdDo1MEJDMDEzRTp7Vu5GKCkTxTVxwXbpXsBARQWnhQ; Version=1; Path=/; HttpOnly - try { - cookie = res.headers['set-cookie'][0].match(/^(AuthSession=[^;]+)/)[0]; - } catch (err) { - return reject(err); - } - - resolve(cookie); - }); - - req.write(JSON.stringify({ + const res = await utils.request({ + path: '/_session', + auth: { username, password }, + method: 'POST', + resolveWithFullResponse: true, + body: { name: username, password: password - })); - req.end(); + } }); + if (!res.ok) { + throw new Error(`Expected 200 from _session authing, but got ${res.status}`); + } + + cookie = res.headers.getSetCookie().find(cookie => cookie.startsWith('AuthSession')); + if (!cookie) { + throw new Error('Expected auth cookie from _session authing'); + } }); after(async () => { - const { _rev } = await utils.request(`/_users/${getUserId(username)}`); - await utils.request({ - path: `/_users/${getUserId(username)}`, - method: 'PUT', - body: { - _id: getUserId(username), - _rev, - _deleted: true, - } - }); + await utils.deleteUsers([{ username }]); await utils.revertSettings(true); await utils.revertDb([], true); }); @@ -214,7 +182,7 @@ describe('Users API', () => { }) .then(() => fail('You should get a 401 in this situation')) .catch(err => { - chai.expect(err.responseBody.error).to.equal('You do not have permissions to modify this person'); + chai.expect(err.body.error).to.equal('You do not have permissions to modify this person'); }); }); @@ -230,7 +198,7 @@ describe('Users API', () => { }) .then(() => fail('You should get an error in this situation')) .catch(err => { - chai.expect(err.responseBody.error).to.equal('unauthorized'); + chai.expect(err.body.error).to.equal('unauthorized'); }); }); @@ -268,7 +236,7 @@ describe('Users API', () => { }) .then(() => fail('You should get an error in this situation')) .catch(err => { - chai.expect(err.responseBody.error).to.equal('You must authenticate with Basic Auth to modify your password'); + chai.expect(err.body.error).to.equal('You must authenticate with Basic Auth to modify your password'); }); }); @@ -516,7 +484,7 @@ describe('Users API', () => { .then(() => chai.expect.fail('should have thrown')) .catch(err => { // online users require the "can_update_users" permission to be able to access this endpoint - chai.expect(err.error).to.deep.equal({ + chai.expect(err.body).to.deep.equal({ code: 403, error: 'Insufficient privileges', }); @@ -535,7 +503,7 @@ describe('Users API', () => { .then(() => chai.expect.fail('should have thrown')) .catch(err => { // online users require the "can_update_users" permission to be able to access this endpoint - chai.expect(err.error).to.deep.equal({ + chai.expect(err.body).to.deep.equal({ code: 403, error: 'Insufficient privileges', }); @@ -580,12 +548,11 @@ describe('Users API', () => { facility_id: 'fixture:offline' }; onlineRequestOptions.path += '?' + querystring.stringify(params); - onlineRequestOptions.headers = { 'Content-Type': 'application/json' }; return utils .request(onlineRequestOptions) .then(resp => chai.expect(resp).to.equal('should have thrown')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); + chai.expect(err.status).to.equal(400); }); }); @@ -599,7 +566,7 @@ describe('Users API', () => { .request(onlineRequestOptions) .then(resp => chai.expect(resp).to.equal('should have thrown')) .catch(err => { - chai.expect(err.statusCode).to.equal(400); + chai.expect(err.status).to.equal(400); }); }); @@ -609,7 +576,6 @@ describe('Users API', () => { facility_id: 'IdonTExist' }; onlineRequestOptions.path += '?' + querystring.stringify(params); - onlineRequestOptions.headers = { 'Content-Type': 'application/json' }; return utils .request(onlineRequestOptions) .then(resp => { @@ -682,18 +648,17 @@ describe('Users API', () => { const opts = { uri: url, method: 'POST', - simple: false, resolveWithFullResponse: true, noAuth: true, - followRedirect: false, + redirect: 'manual', body: {}, headers: { 'X-Forwarded-For': randomIp() }, }; return utils.request(opts).then(response => { - chai.expect(response).to.include({ statusCode: 302, body: '/' }); - chai.expect(response.headers['set-cookie']).to.be.an('array'); - chai.expect(response.headers['set-cookie'].find(cookie => cookie.startsWith('AuthSession'))).to.be.ok; - chai.expect(response.headers['set-cookie'].find(cookie => cookie.startsWith('userCtx'))).to.be.ok; + chai.expect(response).to.include({ status: 302, body: '/' }); + chai.expect(response.headers.getSetCookie()).to.be.an('array'); + chai.expect(response.headers.getSetCookie().find(cookie => cookie.startsWith('AuthSession'))).to.be.ok; + chai.expect(response.headers.getSetCookie().find(cookie => cookie.startsWith('userCtx'))).to.be.ok; }); }; @@ -701,16 +666,15 @@ describe('Users API', () => { const opts = { uri: url, method: 'POST', - simple: false, noAuth: true, - followRedirect: false, + redirect: 'manual', resolveWithFullResponse: true, body: {}, headers: { 'X-Forwarded-For': randomIp() }, }; return utils.request(opts).then(response => { - chai.expect(response.headers['set-cookie']).to.be.undefined; - chai.expect(response).to.deep.include({ statusCode: 401, body: { error: expired ? 'expired': 'invalid' } }); + chai.expect(response.headers.getSetCookie()).to.deep.equal([]); + chai.expect(response).to.deep.include({ status: 401, body: { error: expired ? 'expired': 'invalid' } }); }); }; @@ -1253,8 +1217,8 @@ describe('Users API', () => { }) .then(() => chai.assert.fail('should have thrown')) .catch(err => { - chai.expect(err.response).to.shallowDeepEqual({ - statusCode: 400, + chai.expect(err).to.shallowDeepEqual({ + status: 400, body: { code: 400, error: { message: 'Missing required fields: phone' }} }); }); @@ -1273,8 +1237,8 @@ describe('Users API', () => { }) .then(() => chai.assert.fail('should have thrown')) .catch(err => { - chai.expect(err.response).to.shallowDeepEqual({ - statusCode: 400, + chai.expect(err).to.shallowDeepEqual({ + status: 400, body: { code: 400, error: { message: 'Missing required fields: phone' }} }); @@ -1610,7 +1574,7 @@ describe('Users API', () => { chai.expect(tokenLoginDoc.user).to.equal('org.couchdb.user:testuser'); const onlineRequestOpts = { - auth: { user: 'onlineuser', password }, + auth: { username: 'onlineuser', password }, method: 'PUT', path: `/${tokenLoginDoc._id}`, body: tokenLoginDoc, @@ -1618,8 +1582,8 @@ describe('Users API', () => { return utils.requestOnTestDb(onlineRequestOpts).catch(err => err); }) .then(err => { - chai.expect(err.response).to.deep.include({ - statusCode: 403, + chai.expect(err).to.deep.include({ + status: 403, body: { error: 'forbidden', reason: 'Insufficient privileges' @@ -1694,9 +1658,9 @@ describe('Users API', () => { await utils.request({ path: `/api/v2/users/invalidUsername`, }); - } catch ({ error }) { - expect(error.code).to.equal(404); - expect(error.error).to + } catch ({ body }) { + expect(body.code).to.equal(404); + expect(body.error).to .match(/Failed to find user with name \[invalidUsername\] in the \[(users|medic)\] database./); return; } @@ -1710,9 +1674,9 @@ describe('Users API', () => { path: `/api/v2/users/${userProgramOfficer.username}`, auth: { username: user.username, password }, }); - } catch ({ error }) { - expect(error.code).to.equal(403); - expect(error.error).to.equal('Insufficient privileges'); + } catch ({ body }) { + expect(body.code).to.equal(403); + expect(body.error).to.equal('Insufficient privileges'); return; } @@ -2012,8 +1976,8 @@ describe('Users API', () => { await utils.request({ path: '/api/v3/users', method: 'POST', body: offlineUserPayload }); expect.fail('Should have thrown'); } catch (error) { - expect(error.statusCode).to.equal(400); - expect(error.error.error.message).to.equal('This user cannot have multiple places'); + expect(error.status).to.equal(400); + expect(error.body.error.message).to.equal('This user cannot have multiple places'); } }); @@ -2072,8 +2036,8 @@ describe('Users API', () => { await utils.request({ path: '/api/v3/users', method: 'POST', body: onlineUserPayload }); expect.expect.fail('Should have thrown'); } catch (err) { - expect(err.responseBody.code).to.equal(400); - expect(err.responseBody.error.message).to.equal('Invalid facilities list'); + expect(err.body.code).to.equal(400); + expect(err.body.error.message).to.equal('Invalid facilities list'); } const offlineUserPayload = { @@ -2088,8 +2052,8 @@ describe('Users API', () => { await utils.request({ path: '/api/v3/users', method: 'POST', body: offlineUserPayload }); expect.expect.fail('Should have thrown'); } catch (err) { - expect(err.responseBody.code).to.equal(400); - expect(err.responseBody.error.message).to.equal('Missing required fields: place'); + expect(err.body.code).to.equal(400); + expect(err.body.error.message).to.equal('Missing required fields: place'); } }); }); diff --git a/tests/integration/api/controllers/well-known.spec.js b/tests/integration/api/controllers/well-known.spec.js index 6d77886ce78..a27d0bf94ea 100644 --- a/tests/integration/api/controllers/well-known.spec.js +++ b/tests/integration/api/controllers/well-known.spec.js @@ -17,7 +17,7 @@ describe('well-known', () => { }) .then(() => chai.expect.fail('should have thrown')) .catch(error => { - chai.expect(error.response.statusCode).to.equal(404); + chai.expect(error.status).to.equal(404); }); }); diff --git a/tests/integration/api/rate-limit.spec.js b/tests/integration/api/rate-limit.spec.js index 677ff00bf2e..f7bb6791404 100644 --- a/tests/integration/api/rate-limit.spec.js +++ b/tests/integration/api/rate-limit.spec.js @@ -18,7 +18,7 @@ describe('rate limit', () => { await requestThat401s(); expect.fail('should have been rate limited'); } catch (e) { - expect(e.statusCode).to.equal(429); + expect(e.status).to.equal(429); } await new Promise((resolve) => { @@ -30,7 +30,7 @@ describe('rate limit', () => { expect.fail('should have rejected due to no auth'); } catch (e) { // the rate limit period has passed, so we're back to 401s - expect(e.statusCode).to.equal(401); + expect(e.status).to.equal(401); } }); diff --git a/tests/integration/api/routing.spec.js b/tests/integration/api/routing.spec.js index 4191f742682..affb0cae7cb 100644 --- a/tests/integration/api/routing.spec.js +++ b/tests/integration/api/routing.spec.js @@ -142,9 +142,9 @@ describe('routing', () => { .request(options) .catch(err => err) .then(result => { - expect(result.statusCode).to.equal(401); - expect(result.response.headers['logout-authorization']).to.equal('CHT-Core API'); - expect(result.responseBody.error).to.equal('unauthorized'); + expect(result.status).to.equal(401); + expect(result.headers.get('logout-authorization')).to.equal('CHT-Core API'); + expect(result.body.error).to.equal('unauthorized'); }); }); }); @@ -234,12 +234,12 @@ describe('routing', () => { results.forEach((result, idx) => { if (idx === 0) { // online user request - expect(result.statusCode).to.equal(404); - expect(result.responseBody.error).to.equal('not_found'); + expect(result.status).to.equal(404); + expect(result.body.error).to.equal('not_found'); } else { // offline user requests - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -275,12 +275,12 @@ describe('routing', () => { results.forEach((result, idx) => { if (idx === 0) { // online user request - expect(result.statusCode).to.equal(404); - expect(result.responseBody.error).to.equal('not_found'); + expect(result.status).to.equal(404); + expect(result.body.error).to.equal('not_found'); } else { // offline user requests - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -317,12 +317,12 @@ describe('routing', () => { results.forEach((result, idx) => { if (idx === 0) { // online user request - expect(result.statusCode).to.equal(404); - expect(result.responseBody.error).to.equal('not_found'); + expect(result.status).to.equal(404); + expect(result.body.error).to.equal('not_found'); } else { // offline user requests - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -363,8 +363,8 @@ describe('routing', () => { expect(result.docs.length).to.be.above(0); } else { // offline user request - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -406,8 +406,8 @@ describe('routing', () => { expect(result.fields).to.deep.equal([]); } else { // offline user requests - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -444,8 +444,8 @@ describe('routing', () => { expect(result.indexes.length).to.equal(1); } else { // offline user request - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -488,8 +488,8 @@ describe('routing', () => { expect(result.ok).to.equal(true); } else { // offline user request - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -522,11 +522,11 @@ describe('routing', () => { results.forEach((result, idx) => { if (idx === 0) { // online user request - expect(result.statusCode).to.be.undefined; + expect(result.status).to.be.undefined; } else { // offline user requests - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); } }); }); @@ -559,8 +559,8 @@ describe('routing', () => { .catch(err => err) ]).then(results => { results.forEach(result => { - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); }); }); }); @@ -658,8 +658,8 @@ describe('routing', () => { ]) .then(results => { results.forEach(result => { - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); }); }); }); @@ -695,8 +695,8 @@ describe('routing', () => { .catch(err => err), ]).then(results => { results.forEach(result => { - expect(result.statusCode).to.equal(403); - expect(result.responseBody.error).to.equal('forbidden'); + expect(result.status).to.equal(403); + expect(result.body.error).to.equal('forbidden'); }); }); }); @@ -739,17 +739,17 @@ describe('routing', () => { return createSession() .then(res => { - expect(res.statusCode).to.equal(200); - expect(res.headers['set-cookie'].length).to.equal(1); - const sessionCookie = res.headers['set-cookie'][0].split(';')[0]; + expect(res.status).to.equal(200); + expect(res.headers.getSetCookie().length).to.equal(1); + const sessionCookie = res.headers.getSetCookie()[0].split(';')[0]; expect(sessionCookie.split('=')[0]).to.equal('AuthSession'); return sessionCookie; }) .then(sessionCookie => getSession(sessionCookie)) .then(res => { - expect(res.statusCode).to.equal(200); - expect(res.headers['set-cookie'].length).to.equal(1); - const [ content, age, path, expires, samesite ] = res.headers['set-cookie'][0].split('; '); + expect(res.status).to.equal(200); + expect(res.headers.getSetCookie().length).to.equal(1); + const [ content, age, path, expires, samesite ] = res.headers.getSetCookie()[0].split('; '); // check the cookie content is unchanged const [ contentKey, contentValue ] = content.split('='); @@ -827,7 +827,7 @@ describe('routing', () => { return utils.requestOnTestDb(_.defaults(params, offlineRequestOptions)).catch(err => err); }) .then(response => { - expect(response.statusCode).to.equal(403); + expect(response.status).to.equal(403); }) .then(() => { const params = { @@ -838,7 +838,7 @@ describe('routing', () => { return utils.requestOnMedicDb(_.defaults(params, offlineRequestOptions)).catch(err => err); }) .then(response => { - expect(response.statusCode).to.equal(403); + expect(response.status).to.equal(403); }) .then(() => utils.getDoc('settings')) .then(settings => { diff --git a/tests/integration/api/server.spec.js b/tests/integration/api/server.spec.js index 2b50dec116c..bc6d056347c 100644 --- a/tests/integration/api/server.spec.js +++ b/tests/integration/api/server.spec.js @@ -1,5 +1,4 @@ const utils = require('@utils'); -const request = require('request'); const constants = require('@constants'); const _ = require('lodash'); const placeFactory = require('@factories/cht/contacts/place'); @@ -15,80 +14,61 @@ describe('server', () => { json: false }; - return utils.requestOnTestDb(opts, true) + return utils.requestOnTestDb(opts) .then(() => expect.fail('should have thrown')) .catch(e => { - expect(e.responseBody).to.equal('Content-Type must be application/json'); + expect(e.body).to.equal('Content-Type must be application/json'); }); }); }); describe('response compression', () => { - const requestWrapper = (options) => { - _.defaults(options, { - auth: { - sendImmediately: true, - username: constants.USERNAME, - password: constants.PASSWORD - }, - method: 'GET', - baseUrl: constants.BASE_URL + '/' + constants.DB_NAME, - uri: '/', - gzip: true - }); + const requestWrapper = async (options) => { + const opts = { path: '/', gzip: true, resolveWithFullResponse: true, ...options }; - return new Promise((resolve, reject) => { - request(options, (err, res, body) => { - if (err) { - return reject(err); - } - - if (res.headers['content-type'] === 'application/json' && typeof body === 'string') { - try { - body = JSON.parse(body); - } catch (err) { - // an error occured when trying parse 'body' to Object - } - } - - resolve({ res, body }); - }); - }); + const res = await utils.request(opts); + return { res, body: res.body }; }; it('compresses proxied CouchDB application/json requests which send accept-encoding gzip headers', () => { - const options = { uri: '/_all_docs' }; + const options = { path: '/medic/_all_docs' }; return requestWrapper(options).then(({res}) => { - expect(res.headers['content-encoding']).to.equal('gzip'); - expect(res.headers['content-type']).to.equal('application/json'); + expect(res.headers.get('content-encoding')).to.equal('gzip'); + expect(res.headers.get('content-type')).to.equal('application/json'); }); }); it('compresses proxied CouchDB application/json requests which send accept-encoding deflate headers', () => { - const options = { uri: '/_all_docs', gzip: false, headers: { 'Accept-Encoding': 'deflate' } }; + const options = { + path: '/medic/_all_docs', + gzip: false, + headers: { 'Accept-Encoding': 'deflate' } + }; return requestWrapper(options).then(({res}) => { - expect(res.headers['content-encoding']).to.equal('deflate'); - expect(res.headers['content-type']).to.equal('application/json'); + expect(res.headers.get('content-encoding')).to.equal('deflate'); + expect(res.headers.get('content-type')).to.equal('application/json'); }); }); it('does not compress when no accept-encoding headers are sent', () => { - const options = { uri: '/_all_docs', gzip: false }; + const options = { + path: '/medic/_all_docs', + gzip: false + }; return requestWrapper(options).then(({res}) => { - expect(res.headers['content-type']).to.equal('application/json'); - expect(res.headers['content-encoding']).to.be.undefined; + expect(res.headers.get('content-type')).to.equal('application/json'); + expect(res.headers.get('content-encoding')).to.be.null; }); }); it('compresses audited endpoints responses', () => { // compression threshold is 1024B const options = { - uri: '/_bulk_docs', + path: '/medic/_bulk_docs', method: 'POST', - json: true, body: { docs: [ { _id: 'sample_doc' }, { _id: 'sample_doc2' }, { _id: 'sample_doc3' }, @@ -102,9 +82,8 @@ describe('server', () => { }; return requestWrapper(options).then(({res, body}) => { - expect(res.headers['content-type']).to.equal('application/json'); - expect(res.headers['content-encoding']).to.equal('gzip'); - expect(body.length).to.equal(18); + expect(res.headers.get('content-type')).to.equal('application/json'); + expect(res.headers.get('content-encoding')).to.equal('gzip'); expect(_.omit(body[0], 'rev')).to.eql({ id: 'sample_doc', ok: true }); expect(_.omit(body[1], 'rev')).to.eql({ id: 'sample_doc2', ok: true }); expect(_.omit(body[2], 'rev')).to.eql({ id: 'sample_doc3', ok: true }); @@ -116,22 +95,28 @@ describe('server', () => { .getDoc('sample_doc') .then(doc => { const options = { - uri: '/sample_doc/attach?rev=' + doc._rev, + path: '/medic/sample_doc/attach', body: 'my-attachment-content', headers: { 'Content-Type': 'text/plain' }, - method: 'PUT' + method: 'PUT', + json: false, + qs: { rev: doc._rev } }; return requestWrapper(options); }) .then(({body}) => { - const options = { uri: '/sample_doc/attach?rev=' + body.rev}; + const options = { + path: '/medic//sample_doc/attach', + json: false, + qs: { rev: body.rev } + }; return requestWrapper(options); }) .then(({res, body}) => { - expect(res.headers['content-type']).to.equal('text/plain'); - expect(res.headers['content-encoding']).to.equal('gzip'); + expect(res.headers.get('content-type')).to.equal('text/plain'); + expect(res.headers.get('content-encoding')).to.equal('gzip'); expect(body).to.equal('my-attachment-content'); }); }); @@ -144,22 +129,27 @@ describe('server', () => { .getDoc('sample_doc2') .then(doc => { const options = { - uri: '/sample_doc2/attach?rev=' + doc._rev, + path: '/medic/sample_doc2/attach', body: xml, + json: false, headers: { 'Content-Type': 'application/xml' }, - method: 'PUT' + method: 'PUT', + qs: { rev: doc._rev } }; return requestWrapper(options); }) .then(({body}) => { - const options = { uri: '/sample_doc2/attach?rev=' + body.rev}; + const options = { + path: '/medic/sample_doc2/attach', + qs: { rev: body.rev } + }; return requestWrapper(options); }) .then(({res, body}) => { - expect(res.headers['content-type']).to.equal('application/xml'); - expect(res.headers['content-encoding']).to.equal('gzip'); + expect(res.headers.get('content-type')).to.equal('application/xml'); + expect(res.headers.get('content-encoding')).to.equal('gzip'); expect(body).to.equal(xml); }); }); @@ -170,16 +160,21 @@ describe('server', () => { 'Person 1.1.2.1'; const doc = await utils.getDoc('sample_doc2'); const options = { - uri: '/sample_doc2/attach?rev='+doc._rev, + path: '/medic/sample_doc2/attach', body: png, headers: { 'Content-Type': 'image/png' }, - method: 'PUT' + method: 'PUT', + qs: { rev: doc._rev }, }; const { body } = await requestWrapper(options); - const getAttachmentOptions = { uri: '/sample_doc2/attach?rev=' + body.rev }; + const getAttachmentOptions = { + path: '/medic/sample_doc2/attach', + qs: { rev: body.rev }, + json: false, + }; const { res, body: attachmentBody } = await requestWrapper(getAttachmentOptions); - expect(res.headers[ 'content-type' ]).to.equal('image/png'); - expect(res.headers[ 'content-encoding' ]).to.be.undefined; + expect(res.headers.get('content-type')).to.equal('image/png'); + expect(res.headers.get('content-encoding')).to.be.null; expect(attachmentBody).to.equal(png); }); }); diff --git a/tests/integration/infodocs/infodocs.spec.js b/tests/integration/infodocs/infodocs.spec.js index c6e7f2fef74..c49848bd0d2 100644 --- a/tests/integration/infodocs/infodocs.spec.js +++ b/tests/integration/infodocs/infodocs.spec.js @@ -58,7 +58,7 @@ describe('infodocs', () => { await utils.requestOnTestDb({ path, method, body: doc }); assert.fail('request should fail with conflict'); } catch (err) { - assert.equal(err.statusCode, 409); + assert.equal(err.status, 409); } const [newInfoDoc] = await delayedInfoDocsOf(doc._id); diff --git a/tests/integration/medic-collect/medic-collect.spec.js b/tests/integration/medic-collect/medic-collect.spec.js index d8e9c0d72df..e40bb3e40aa 100644 --- a/tests/integration/medic-collect/medic-collect.spec.js +++ b/tests/integration/medic-collect/medic-collect.spec.js @@ -1,6 +1,4 @@ const assert = require('chai').assert; -const constants = require('@constants'); -const request = require('request-promise-native'); const utils = require('@utils'); const host = 'localhost'; const db = utils.db; @@ -37,19 +35,15 @@ describe('medic-collect', () => { describe('without User-Agent header', () => { it('is prompted for auth details if not supplied', () => { return getForms({ auth: false, userAgent: false }) - .then(() => { - assert.fail('should fail the request'); - }) - .catch(err => { - assert.equal(err.statusCode, 401); - assert.equal(err.response.headers['www-authenticate'], 'Basic realm="Medic Web Services"'); + .then(err => { + assert.equal(err.status, 401); }); }); it('can fetch a list of forms', () => { return getForms({ auth: true, userAgent: false }) .then(res => { - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); assert.equal(res.body, MY_COLLECT_FORM_RESPONSE); }); }); @@ -58,19 +52,15 @@ describe('medic-collect', () => { describe('with User-Agent header', () => { it('is prompted for auth details if not supplied', () => { return getForms({ auth: false, userAgent: true }) - .then(() => { - assert.fail('should fail the request'); - }) - .catch(err => { - assert.equal(err.statusCode, 401); - assert.equal(err.response.headers['www-authenticate'], 'Basic realm="Medic Web Services"'); + .then(err => { + assert.equal(err.status, 401); }); }); it('can fetch a list of forms', () => { return getForms({ auth: true, userAgent: true }) .then(res => { - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); assert.equal(res.body, MY_COLLECT_FORM_RESPONSE); }); }); @@ -78,8 +68,6 @@ describe('medic-collect', () => { }); const getForms = ({ auth, userAgent }) => { - const url = auth ? constants.BASE_URL_AUTH : constants.BASE_URL; - const headers = { 'X-OpenRosa-Version': '1.0', Date: new Date().toISOString(), @@ -90,10 +78,11 @@ const getForms = ({ auth, userAgent }) => { 'org.medicmobile.collect.android/SNAPSHOT'; } - return request.get({ - url: `${url}/api/v1/forms`, + return utils.request({ + path: `/api/v1/forms`, headers, - resolveWithFullResponse: true + resolveWithFullResponse: true, + noAuth: !auth, }); }; diff --git a/tests/integration/nginx/nginx.spec.js b/tests/integration/nginx/nginx.spec.js index a661187fb6d..506640e93b7 100644 --- a/tests/integration/nginx/nginx.spec.js +++ b/tests/integration/nginx/nginx.spec.js @@ -5,14 +5,14 @@ const constants = require('@constants'); describe('HTTP request should redirect to HTTPS', () => { it('should return a 301 status code and redirect to HTTPS @docker', async () => { const [jsonResponse, htmlResponse] = await Promise.all([ - utils.request({ uri: `http://${constants.API_HOST}/`, followRedirect: false, json: true }).catch(err => err), - utils.request({ uri: `http://${constants.API_HOST}/`, followRedirect: false, json: false }).catch(err => err), + utils.request({ uri: `http://${constants.API_HOST}/`, redirect: 'manual', json: true, resolveWithFullResponse: true }).catch(err => err), + utils.request({ uri: `http://${constants.API_HOST}/`, redirect: 'manual', json: false, resolveWithFullResponse: true }).catch(err => err), ]); - expect(jsonResponse.statusCode).to.be.equal(301); - expect(htmlResponse.statusCode).to.be.equal(301); - expect(jsonResponse.responseBody.error).to.be.equal('301 Moved Permanently'); - expect(htmlResponse.responseBody).to.contain('301 Moved Permanently'); + expect(jsonResponse.status).to.be.equal(301); + expect(htmlResponse.status).to.be.equal(301); + expect(jsonResponse.body.error).to.be.equal('301 Moved Permanently'); + expect(htmlResponse.body).to.contain('301 Moved Permanently'); }); }); @@ -23,10 +23,10 @@ describe('HTTP acme-challenge should not redirect', () => { utils.request({ uri: `http://${constants.API_HOST}/.well-known/acme-challenge/`, json: false }).catch(err => err), ]); - expect(jsonResponse.statusCode).to.be.equal(404); - expect(htmlResponse.statusCode).to.be.equal(404); - expect(jsonResponse.responseBody.error).to.be.equal('404 Not Found'); - expect(htmlResponse.responseBody).to.contain('404 Not Found'); + expect(jsonResponse.status).to.be.equal(404); + expect(htmlResponse.status).to.be.equal(404); + expect(jsonResponse.body.error).to.be.equal('404 Not Found'); + expect(htmlResponse.body).to.contain('404 Not Found'); }); }); diff --git a/tests/integration/sentinel/transitions/create-user-for-contacts.spec.js b/tests/integration/sentinel/transitions/create-user-for-contacts.spec.js index d534d67137e..efbe2d564e7 100644 --- a/tests/integration/sentinel/transitions/create-user-for-contacts.spec.js +++ b/tests/integration/sentinel/transitions/create-user-for-contacts.spec.js @@ -47,10 +47,10 @@ const loginAsUser = ({ username, password }) => { const opts = { path: '/medic/login', method: 'POST', - simple: false, + resolveWithFullResponse: true, noAuth: true, body: { user: username, password }, - followRedirect: false, + redirect: 'manual', }; return utils.request(opts); }; @@ -124,7 +124,7 @@ describe('create_user_for_contacts', () => { await utils.createUsers([ORIGINAL_USER]); newUsers.push(ORIGINAL_USER.username); // Can log in as user - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 302 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 302 }); await utils.saveDoc(NEW_PERSON); // Write another contact that has a user being created and another user being replaced // (This is an approximation of behavior that could happen if Sentinel was down when the @@ -154,11 +154,11 @@ describe('create_user_for_contacts', () => { // Transition successful assert.isTrue(transitions.create_user_for_contacts.ok); // Can no longer log in as user - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 401 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 401 }); // User's password was automatically reset. Change it to something we know. await updateUserPassword(ORIGINAL_USER.username, 'n3wPassword!'); // Can still login as original user with new password - assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { statusCode: 302 }); + assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { status: 302 }); // New replacement user created const [newUserSettings, ...additionalUsers] = await utils.getUserSettings({ contactId: NEW_PERSON._id }); @@ -217,7 +217,7 @@ describe('create_user_for_contacts', () => { await utils.createUsers([ORIGINAL_USER]); newUsers.push(ORIGINAL_USER.username); // Can log in as user - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 302 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 302 }); await utils.saveDoc(NEW_PERSON); const originalContact = await utils.getDoc(ORIGINAL_PERSON._id); originalContact.user_for_contact = { @@ -235,11 +235,11 @@ describe('create_user_for_contacts', () => { // Transition successful assert.isTrue(transitions.create_user_for_contacts.ok); // Can no longer log in as user - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 401 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 401 }); // User's password was automatically reset. Change it to something we know. await updateUserPassword(ORIGINAL_USER.username, 'n3wPassword!'); // Can still login as original user with new password - assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { statusCode: 302 }); + assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { status: 302 }); // New user created const [newUserSettings, ...additionalUsers] = await utils.getUserSettings({ contactId: NEW_PERSON._id }); @@ -273,7 +273,7 @@ describe('create_user_for_contacts', () => { await utils.createUsers([otherUser]); newUsers.push(otherUser.username); // Can log in as user - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 302 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 302 }); await utils.saveDoc(NEW_PERSON); const originalContact = await utils.getDoc(ORIGINAL_PERSON._id); originalContact.user_for_contact = { @@ -291,11 +291,11 @@ describe('create_user_for_contacts', () => { // Transition successful assert.isTrue(transitions.create_user_for_contacts.ok); // Can no longer log in as user - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 401 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 401 }); // User's password was automatically reset. Change it to something we know. await updateUserPassword(ORIGINAL_USER.username, 'n3wPassword!'); // Can still login as original user with new password - assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { statusCode: 302 }); + assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { status: 302 }); // New user created const [newUserSettings, ...additionalUsers] = await utils.getUserSettings({ contactId: NEW_PERSON._id }); assert.isEmpty(additionalUsers); @@ -323,7 +323,7 @@ describe('create_user_for_contacts', () => { const [otherUserSettings] = await utils.getUserSettings({ name: otherUser.username }); assert.equal(otherUserSettings.contact_id, ORIGINAL_PERSON._id); // Can still log in as other user - assert.include(await loginAsUser(otherUser), { statusCode: 302 }); + assert.include(await loginAsUser(otherUser), { status: 302 }); }); it('replaces multiple users for a contact', async () => { @@ -334,8 +334,8 @@ describe('create_user_for_contacts', () => { await utils.createUsers([otherUser]); newUsers.push(otherUser.username); // Can log in as users - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 302 }); - assert.include(await loginAsUser(otherUser), { statusCode: 302 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 302 }); + assert.include(await loginAsUser(otherUser), { status: 302 }); await utils.saveDoc(NEW_PERSON); const originalContact = await utils.getDoc(ORIGINAL_PERSON._id); originalContact.user_for_contact = { @@ -357,14 +357,14 @@ describe('create_user_for_contacts', () => { // Transition successful assert.isTrue(transitions.create_user_for_contacts.ok); // Can no longer log in as users - assert.include(await loginAsUser(ORIGINAL_USER), { statusCode: 401 }); - assert.include(await loginAsUser(otherUser), { statusCode: 401 }); + assert.include(await loginAsUser(ORIGINAL_USER), { status: 401 }); + assert.include(await loginAsUser(otherUser), { status: 401 }); // User's password was automatically reset. Change it to something we know. await updateUserPassword(ORIGINAL_USER.username, 'n3wPassword!'); await updateUserPassword(otherUser.username, 'n3wPassword!'); // Can still login as original user with new password - assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { statusCode: 302 }); - assert.include(await loginAsUser({ ...otherUser, password: 'n3wPassword!' }), { statusCode: 302 }); + assert.include(await loginAsUser({ ...ORIGINAL_USER, password: 'n3wPassword!' }), { status: 302 }); + assert.include(await loginAsUser({ ...otherUser, password: 'n3wPassword!' }), { status: 302 }); // New users created const [newUserSettings0, newUserSettings1, ...additionalUsers] = await utils.getUserSettings({ contactId: NEW_PERSON._id }); diff --git a/tests/page-objects/default/login/login.wdio.page.js b/tests/page-objects/default/login/login.wdio.page.js index 766689b9588..e61b4fd5f82 100644 --- a/tests/page-objects/default/login/login.wdio.page.js +++ b/tests/page-objects/default/login/login.wdio.page.js @@ -59,10 +59,10 @@ const cookieLogin = async (options = {}) => { path: '/medic/login', body: { user: username, password: password, locale }, method: 'POST', - simple: false, + resolveWithFullResponse: true, }; const resp = await utils.request(opts); - const cookieArray = utils.parseCookieResponse(resp.headers['set-cookie']); + const cookieArray = utils.parseCookieResponse(resp.headers.getSetCookie()); await browser.url('/'); await browser.setCookies(cookieArray); diff --git a/tests/utils/index.js b/tests/utils/index.js index 4b69ee69461..ad846f714c7 100644 --- a/tests/utils/index.js +++ b/tests/utils/index.js @@ -2,7 +2,6 @@ const _ = require('lodash'); const constants = require('@constants'); -const rpn = require('request-promise-native'); const fs = require('fs'); const os = require('os'); const path = require('path'); @@ -62,10 +61,6 @@ const logsDb = new PouchDB(`${constants.BASE_URL}/${constants.DB_NAME}-logs`, { const existingFeedbackDocIds = []; const MINIMUM_BROWSER_VERSION = '90'; const KUBECTL_CONTEXT = `-n ${PROJECT_NAME} --context k3d-${PROJECT_NAME}`; -const cookieJar = rpn.jar(); - -// Cookies from the jar will be included on Node `fetch` calls -global.fetch = require('fetch-cookie').default(global.fetch, cookieJar); const makeTempDir = (prefix) => fs.mkdtempSync(path.join(path.join(os.tmpdir(), prefix || 'ci-'))); const env = { @@ -77,7 +72,7 @@ const env = { const dockerPlatformName = () => { try { - return JSON.parse(execSync(`docker version --format '{{json .Server.Platform.Name}}'`)); + return JSON.parse(execSync(`docker version --format '{{json .Server.Platform.Name}}'`).toString()); } catch (error) { console.log('docker version failed. NOTE this error is not relevant if running outside of docker'); console.log(error.message); @@ -92,7 +87,7 @@ const isDockerDesktop = () => { const dockerGateway = () => { const network = isDocker() ? NETWORK : `k3d-${PROJECT_NAME}`; try { - return JSON.parse(execSync(`docker network inspect ${network} --format='{{json .IPAM.Config}}'`)); + return JSON.parse(execSync(`docker network inspect ${network} --format='{{json .IPAM.Config}}'`).toString()); } catch (error) { console.log('docker network inspect failed. NOTE this error is not relevant if running outside of docker'); console.log(error.message); @@ -138,81 +133,115 @@ const setupUserDoc = (userName = constants.USERNAME, userDoc = userSettings.buil }); }; -const getSession = async () => { - if (cookieJar.getCookies(constants.BASE_URL).length) { - return; +const randomIp = () => { + const section = () => (Math.floor(Math.random() * 255) + 1); + return `${section()}.${section()}.${section()}.${section()}`; +}; + +const getRequestUri = (options) => { + let uri = (options.uri || `${constants.BASE_URL}${options.path}`); + if (options.qs) { + Object.keys(options.qs).forEach((key) => { + if (Array.isArray(options.qs[key])) { + options.qs[key] = JSON.stringify(options.qs[key]); + } + }); + uri = `${uri}?${new URLSearchParams(options.qs).toString()}`; } - const options = { - method: 'POST', - uri: `${constants.BASE_URL}/_session`, - json: true, - body: { name: auth.username, password: auth.password }, - auth, - resolveWithFullResponse: true, - }; - const response = await rpn(options); - const setCookie = response.headers?.['set-cookie']; - const header = Array.isArray(setCookie) ? setCookie.find(header => header.startsWith('AuthSession')) : setCookie; - if (header) { - try { - cookieJar.setCookie(rpn.cookie(header), constants.BASE_URL); - } catch (err) { - console.error(err); - } + return uri; +}; + +const setRequestContentType = (options) => { + let sendJson = true; + if (options.json === false || + (options.headers['Content-Type'] && options.headers['Content-Type'] !== 'application/json') + ) { + sendJson = false; + } + + if (sendJson) { + options.headers.Accept = 'application/json'; + options.headers['Content-Type'] = 'application/json'; + options.body = JSON.stringify(options.body); } + + return sendJson; }; -const isLoginRequest = options => { - return options.path === '/medic/login' && options.body.user !== auth.username; +const setRequestEncoding = (options) => { + if (options.gzip) { + options.headers['Accept-Encoding'] = 'gzip'; + } + + if (options.gzip === false && !options.headers['Accept-Encoding']) { + options.headers['Accept-Encoding'] = 'identity'; + } }; -const randomIp = () => { - const section = () => (Math.floor(Math.random() * 255) + 1); - return `${section()}.${section()}.${section()}.${section()}`; +const setRequestAuth = (options) => { + if (options.noAuth) { + return; + } + + const auth = options.auth || { username: constants.USERNAME, password: constants.PASSWORD }; + const basicAuth = btoa(`${auth.username}:${auth.password}`); + options.headers.Authorization = `Basic ${basicAuth}`; +}; + +const getRequestOptions = (options) => { + options = typeof options === 'string' ? { path: options } : _.clone(options); + options.headers = options.headers || {}; + options.headers['X-Forwarded-For'] = randomIp(); + + const uri = getRequestUri(options); + const sendJson = setRequestContentType(options); + + setRequestAuth(options); + setRequestEncoding(options); + + return { uri, options, resolveWithFullResponse: options.resolveWithFullResponse, sendJson }; +}; + +const getResponseBody = async (response, sendJson) => { + const receiveJson = (!response.headers.get('content-type') && sendJson) || + response.headers.get('content-type')?.startsWith('application/json'); + return receiveJson ? await response.json() : await response.text(); }; // First Object is passed to http.request, second is for specific options / flags // for this wrapper -const request = async (options, { debug } = {}) => { //NOSONAR - options = typeof options === 'string' ? { path: options } : _.clone(options); - if (!options.noAuth && !options.auth && !isLoginRequest(options)) { - await getSession(); - options.jar = cookieJar; - } else { - options.headers = options.headers || {}; - options.headers['X-Forwarded-For'] = randomIp(); +const request = async (options, { debug } = {}) => { + const { uri, options: requestInit, resolveWithFullResponse, sendJson } = getRequestOptions(options); + if (debug) { + console.debug('SENDING REQUEST', JSON.stringify({ ...options, body: null }, null, 2)); } - options.uri = options.uri || `${constants.BASE_URL}${options.path}`; - options.json = options.json === undefined ? true : options.json; + + const response = await fetch(uri, requestInit); + const responseObj = { + ...response, + body: await getResponseBody(response, sendJson), + status: response.status, + ok: response.ok, + headers: response.headers + }; if (debug) { - console.log('SENDING REQUEST'); - console.log(JSON.stringify(options, null, 2)); + console.debug('RESPONSE', response.status, response.body); } - options.transform = (body, response, resolveWithFullResponse) => { - if (debug) { - console.log('RESPONSE'); - console.log(response.statusCode); - console.log(response.body); - } - // we might get a json response for a non-json request. - const contentType = response.headers['content-type']; - if (contentType?.startsWith('application/json') && !options.json) { - response.body = JSON.parse(response.body); - } - // return full response if `resolveWithFullResponse` or if non-2xx status code (so errors can be inspected) - return resolveWithFullResponse || !(/^2/.test('' + response.statusCode)) ? response : response.body; - }; + if (resolveWithFullResponse) { + return responseObj; + } - try { - return await rpn(options); - } catch (err) { - err.responseBody = err?.response?.body; - console.warn(`Error with request: ${options.method || 'GET'} ${options.uri} ${err.statusCode}`); - throw err; + if (response.ok || (response.status > 300 && response.status < 399)) { + return responseObj.body; } + + console.warn(`Error with request: ${options.method || 'GET'} ${uri} ${responseObj.status}`); + const err = new Error(response.error || `${response.status} - ${JSON.stringify(responseObj.body)}`); + Object.assign(err, responseObj); + throw err; }; const requestOnTestDb = (options, debug) => { diff --git a/tests/utils/sentinel.js b/tests/utils/sentinel.js index 59202270461..11b40ac2a13 100644 --- a/tests/utils/sentinel.js +++ b/tests/utils/sentinel.js @@ -19,7 +19,7 @@ const waitForSeq = (metadataId, docIds) => { return utils.sentinelDb .get(metadataId) .catch(err => { - if (err.statusCode === 404) { // maybe Sentinel hasn't started yet + if (err.status === 404) { // maybe Sentinel hasn't started yet return { value: 0 }; } throw err; diff --git a/tests/utils/sms.js b/tests/utils/sms.js index c2e5f5486a7..3ee179d1875 100644 --- a/tests/utils/sms.js +++ b/tests/utils/sms.js @@ -5,7 +5,7 @@ const sendSms = async (phone, message = 'testing sms') => { method: 'POST', path: '/api/v2/records', headers: { - 'Content-type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' }, body: `message=${message}&from=${phone}`, });