1.0.2 • Published 4 years ago

jest-aws-sdk-mock v1.0.2

Weekly downloads
658
License
MIT
Repository
github
Last release
4 years ago

jest-aws-sdk-mock

Create Jest Mocks for AWS SDK services.

Build Status codecov

This module was created to help test AWS Lambda functions but can be used in any situation where the AWS SDK needs to be mocked. This is a rewrite of https://github.com/dwyl/aws-sdk-mock but using jest under the hood instead of sinon.js.

What?

Uses Jest under the hood to mock the AWS SDK services and their associated methods.

How? (Usage)

install jest-aws-sdk-mock from NPM

npm install jest-aws-sdk-mock --save-dev

Use in your Tests

Using plain JavaScript

const AWSMock = require('jest-aws-sdk-mock');

AWSMock.mock('DynamoDB', 'putItem', function (params, callback){
  callback(null, 'successfully put item in database');
});

AWSMock.mock('SNS', 'publish', 'test-message');

// S3 getObject mock - return a Buffer object with file data
AWSMock.mock('S3', 'getObject', Buffer.from(require('fs').readFileSync('testFile.csv')));


/**
    TESTS
**/

AWSMock.restore('SNS', 'publish');
AWSMock.restore('DynamoDB');
AWSMock.restore('S3');
// or AWSMock.restore(); this will restore all the methods and services

Using TypeScript

import AWSMock from 'jest-aws-sdk-mock';
import AWS from 'aws-sdk';
import { GetItemInput } from 'aws-sdk/clients/dynamodb';

describe('the module', () => {
  afterEach(() => {
    AWSMock.restore();
  });

  it('should mock getItem from DynamoDB', async () => {
    // Overwriting DynamoDB.getItem()
    AWSMock.setSDKInstance(AWS);
    AWSMock.mock('DynamoDB', 'getItem', (params: GetItemInput, callback: Function) => {
      console.log('DynamoDB', 'getItem', 'mock called');
      callback(null, {pk: 'foo', sk: 'bar'});
    })

    const input:GetItemInput = { TableName: '', Key: {} };
    const dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
    expect(await dynamodb.getItem(input).promise()).toEqual({ pk: 'foo', sk: 'bar' });

    AWSMock.restore('DynamoDB');
  });

  it('should mock reading from DocumentClient', async () => {
    // Overwriting DynamoDB.DocumentClient.get()
    AWSMock.setSDKInstance(AWS);
    AWSMock.mock('DynamoDB.DocumentClient', 'get', (params: GetItemInput, callback: Function) => {
      console.log('DynamoDB.DocumentClient', 'get', 'mock called');
      callback(null, {pk: 'foo', sk: 'bar'});
    });

    const input:GetItemInput = { TableName: '', Key: {} };
    const client = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
    expect(await client.get(input).promise()).toEqual({ pk: 'foo', sk: 'bar' });
  });
});

Notes:

  • The AWS Service needs to be initialised after the invocation of the mock function

The below won't work

const AWS = require('aws-sdk');
const AWSMock = require('jest-aws-sdk-mock');

const sns = new AWS.SNS();
// won't override sns.publish
AWSMock.mock('SNS', 'publish', 'message');
  • The mock function will be overwritten if you call mock on the same method again
AWSMock.mock('SNS', 'publish', function(params, callback) {
    callback(null, 'message');
});
const sns = new AWS.SNS();
AWSMock.mock('SNS', 'publish', function(params, callback) {
    callback(null, 'test');
});
sns.publish({} as any, function(err, data) {
    expect(data).toBe('test');
    done();
});
  • Individual SDK import will work
AWSMock.mock('S3', 'getObject', function(params, callback) {
    callback(null, 'message');
});
const S3 = require('aws-sdk/clients/s3');
const s3 = new S3();
const result = await s3.getObject({} as any).promise();
expect(result).toEqual('message');
done();

Nested services

It is possible to mock nested services like DynamoDB.DocumentClient. Simply use this dot-notation name as the service parameter to the mock() and restore() methods:

AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) {
  callback(null, {Item: {Key: 'Value'}});
});

NB: Use caution when mocking both a nested service and its parent service. The nested service should be mocked before and restored after its parent:

// OK
AWS.mock('DynamoDB.DocumentClient', 'get', 'message');
AWS.mock('DynamoDB', 'describeTable', 'message');
AWS.restore('DynamoDB');
AWS.restore('DynamoDB.DocumentClient');

// Not OK
AWS.mock('DynamoDB', 'describeTable', 'message');
AWS.mock('DynamoDB.DocumentClient', 'get', 'message');

// Not OK
AWS.restore('DynamoDB.DocumentClient');
AWS.restore('DynamoDB');

Setting the aws-sdk module explicitly

Project structures that don't include the aws-sdk at the top level node_modules project folder will not be properly mocked. An example of this would be installing the aws-sdk in a nested project directory. You can get around this by explicitly setting the path to a nested aws-sdk module using setSDK().

Example:

const path = require('path');
const AWS = require('jest-aws-sdk-mock');

AWS.setSDK(path.resolve('../../functions/foo/node_modules/aws-sdk'));

/**
    TESTS
**/

Setting the aws-sdk object explicitly

Due to transpiling, code written in TypeScript or ES6 may not correctly mock because the aws-sdk object created within aws-sdk-mock will not be equal to the object created within the code to test. In addition, it is sometimes convenient to have multiple SDK instances in a test. For either scenario, it is possible to pass in the SDK object directly using setSDKInstance().

Example:

// test code
const AWSMock = require('jest-aws-sdk-mock');
import AWS from 'aws-sdk';
AWSMock.setSDKInstance(AWS);
AWSMock.mock('SQS', /* ... */);

// implementation code
const sqs = new AWS.SQS();

Configuring promises

If your environment lacks a global Promise constructor (e.g. nodejs 0.10), you can explicitly set the promises on aws-sdk-mock. Set the value of AWS.Promise to the constructor for your chosen promise library.

Example (if Q is your promise library of choice):

const AWS = require('jest-aws-sdk-mock'),
    Q = require('q');

AWS.Promise = Q.Promise;


/**
    TESTS
**/

Documentation

AWS.mock(service, method, replace)

Replaces a method on an AWS service with a replacement function or string.

ParamTypeOptional/RequiredDescription
servicestringRequiredAWS service to mock e.g. SNS, DynamoDB, S3
methodstringRequiredmethod on AWS service to mock e.g. 'publish' (for SNS), 'putItem' for 'DynamoDB'
replacestring or functionRequiredA string or function to replace the method

AWS.restore(service, method)

Removes the mock to restore the specified AWS service

ParamTypeOptional/RequiredDescription
servicestringOptionalAWS service to restore - If only the service is specified, all the methods are restored
methodstringOptionalMethod on AWS service to restore

If AWS.restore is called without arguments (AWS.restore()) then all the services and their associated methods are restored i.e. equivalent to a 'restore all' function.

AWS.setSDK(path)

Explicitly set the require path for the aws-sdk

ParamTypeOptional/RequiredDescription
pathstringRequiredPath to a nested AWS SDK node module

AWS.setSDKInstance(sdk)

Explicitly set the aws-sdk instance to use

ParamTypeOptional/RequiredDescription
sdkobjectRequiredThe AWS SDK object