sudo
sudo

Reputation: 115

Write a unit test in mocha for the given method using mocks/stubs

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

Answers (1)

Lin Du
Lin Du

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

Related Questions