vamsiampolu
vamsiampolu

Reputation: 6622

Mock the constructor for AWS.DynamoDB.DocumentClient using jest

I have a function that looks like this:

function connect() {
   const secret = 'secret';
   const key = 'key';
   const region = 'region';
   const client = new AWS.DynamoDB({
      secret,
      key,
      region
   });'
   return new AWS.DynamoDB.DocumentClient({ service: client })
}

I would like to test the function connect. I have mocked the DynamoDB constructor like this:

// See https://stackoverflow.com/questions/47606545/mock-a-dependencys-constructor-jest
jest.mock('aws-sdk', () => {
  const DynamoDB = jest.fn().mockImplementation(() => {
    return {};
  });
  return {
    DynamoDB,
  };
});

However, this means that the DocumentClient constructor fails. How do I mock that as well?

Upvotes: 9

Views: 25050

Answers (7)

Munib
Munib

Reputation: 967

Trying out the most voted answer, I tried to mock the document client and it didn't work.

I got this error: TypeError: AWS.DynamoDB.DocumentClient is not a constructor

Instead, I realized that I had to mock the DocumentClient as a class, not a function.

So, with that in mind, this is what worked instead:

jest.mock(`aws-sdk`, () => {
    class mockDocumentClient {
        async put(config) {
            //TODO: your logic here
            return true;
        }
        async query(config) {
            // TODO: your logic here
            return true;
        }
    }
    return {
        DynamoDB: {
            DocumentClient: mockDocumentClient,
    }};
});

Upvotes: 2

Marcelo Paes Rech
Marcelo Paes Rech

Reputation: 1

For me, what worked is the following:

import AWS from "aws-sdk"
...
jest.spyOn(AWS.DynamoDB, "DocumentClient").mockReturnValue(mockedDocumentClient);

Here mockedDocumentClient is my mock object that fakes the DocumentClient behaviour. I just include the methods I would use on it.

Upvotes: 0

Jose Quijada
Jose Quijada

Reputation: 692

Jest provides DynamoDB integration for running tests. See this document, look at 3. Configure DynamoDB client:

const {DocumentClient} = require('aws-sdk/clients/dynamodb');

const isTest = process.env.JEST_WORKER_ID;
const config = {
  convertEmptyValues: true,
  ...(isTest && {endpoint: 'localhost:8000', sslEnabled: false, region: 'local-env'})
};

const ddb = new DocumentClient(config);

I guess you can abstract out (if you haven't already) the DynamoDB client configuration into its own module file and export that client so that it can be required elsewhere, and when the Jest tests run, the client gets configured to point the mock DynamoDB server/tables that you have set up as per the other steps of the Jest DynamoDB documentation.

Upvotes: 0

dpmott
dpmott

Reputation: 292

Building on the comment from duxtinto above:

In my case (and in the case of the OP if I'm reading it right), DynamoDB isn't being called as a function, but rather is an object with a DocumentClient field on it, so this worked for me:

jest.mock('aws-sdk', () => {
  return {
    DynamoDB: { // just an object, not a function
      DocumentClient: jest.fn(() => ({
        put: mockDynamoDbPut
      }))
    }
  }});

Upvotes: 10

Esteban Arredondo
Esteban Arredondo

Reputation: 69

Here what worked for me using jest with TypeScript:

// blabla.test.ts
import { DynamoDB } from 'aws-sdk';
import { ConsumerClass } from '../consumer-class';
import { DependencyConsumerClass } from '../dependency-consumer-class';

/*
* Inside consumerClassInstance.save() is calling this.dynamo.putItem({...}).promise();
*/
jest.mock('aws-sdk', () => {
    return {
        DynamoDB: jest.fn(() => {
            return {
                putItem: jest.fn(() => {
                    return {
                        promise: jest.fn(() => true)
                    };
                })
            };
        })
    };
});

test('sample test', async () => {
    const dependencyConsumerClass = new DependencyConsumerClass();
    const consumerClassInstance = new ConsumerClass(dependencyConsumerClass, new DynamoDB());
    
    const result = await consumerClassInstance.save();
    console.log(result);
});

Upvotes: 1

duxtinto
duxtinto

Reputation: 489

This worked for me:

const mockDynamoDbPut = jest.fn().mockImplementation(() => {
  return {
    promise() {
      return Promise.resolve({});
    }
  };
});

jest.doMock('aws-sdk', () => {
  return {
    DynamoDB: jest.fn(() => ({
      DocumentClient: jest.fn(() => ({
        put: mockDynamoDbPut
      }))
    }))
  };
});

I hope it's helpful for you too.

Regards,

David.

Upvotes: 7

seanplwong
seanplwong

Reputation: 1081

DocumentClient might call some of the client method, so simply define those methods stub. Say for example, DocumentClient would use batchGetItem, in your code

import AWS from 'aws-sdk';

jest.mock('aws-sdk', () => {
  const DynamoDB = jest.fn().mockImplementation(() => {
    return {
      batchGetItem: jest.fn(),
    };
  });
  return {
    DynamoDB,
  };
});

// you could inspect the mock
console.log(new AWS.DynamoDB({ ... }));

Upvotes: 5

Related Questions