node.jstestingsinonproxyquiregoogle-auth-library

can't mock constructor using sinon and proxyquire


I've looked at several similar questions but none of the cases fit my problem. I'm trying to mock a constructor, which I've done in other tests, but I can't get it to work in the case of using google-auth-library

code.js

const {OAuth2Client} = require('google-auth-library');
const keys = require('./oauth2.keys.json');

async function getRedirectUrl() {
  const oAuth2Client = new OAuth2Client(
    keys.installed.client_id,
    keys.installed.client_secret,
    keys.installed.redirect_uris[0]
  );

  const authorizeUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: 'https://www.googleapis.com/auth/bigquery',
    prompt: 'consent'
  });

  return authorizeUrl;
}

test.js

let Code = require('../code.js');

describe('code', function() {
    let generateUrlStub, tokenStub, mockClient;

    before(async () => {
      generateUrlStub = sinon.stub().returns('http://example.com');
      tokenStub = sinon.stub().returns({tokens: 'tokens'});

      mockClient = sinon.stub().returns({
        generateAuthUrl: generateUrlStub,
        getToken: tokenStub,
      });

      Code = proxyquire('../Code.js', {
        'google-auth-library': mockClient,
      });
    });

    it('should call generateAuthUrl', async function() {
      const output = await Code.getRedirectUrl();
      sinon.assert.called(generateUrlStub)
    });
});

Solution

  • Here is the unit test solution:

    const { OAuth2Client } = require("google-auth-library");
    const keys = {
      installed: {
        client_id: "1",
        client_secret: "client_secret",
        redirect_uris: ["http://example.com/callback"]
      }
    };
    
    async function getRedirectUrl() {
      const oAuth2Client = new OAuth2Client(
        keys.installed.client_id,
        keys.installed.client_secret,
        keys.installed.redirect_uris[0]
      );
    
      const authorizeUrl = oAuth2Client.generateAuthUrl({
        access_type: "offline",
        scope: "https://www.googleapis.com/auth/bigquery",
        prompt: "consent"
      });
    
      return authorizeUrl;
    }
    
    module.exports = { getRedirectUrl };
    

    index.spec.js:

    const proxyquire = require("proxyquire");
    const sinon = require("sinon");
    const { expect } = require("chai");
    
    describe("code", function() {
      let generateUrlStub, tokenStub, code;
      beforeEach(() => {
        generateUrlStub = sinon.stub().returns("http://example.com");
        tokenStub = sinon.stub().returns({ tokens: "tokens" });
    
        code = proxyquire("./", {
          "google-auth-library": {
            OAuth2Client: sinon.stub().callsFake(() => {
              return {
                generateAuthUrl: generateUrlStub,
                getToken: tokenStub
              };
            })
          }
        });
      });
      afterEach(() => {
        sinon.restore();
      });
    
      it("should call generateAuthUrl", async function() {
        const output = await code.getRedirectUrl();
        expect(output).to.be.eq("http://example.com");
        sinon.assert.called(generateUrlStub);
      });
    });
    

    Unit test result with 100% coverage:

      code
        ✓ should call generateAuthUrl
    
    
      1 passing (216ms)
    
    ---------------|----------|----------|----------|----------|-------------------|
    File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
    ---------------|----------|----------|----------|----------|-------------------|
    All files      |      100 |      100 |      100 |      100 |                   |
     index.js      |      100 |      100 |      100 |      100 |                   |
     index.spec.js |      100 |      100 |      100 |      100 |                   |
    ---------------|----------|----------|----------|----------|-------------------|
    

    Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/58955304