Search code examples
node.jstypescriptamazon-web-serviceschaisinon

How to mock AWS RDSDataService methods?


I have a database file (not a class) that does an update operation as shown below -

    /* database operations file  - NOT A CLASS */
    import * as AWS from 'aws-sdk';
    AWS.config.update({
         region: 'us-west-2'
    });
    //.... set resourceARN, secretARN and other params to be passed to 
    const secretARN = process.env['SECRETARN'];
    const resourceARN = process.env['RESOURCEARN'];
    const rdsDataService = new AWS.RDSDataService();
    const databaseName = process.env['DATABASE'];


    
    // update query here
    
    const addID = async(myID:string, userIds:string[], param3:string) => {
    // .....some validation on the parameters
    const userIdlist = userIds.join();
    const updateQuery = 'my update sql query';

    const sqlParams:any = {
        secretArn: secretARN,
        resourceArn: resourceARN,
        sql: updateQuery,
        database: databaseName,
        includeResultMetadata: true
    }
    // run SQL command
    await rdsDataService.executeStatement(sqlParams).promise()
        .then(() => { logger.info('Update Query succeeded') })
        .catch((error) => { logger.info(error); throw new Error('Unable to perform update for given users') });
};

export default {
    addID
}

This is my test file -

import * as sinon from 'sinon';
import chai from 'chai';
import * as AWS from 'aws-sdk';
import chaiaspromised from 'chai-as-promised';
import AWSMock from 'aws-sdk-mock';
import proxyquire from 'proxyquire';
chai.use(chaiaspromised);

const expect = chai.expect;
describe('Test Database component', () => {
    it('add ID should be successful when all arguments are provided correctly', async () => {
    AWSMock.setSDKInstance(AWS);
    const rdstub = AWSMock.mock('RDSDataService', 'executeStatement', function (params, callback){
        callback(null, 'successfully put item in database');
    });
    const dbops = proxyquire('path to the database file above', {rdsDataService:rdstub}).default;
    expect(await dbops.addRegulationID('xyz', ['101', '102'], 'xyz')).to.not.throw();
    AWSMock.restore('AWS.RDSDataService');
});
});

whenever I run the test, I get an error like below -

Test Database component
    1) add ID should be successful when all arguments are provided correctly


  0 passing (4s)
  1 failing

  1) Test Database component add ID should be successful when all arguments are provided correctly:
     Error: Unable to perform update for given users
      at lib/dbops.ts:96:55

How can I mock the executeStatement API of RDSDataService? Do I need a separate mock library for it? I tried the above after referring a few examples for the npm library, but somehow the mock does not seem to be working for RDSDataService. Where am I going wrong here?


Solution

  • proxyquire and sinon packages are enough, you don't need to use aws-sdk-mock package.

    index.ts:

    import * as AWS from 'aws-sdk';
    AWS.config.update({ region: 'us-west-2' });
    const secretARN = process.env['SECRETARN'];
    const resourceARN = process.env['RESOURCEARN'];
    const databaseName = process.env['DATABASE'];
    
    const rdsDataService = new AWS.RDSDataService();
    
    const addID = async (myID: string, userIds: string[], param3: string) => {
      const updateQuery = 'my update sql query';
    
      const sqlParams: any = {
        secretArn: secretARN,
        resourceArn: resourceARN,
        sql: updateQuery,
        database: databaseName,
        includeResultMetadata: true,
      };
      await rdsDataService
        .executeStatement(sqlParams)
        .promise()
        .then(() => {
          console.info('Update Query succeeded');
        })
        .catch((error) => {
          console.info(error);
          throw new Error('Unable to perform update for given users');
        });
    };
    
    export default { addID };
    

    index.test.ts:

    import sinon from 'sinon';
    import chai, { expect } from 'chai';
    import chaiaspromised from 'chai-as-promised';
    import proxyquire from 'proxyquire';
    
    chai.use(chaiaspromised);
    
    describe('69592200', () => {
      it('should execute statement correctly', async () => {
        const rdsDataService = {
          executeStatement: sinon.stub().returnsThis(),
          promise: sinon.stub().resolves(),
        };
        const AWSStub = {
          RDSDataService: sinon.stub().returns(rdsDataService),
          config: {
            update: sinon.stub(),
          },
        };
        const dbops = proxyquire('./', {
          'aws-sdk': AWSStub,
        }).default;
        await dbops.addID('xyz', ['101', '102'], 'xyz');
        sinon.assert.calledWithExactly(AWSStub.config.update, { region: 'us-west-2' });
        sinon.assert.calledOnce(rdsDataService.executeStatement);
        sinon.assert.calledOnce(rdsDataService.promise);
      });
    
      it('should throw error if execute query statement fail', async () => {
        const error = new Error('network');
        const rdsDataService = {
          executeStatement: sinon.stub().returnsThis(),
          promise: sinon.stub().rejects(error),
        };
        const AWSStub = {
          RDSDataService: sinon.stub().returns(rdsDataService),
          config: {
            update: sinon.stub(),
          },
        };
        const dbops = proxyquire('./', {
          'aws-sdk': AWSStub,
        }).default;
        await expect(dbops.addID('xyz', ['101', '102'], 'xyz')).to.eventually.rejectedWith(
          'Unable to perform update for given users',
        );
      });
    });
    

    test result:

    69592200
    Update Query succeeded
        ✓ should execute statement correctly (3974ms)
    Error: network
        at /Users/dulin/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/69592200/index.test.ts:30:19
        at Generator.next (<anonymous>)
        at /Users/dulin/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/69592200/index.test.ts:27:71
        at new Promise (<anonymous>)
        at __awaiter (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/69592200/index.test.ts:23:12)
        at Context.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/69592200/index.test.ts:29:71)
        at callFn (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runnable.js:364:21)
        at Test.Runnable.run (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runnable.js:352:5)
        at Runner.runTest (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runner.js:677:10)
        at /Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runner.js:801:12
        at next (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runner.js:594:14)
        at /Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runner.js:604:7
        at next (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runner.js:486:14)
        at Immediate.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/expressjs-research/node_modules/mocha/lib/runner.js:572:5)
        at processImmediate (internal/timers.js:461:21)
        ✓ should throw error if execute query statement fail
    
    
      2 passing (4s)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |     100 |     100 |                   
     index.ts |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------