node.jsunit-testingaws-sdksinonproxyquire

TypeError: AWS.SecretsManager is not a constructor in unit testing with proxyquire


I have written a test code to test code that gives credentials from AWS Secret Manager. I used proxyquire and sinon for stubbing and getting this error.

Function I want to test

    exports.getCredsFromAWSSecretsManager = (keyName) => {
    const SM = new AWS.SecretsManager({
        apiVersion: process.env.AWS_SM_API_VERSION,
        region: process.env.AWS_SM_REGION
    });

    return SM.getSecretValue(params).promise().then((data) => {
        logger.info(logMsgs.awsHlpr_smGetSecretValueSuccess(JSON.stringify(data)));
        return JSON.parse(data.SecretString);
        
    }).catch((err) => {
        logger.error(logMsgs.awsHlpr_smGetSecretValueErr(JSON.stringify(err)));
        throw err;
    });
};

Test case that I have written

const sinon = require("sinon");
const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
const { mockLogger } = require("../../mockdata/mockLogger");

let awsHelper;
let secretsManagerStub;

describe.only("AWS Helper ", () => {

    // function1

    describe("AWS Helper: getCredsFromAWSSecretsManagera method", () => {

        before((done) => {
            const data = {
                SecretString: JSON.stringify({ publicKey: 'secretUsername', privateKey: 'secretPassword' }),
              };
            
            secretsManagerStub = {
                getSecretValue: sinon.stub().callsFake((params, callback) => {
                  callback(null, data);
                }),
               
              };

            const awsStub = {
                
                  SecretsManager: sinon.stub().returns(secretsManagerStub)
               
                
            } 
            awsHelper = proxyquire('../../../utils/aws_helper.js', {
                'aws-sdk':{
                    AWS:awsStub
                } ,
                 "../../utils/logger": mockLogger,
            }); 
            
              

            done();
        });

        afterEach(() => {
            
            sinon.restore();
        });

        it('should write random data!', async () => {

            const expectedData = "abcdef";

            secretsManagerStub.getSecretValue.yields(null, expectedData);

            const data = await awsHelper.getCredsFromAWSSecretsManager();

            sinon.assert.callCount(secretsManagerStub.getSecretValue, 1);
            assert.strictEqual(data, expectedData);
            
        });

    });
});

This code gives me the error saying TypeError: AWS.SecretsManager is not a constructor

any help would be greatly appreciated.


Solution

  • AWS is a namespace, it contains all AWS service classes like SecretsManager. You should provide the awsStub to aws-sdk, there is no need to wrap the awsStub inside an object.

    aws_helper.js:

    const AWS = require('aws-sdk');
    
    exports.getCredsFromAWSSecretsManager = () => {
      const SM = new AWS.SecretsManager({
        apiVersion: process.env.AWS_SM_API_VERSION,
        region: process.env.AWS_SM_REGION,
      });
      const params = {
        SecretId: '1',
      };
    
      return SM.getSecretValue(params)
        .promise()
        .then((data) => {
          console.info(data);
          return JSON.parse(data.SecretString);
        })
        .catch((err) => {
          console.error(err);
          throw err;
        });
    };
    

    aws_helper.test.js:

    const sinon = require('sinon');
    const proxyquire = require('proxyquire').noCallThru().noPreserveCache();
    
    let awsHelper;
    let secretsManagerStub;
    
    describe('AWS Helper: getCredsFromAWSSecretsManagera method', () => {
      before(() => {
        const data = {
          SecretString: JSON.stringify({ publicKey: 'secretUsername', privateKey: 'secretPassword' }),
        };
    
        secretsManagerStub = {
          getSecretValue: sinon.stub().returnsThis(),
          promise: sinon.stub().resolves(data),
        };
    
        const awsStub = {
          SecretsManager: sinon.stub().returns(secretsManagerStub),
        };
        awsHelper = proxyquire('./aws_helper.js', {
          'aws-sdk': awsStub,
        });
      });
    
      afterEach(() => {
        sinon.restore();
      });
    
      it('should write random data!', async () => {
        const data = await awsHelper.getCredsFromAWSSecretsManager();
        sinon.assert.callCount(secretsManagerStub.getSecretValue, 1);
        sinon.assert.match(data, { publicKey: 'secretUsername', privateKey: 'secretPassword' });
      });
    });
    

    test result:

      AWS Helper: getCredsFromAWSSecretsManagera method
    {
      SecretString: '{"publicKey":"secretUsername","privateKey":"secretPassword"}'
    }
        ✓ should write random data!
    
    
      1 passing (2s)
    
    ---------------|---------|----------|---------|---------|-------------------
    File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ---------------|---------|----------|---------|---------|-------------------
    All files      |   77.78 |      100 |   66.67 |   77.78 |                   
     aws_helper.js |   77.78 |      100 |   66.67 |   77.78 | 19-20             
    ---------------|---------|----------|---------|---------|-------------------