简体   繁体   中英

Mocking two S3 API calls in the same AWS Lambda function using Jest

I'm trying to mock two S3 calls in the same Lambda function but seem to be getting Access Denied errors so this leads me to believe the S3 calls are not being mocked. The syntax I'm currently using works when mocking just one S3 call in the function but the function I'm currently testing has two S3 calls(deleteObject and putObject).

Here is my mock code:

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

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

 jest.mock("aws-sdk", () => ({
      S3: jest.fn(() => ({
           deleteObject: deleteObjectMock,
           putObject: putObjectMock,
      })),
 }));

And my test:

 const newHandler = Handler.handler
 const returnValue = await handler ({
      queryStringParameters: {
           eventListValue: "test",
           eventListName: "test2",
      body: {newStuff: "stuff goes here", eventList: [] },
 });
 expect(returnValue).toEqual({
      statusCode:200,
      headers: {
           "Access-Control-Allow-Origin": "*",
           "Access-Control-Allow-Credentials": true,
      },
      body: undefined
 })
 });

And the part of the file that has the two S3 calls:

 if(event.queryStringParameters.value){
      await s3.deleteObject({Bucket: "my-bucket-name", Key: "name-of-object", 
 }).promise()
 }

 const putObjectResponse = await s3.putObject({Bucket: "my-bucket-name", Key: 
 "name-of-object",
  ContentType: "application/json", Body: event.body}).promise();

Access denied is returned when I try to test this. Any help would be great.

Here is the unit test solution:

handler.js :

import AWS from 'aws-sdk';

const s3 = new AWS.S3();

export async function handler(event) {
  if (event.queryStringParameters.value) {
    await s3.deleteObject({ Bucket: 'my-bucket-name', Key: 'name-of-object' }).promise();
  }

  const putObjectResponse = await s3
    .putObject({ Bucket: 'my-bucket-name', Key: 'name-of-object', ContentType: 'application/json', Body: event.body })
    .promise();

  return putObjectResponse;
}

handler.test.js :

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

jest.mock('aws-sdk', () => {
  const putObjectOutputMock = {
    promise: jest.fn(),
  };
  const putObjectMock = jest.fn(() => putObjectOutputMock);

  const deleteObjectOutputMock = {
    promise: jest.fn(),
  };
  const deleteObjectMock = jest.fn(() => deleteObjectOutputMock);

  const mS3 = {
    deleteObject: deleteObjectMock,
    putObject: putObjectMock,
  };
  return { S3: jest.fn(() => mS3) };
});

describe('61719699', () => {
  it('should delete object and put object', async () => {
    const mS3 = new AWSMock.S3();
    const mPutObjectResponse = {
      statusCode: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': true,
      },
      body: undefined,
    };
    mS3.putObject().promise.mockResolvedValueOnce(mPutObjectResponse);

    const mEvent = { queryStringParameters: { value: 'test' }, body: { newStuff: 'stuff goes here', eventList: [] } };
    const returnValue = await handler(mEvent);
    expect(returnValue).toEqual({
      statusCode: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': true,
      },
      body: undefined,
    });
    expect(mS3.deleteObject).toBeCalledWith({ Bucket: 'my-bucket-name', Key: 'name-of-object' });
    expect(mS3.deleteObject().promise).toBeCalled();
    expect(mS3.putObject).toBeCalledWith({
      Bucket: 'my-bucket-name',
      Key: 'name-of-object',
      ContentType: 'application/json',
      Body: { newStuff: 'stuff goes here', eventList: [] },
    });
  });
});

unit test results with coverage report:

 PASS  stackoverflow/61719699/handler.test.js (10.22s)
  61719699
    ✓ should delete object and put object (7ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |    66.67 |     100 |     100 |                   
 handler.js |     100 |    66.67 |     100 |     100 | 6                 
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.94s

Problem was because I was using the specific service import instead of the top-level import in my code file.

Changed

 const S3 = require("aws-sdk/clients/s3");

to

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM