Created
October 14, 2016 17:05
-
-
Save visualjeff/f6de98d08cce7f7eb14972d1d636c16e to your computer and use it in GitHub Desktop.
Automated testing example for Node.js Hapi apps using Lab
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Node.js testing: | |
1. Use the package lab (also code and sinon). | |
npm install lab --save-dev | |
npm install code --save-dev // assertion library | |
npm install sinon --save-dev | |
2. Add the following test script to your package.json | |
For Linux: | |
"test": "./node_modules/lab/bin/lab -c -L", | |
For Windows: | |
"test": "lab -c -L", | |
3. Create a test directory for your tests. | |
4. Common imports for you tests: | |
const Code = require('code'); //assertion library | |
const Lab = require('lab'); | |
const Sinon = require('sinon'); | |
const Request = require('request'); | |
const lab = exports.lab = Lab.script(); | |
const server = exports.server = require('../index'); //How lab starts your node.js app | |
const describe = lab.describe; | |
const it = lab.it; | |
const expect = Code.expect; | |
const cookieVal = 'azure-auth=Fe26.2**0ad...'; //Put token here | |
5. Tests take the format: | |
describe('Test case name here:', () => { | |
//simulate a db error. We were using a document database with a rest endpoint. | |
it('DB error', (done) => { | |
const stub = Sinon.stub(Request, 'get', (url, callback) => { | |
callback(new Error('Error: connect ECONNREFUSED'), null, null); //Error message mirrors what the db would return in the event of a connection being refused. | |
}); | |
//endpoint info | |
const options = { | |
method: 'GET', | |
url: '/api/v1/availableRoles?locationId=001&locationType=Warehouse', | |
headers: { | |
Cookie: cookieVal | |
} | |
}; | |
//actual test is exercised | |
server.inject(options, (response) => { | |
stub.restore(); | |
expect(response.statusCode).to.equal(500); | |
done(); | |
}); | |
}); | |
//Test for an empty response from the db. | |
it('Empty response', (done) => { | |
//db response payload | |
const dbResp = { 'db_name':'role','doc_count':0,'doc_del_count':0,'update_seq':0,'purge_seq':0,'compact_running':false,'disk_size':79,'data_size':0,'instance_start_time':'1456585969789668','disk_format_version':6,'committed_update_seq':0 }; | |
//Load the response | |
const stub = Sinon.stub(Request, 'get', (url, callback) => { | |
callback(null, null, JSON.stringify(dbResp)); | |
}); | |
//endpoint info | |
const options = { | |
method: 'GET', | |
url: '/api/v1/availableRoles?locationId=001&locationType=Warehouse', | |
headers: { | |
Cookie: cookieVal | |
} | |
}; | |
//actual test is exercised | |
server.inject(options, (response) => { | |
stub.restore(); | |
expect(response.statusCode).to.equal(200); | |
expect(response.result.data).to.be.instanceof(Array); | |
expect(response.result.data).to.be.empty(); | |
done(); | |
}); | |
}); | |
//test for a validation error | |
it('Validation error - no query params', (done) => { | |
server.inject({ url: '/api/v1/availableRoles', headers: { Cookie: cookieVal } }, (response) => { | |
expect(response.statusCode).to.equal(400); | |
expect(response.result.errors[0].title).to.equal('Bad Request'); | |
expect(response.result.errors[0].status).to.equal(400); | |
expect(response.result.errors[0].detail).to.be.not.empty(); | |
done(); | |
}); | |
}); | |
Here two more complicated examples below: | |
NOTE: These examples dependency on ldapjs for the ldapClientStub: | |
npm install ldapjs --save | |
Import ldapjs into your Javascript file: | |
const Ldap = require('ldapjs'); | |
it('LDAP search error - Depot', (done) => { | |
const dbResp = { 'total_rows':2,'offset':0,'rows':[ | |
{ 'id':'3386dc099a874451e890ee4a7d003e66','key':'Warehouse','value':{ '_id':'3386dc099a874451e890ee4a7d003e66','_rev':'1-3e470cd2030438bc28539106953ba0ae','name':'ADM','type':'Warehouse','title':'Admin Manager','groups':'[bldtype]ALL[lang]ADM,[bldtype][region][bldnum],[region] [string] Admin,!App-Showcase(USR),!Group-LOC_ALL,!NoAccess-G_DRIVE,!PowerUsers(LOC),!Internet-VEAL,Google App Pilot - Provisioned Users' } }, | |
{ 'id':'3386dc099a874451e890ee4a7d0042b9','key':'Warehouse','value':{ '_id':'3386dc099a874451e890ee4a7d0042b9','_rev':'1-c3a44ad41e1222d323b35164fcf5d55a','name':'AID','type':'Warehouse','title':'Hearing Aid Manager','groups':'[bldtype]ALL[lang]AID,[bldtype][region][bldnum],[region] [string] Hearing Aid,!Group-LOC_ALL,!NoAccess-G_DRIVE,!PowerUsers(LOC),!App-HAC(PWR),!Internet-VEAL,Google App Pilot - Provisioned Users' } }] }; | |
const getStub = Sinon.stub(Request, 'get', (url, callback) => { | |
callback(null, null, JSON.stringify(dbResp)); | |
}); | |
const logStub = Sinon.stub(Request, 'post', (url, callback) => { //Logger error | |
callback('hey', null, {}); | |
}); | |
const ldapClientStub = Sinon.stub(Ldap, 'createClient').returns({ | |
on: () => {}, | |
bind: (dn, password, callback) => { | |
return callback(null, null); | |
}, | |
search: (searchBaseDn, searchOptions, callback) => { | |
return callback(new Error('ldapSearchdErr'), null); | |
} | |
}); | |
server.inject({ url: '/api/v1/availableRoles?locationId=001&locationType=Depot', headers: { Cookie: cookieVal } }, (response) => { | |
getStub.restore(); | |
logStub.restore(); | |
ldapClientStub.restore(); | |
expect(response.statusCode).to.equal(500); | |
expect(response.result.errors[0].title).to.equal('Internal Server Error'); | |
expect(response.result.errors[0].status).to.equal(500); | |
expect(response.result.errors[0].detail).to.be.not.empty(); | |
done(); | |
}); | |
}); | |
it('Happy Path - None of the Roles in AD', (done) => { | |
const dbResp = { 'total_rows':2,'offset':0,'rows':[ | |
{ 'id':'3386dc099a874451e890ee4a7d003e66','key':'Warehouse','value':{ '_id':'3386dc099a874451e890ee4a7d003e66','_rev':'1-3e470cd2030438bc28539106953ba0ae','name':'ADM','type':'Warehouse','title':'Admin Manager','groups':'[bldtype]ALL[lang]ADM,[bldtype][region][bldnum],[region] [string] Admin,!App-Showcase(USR),!Group-LOC_ALL,!NoAccess-G_DRIVE,!PowerUsers(LOC),!Internet-VEAL,Google App Pilot - Provisioned Users' } }, | |
{ 'id':'3386dc099a874451e890ee4a7d0042b9','key':'Warehouse','value':{ '_id':'3386dc099a874451e890ee4a7d0042b9','_rev':'1-c3a44ad41e1222d323b35164fcf5d55a','name':'AID','type':'Warehouse','title':'Hearing Aid Manager','groups':'[bldtype]ALL[lang]AID,[bldtype][region][bldnum],[region] [string] Hearing Aid,!Group-LOC_ALL,!NoAccess-G_DRIVE,!PowerUsers(LOC),!App-HAC(PWR),!Internet-VEAL,Google App Pilot - Provisioned Users' } }] }; | |
const getStub = Sinon.stub(Request, 'get', (url, callback) => { | |
callback(null, null, JSON.stringify(dbResp)); | |
}); | |
const logStub = Sinon.stub(Request, 'post', (url, callback) => { | |
callback(null, null, 'something'); | |
}); | |
const ldapClientStub = Sinon.stub(Ldap, 'createClient').returns({ | |
on: () => {}, | |
bind: (dn, password, callback) => { | |
return callback(null, null); | |
}, | |
unbind: () => {}, | |
search: (searchBaseDn, searchOptions, callback) => { | |
const ldapSearchRes = { | |
on: (event, searchCallback) => { | |
if (event === 'end') { | |
return searchCallback({ status: 0 }); | |
} | |
} | |
}; | |
return callback(null, ldapSearchRes); | |
} | |
}); | |
server.inject({ url: '/api/v1/availableRoles?locationId=001&locationType=Warehouse', headers: { Cookie: cookieVal } }, (response) => { | |
getStub.restore(); | |
logStub.restore(); | |
ldapClientStub.restore(); | |
expect(response.statusCode).to.equal(200); | |
expect(response.result.data).to.be.instanceof(Array); | |
expect(response.result.data.length).to.equal(2); | |
expect(response.result.data[0].id).to.be.not.empty(); | |
expect(response.result.data[0].type).to.equal('availableRoles'); | |
expect(response.result.data[0].attributes.name).to.equal('ADM'); | |
expect(response.result.data[0].attributes.type).to.equal('Warehouse'); | |
expect(response.result.data[0].attributes.title).to.equal('Admin Manager'); | |
expect(response.result.data[0].attributes.groups).to.be.not.empty(); | |
expect(response.result.data[0].attributes.groups).to.equal('[bldtype]ALL[lang]ADM,[bldtype][region][bldnum],[region] [string] Admin,!App-Showcase(USR),!Group-LOC_ALL,!NoAccess-G_DRIVE,!PowerUsers(LOC),!Internet-VEAL,Google App Pilot - Provisioned Users'); | |
expect(response.result.data[1].id).to.be.not.empty(); | |
expect(response.result.data[1].type).to.equal('availableRoles'); | |
expect(response.result.data[1].attributes.name).to.equal('AID'); | |
expect(response.result.data[1].attributes.type).to.equal('Warehouse'); | |
expect(response.result.data[1].attributes.title).to.equal('Hearing Aid Manager'); | |
expect(response.result.data[1].attributes.groups).to.be.not.empty(); | |
expect(response.result.data[1].attributes.groups).to.equal('[bldtype]ALL[lang]AID,[bldtype][region][bldnum],[region] [string] Hearing Aid,!Group-LOC_ALL,!NoAccess-G_DRIVE,!PowerUsers(LOC),!App-HAC(PWR),!Internet-VEAL,Google App Pilot - Provisioned Users'); | |
done(); | |
}); | |
}); | |
}); | |
For details see the lab docs: | |
https://www.npmjs.com/package/lab |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment