Reputation: 115
I am pretty new to unit testing in node.js.
I have a function which looks something like this. I need to write a unit test for the function.
async refreshToken(req, res) {
const token = req.body.token || req.query.token;
const options = {method: 'POST', url: ''};
let resp;
try {
resp = await request(options);
} catch (e) {
console.error(e);
}
if (resp) {
const grant = {
another_token: {
token: resp.another_token,
},
expires_in: resp.expires_in
}
res.end(JSON.stringify(grant));
} else {
res.status(400).end("not authorized");
}
}
I am planning to use mocha framework with sinon and chai.
I tried a test using mocha, but could not figure out how to assert if the request(options) is called at least once.
describe('refreshToken', () => {
it('should take token from body', async () => {
const req = {
body: {
token: "123"
}
}
await auth.refreshToken(req, res);
request.should.have.been.calledOnceWithExactly(options);
})
I get:
TypeError: Cannot read property 'xxxxx' of undefined
I am having difficulty how to make this work with mock/stub.
Upvotes: 0
Views: 1061
Reputation: 102297
Here is the unit test solution:
auth.ts
:
import request from 'request-promise';
export async function refreshToken(req, res) {
const token = req.body.token || req.query.token;
const options = { method: 'POST', url: 'https://github.com/mrdulin' };
let resp;
try {
resp = await request(options);
} catch (e) {
console.error(e);
}
if (resp) {
const grant = {
another_token: {
token: resp.another_token
},
expires_in: resp.expires_in
};
res.end(JSON.stringify(grant));
} else {
res.status(400).end('not authorized');
}
}
auth.spec.ts
:
import sinon from 'sinon';
import proxyquire from 'proxyquire';
import { expect } from 'chai';
describe('auth', () => {
describe('#refreshToken', () => {
it('should take token from body', async () => {
const mResponse = { another_token: '123', expires_in: '3600' };
const requestPromiseStub = sinon.stub().resolves(mResponse);
const auth = proxyquire('./auth', {
'request-promise': requestPromiseStub
});
const req = {
body: {
token: '123'
}
};
const res = { end: sinon.stub() };
await auth.refreshToken(req, res);
expect(requestPromiseStub.calledWith({ method: 'POST', url: 'https://github.com/mrdulin' })).to.be.true;
expect(
res.end.calledWith(
JSON.stringify({
another_token: {
token: mResponse.another_token
},
expires_in: mResponse.expires_in
})
)
).to.be.true;
});
it('should cause not authorized error', async () => {
const mError = new Error('network error');
const requestPromiseStub = sinon.stub().rejects(mError);
const auth = proxyquire('./auth', {
'request-promise': requestPromiseStub
});
const errorLogSpy = sinon.spy(console, 'error');
const req = {
body: {
token: '123'
}
};
const res = { status: sinon.stub().returnsThis(), end: sinon.stub() };
await auth.refreshToken(req, res);
expect(errorLogSpy.calledWith(mError)).to.be.true;
expect(res.status.calledWith(400)).to.be.true;
expect(res.status().end.calledWith('not authorized')).to.be.true;
});
});
});
Unit test result with coverage report:
auth
#refreshToken
✓ should take token from body (1262ms)
Error: network error
at /Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/57479631/auth.spec.ts:1:26462
at step (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/57479631/auth.spec.ts:1:23604)
at Object.next (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/57479631/auth.spec.ts:1:20644)
at /Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/57479631/auth.spec.ts:1:19788
at new Promise (<anonymous>)
at __awaiter (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/57479631/auth.spec.ts:1:18995)
at Context.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/57479631/auth.spec.ts:1:26156)
at callFn (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runnable.js:387:21)
at Test.Runnable.run (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runnable.js:379:7)
at Runner.runTest (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:535:10)
at /Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:653:12
at next (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:447:14)
at /Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:457:7
at next (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:362:14)
at Immediate.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:425:5)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
✓ should cause not authorized error (88ms)
2 passing (1s)
--------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files | 100 | 75 | 100 | 100 | |
auth.spec.ts | 100 | 100 | 100 | 100 | |
auth.ts | 100 | 75 | 100 | 100 | 4 |
--------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/57479631
Upvotes: 0