Mock the aws-sdk using jest

Mock the aws-sdk using jest

Hello there!

Unit testing can be challenging, especially when it comes to creating mocks for external libraries. In this article, I'll discuss how to mock the lambda invoke function in the AWS SDK using Jest.

I'll be writing test cases for a CacheServiceProvider, which is a simple cache service provider containing a getter and a setter.

To mock the lambda invoke function, I'll use Jest's mockImplementation method. This allows us to set responses for the promise resolve/reject.

Here's the code for the CacheServiceProvider.ts:

import { Lambda } from "aws-sdk";

export enum Action {
  Get = "get",
  Delete = "delete",
  Keys = "keys",
  Set = "set",
}

export default class CacheServiceProvider {
  private lambda: Lambda;

  async set(key: string, value: string, expire: number): Promise<string> {
    return this.invoke({
      action: Action.Set,
      key,
      value,
      expire,
    }).then(
      (data: Lambda.InvocationResponse) => {
        const response = JSON.parse(data.Payload.toString());
        return response.body.data;
      },
      (err) => {
        return err;
      }
    );
  }

  async get(key: string): Promise<string> {
    return this.invoke({
      action: Action.Get,
      key,
    }).then(
      (data: Lambda.InvocationResponse) => {
        const response = JSON.parse(data.Payload.toString());
        return response.body.data;
      },
      (err) => {
        return err;
      }
    );
  }

  private async invoke(body: object): Promise<Lambda.InvocationResponse> {
    return await this.lambda
      .invoke({
        FunctionName: "my-function-name",
        InvocationType: "RequestResponse",
        Payload: JSON.stringify({
          body,
        }),
      })
      .promise();
  }

  constructor() {
    this.lambda = new Lambda();
  }
}

And here's the code for the test cases in CacheServiceProvider.test.ts:

import CacheServiceProvider from "./CacheServiceProvider";

let provider: CacheServiceProvider;

const key = "TestKey";
const value = "TestValue";

provider = new CacheServiceProvider();

const fakePromise = {
  promise: jest.fn(),
};

jest.mock("aws-sdk", () => ({
  Lambda: jest.fn(() => ({
    invoke: () => fakePromise,
  })),
}));

describe("CacheHelperServiceProvider", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it("Should be able to set and get value using a key", async () => {
    fakePromise.promise = jest.fn().mockImplementation(() =>
      Promise.resolve({
        Payload: JSON.stringify({
          body: {
            data: value,
          },
        }),
      })
    );

    const setResponse = await provider.set(key, value, 10);
    expect(setResponse).toStrictEqual(value);

    const getResponse = await provider.get(key);
    expect(getResponse).toStrictEqual(value);
  });

  it("Should throw an error when using different key", async () => {
    fakePromise.promise = jest
      .fn()
      .mockImplementation(() => Promise.reject(new Error()));

    try {
      await provider.get(key);
    } catch (error) {
      expect(error).toBeDefined();
    }
  });

});

To mock the lambda invoke function, I first create a fakePromise function and set it to an empty object with a promise property using Jest's fn method.

Then, I use Jest's mock method to mock the Lambda function in the AWS SDK and return an object with an invoke function that returns our fakePromise object.

In the first test case, I use Jest's mockImplementation method to set the response to the lambda invoke function's promise.

If you found this article useful, please consider leaving a comment to let me know how it helped you. Additionally, I welcome any suggestions you may have to improve the content.