Home > front end >  How to mock dynamoDB call with jest?
How to mock dynamoDB call with jest?

Time:10-11

I have a simple Handler with calls getData defined in separate file

export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  let respData = await new DynamoDBClient().getData(123);
  return {
    statusCode: 200,
    body: JSON.stringify(respData),
  };
};

within my DynamoDB class, I have the following.

import { DynamoDB } from 'aws-sdk';
export default class DynamoDBClient {
private config: Config;
private client: DynamoDB.DocumentClient;

constructor() {
  this.config = getConfig();

  const dynamoDBClientConfig = this.config.mockDynamoDBEndpoint
  ? {
      endpoint: this.config.mockDynamoDBEndpoint,
      sslEnabled: false,
      region: 'local'
    }
  : undefined;

 this.client = new DynamoDB.DocumentClient(dynamoDBClientConfig);
}
// function
getData= async (id: string): Promise<any> => {
 const response = await this.client
  .query({
    TableName: tableName,
    IndexName: tableIndex,
    KeyConditionExpression: 'id= :id',
    ExpressionAttributeValues: {
      ':id': id
    }
  })
  .promise();
 return response;
}
}

My Test case

describe('DynamoDB', () => {
test('should return no data', async () => {
    
    const spy = jest.spyOn(DynamoDBClient, 'getData').mockImplementation(() => jest.fn(() => {
      return Promise.resolve({});
  }));
    const actual = await handler(event);
    console.log(actual);

    expect(actual).toEqual({ statusCode: 400, body: JSON.stringify({ }) });
  });
 });

CodePudding user response:

You defined .getData() method using property initializer syntax. It will be bound to the class instance. Since the handler function depends on DynamoDBClient class via the import statement, you can't create an instance in the test case and pass it to handler when calling it.

You can mock aws-sdk module and the DynamoDB.DocumentClient class and its instance.

DynamoDBClient.ts:

import { DynamoDB } from 'aws-sdk';

function getConfig() {
  return { mockDynamoDBEndpoint: '' };
}
interface Config {
  mockDynamoDBEndpoint: string;
}

export default class DynamoDBClient {
  private config: Config;
  private client: DynamoDB.DocumentClient;

  constructor() {
    this.config = getConfig();

    const dynamoDBClientConfig = this.config.mockDynamoDBEndpoint
      ? {
          endpoint: this.config.mockDynamoDBEndpoint,
          sslEnabled: false,
          region: 'local',
        }
      : undefined;

    this.client = new DynamoDB.DocumentClient(dynamoDBClientConfig);
  }

  getData = async (id: string): Promise<any> => {
    const response = await this.client
      .query({
        TableName: 'tableName',
        IndexName: 'tableIndex',
        KeyConditionExpression: 'id= :id',
        ExpressionAttributeValues: {
          ':id': id,
        },
      })
      .promise();
    return response;
  };
}

handler.ts:

import DynamoDBClient from './DynamoDBClient';

interface APIGatewayProxyEvent {}
interface APIGatewayProxyResult {}

export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  let respData = await new DynamoDBClient().getData('123');
  return { statusCode: 200, body: JSON.stringify(respData) };
};

handler.test.ts:

import { handler } from './handler';
import { DynamoDB } from 'aws-sdk';

const mDocumentClientInstance = {
  query: jest.fn().mockReturnThis(),
  promise: jest.fn(),
};
jest.mock('aws-sdk', () => {
  return {
    DynamoDB: {
      DocumentClient: jest.fn(() => mDocumentClientInstance),
    },
  };
});

describe('69475890', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });
  test('should pass', async () => {
    mDocumentClientInstance.promise.mockResolvedValueOnce({});
    const event = {};
    const actual = await handler(event);
    expect(actual).toEqual({ statusCode: 200, body: JSON.stringify({}) });
    expect(DynamoDB.DocumentClient).toBeCalled();
    expect(mDocumentClientInstance.query).toBeCalledWith({
      TableName: 'tableName',
      IndexName: 'tableIndex',
      KeyConditionExpression: 'id= :id',
      ExpressionAttributeValues: {
        ':id': '123',
      },
    });
    expect(mDocumentClientInstance.promise).toBeCalled();
  });
});

test result:

 PASS  examples/69475890/handler.test.ts (8.642 s)
  69475890
    ✓ should pass (4 ms)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |     100 |       50 |     100 |     100 |                   
 DynamoDBClient.ts |     100 |       50 |     100 |     100 | 18                
 handler.ts        |     100 |      100 |     100 |     100 |                   
-------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.231 s
  • Related