Search code examples
node.jses6-promisesinonchai

How to test await/async with DynamoDb on nodejs?


I use NodeJs to implement AWS Lambda function and want to clarify what is the right way to test integration with DynamoDB:

Lambda code:

const AWS = require('aws-sdk');

AWS.config.update({region: region});
const dynamoDb = new AWS.DynamoDB();

exports.handler = async function(event, context) {
   ...
   await dynamoDb.deleteItem(item).promise();
}

I was going to use mocha, sinon, chai and aws-sdk-mock for tests:

const expect = require('chai').expect;
const AWS = require('aws-sdk-mock');
const lambda = require('../index.js');
const sinon = require('sinon');

describe('Test', function () {
  let deleteItemSpy;

  beforeEach(function () {
     deleteItemSpy = sinon.spy();
     AWS.mock('DynamoDB', 'deleteItem', deleteItemSpy);
  }
  it('valid call', async function() {
     await lambda.handler({"id":1}, null); 
     expect(deleteItemSpy.calledOnce).to.be.true;
  })
});

But there are two main problems:

  1. Mock doesn't work if dynamoDb is created outside of the handler. What other options do I have? Can I use sinon.stub somehow?

  2. It throws timeout because await never receives the result from lambda. Problem is related to spy itself. I probably can replace it with: AWS.mock('DynamoDB', 'deleteItem', function (params, callback) { });


Solution

  • Ok I figured it out. Not sure if it the best way, but it works.

    const expect = require('chai').expect;
    const AWS = require('aws-sdk');
    const sinon = require('sinon');
    
    describe('Test', function () {
       let deleteItemStub;
       let mockDynamoDb;
       let lambda;
    
       before(function() {
           deleteItemStub = sinon.stub();
           mockDynamoDb = sinon.stub(AWS, 'DynamoDB').callsFake(function() {
               return {
                   deleteItem: deleteItemStub
               };
           });
           lambda = require('../index.js');
       });
       after(function () {
           mockDynamoDb.restore();
       });
    
       beforeEach(function () {
           deleteItemStub.returns({ promise: () => Promise.resolve() });
       });
    
       afterEach(function () {
           deleteItemStub.reset();
       });
       it('valid call', async function() {
           await lambda.handler({"id":1}, null); 
           expect(deleteItemStub.calledOnce).to.be.true;
       });
    });