How to Mock AWS S3 in a Jest (Unit) Test

image

I found it a bit hard to find out how to mock AWS S3 while using Jest. So, I thought I’d document it here.

Useful Stack Overflow answers:

How to mock S3 with jest? Jest Mock module per test

Here’s the code we will be testing

const AWS = require('aws-sdk')

// a function that returns a promise
function copyFileToS3() {

  // initialise AWS S3
  const s3 = new AWS.S3({
    accessKeyId: 'whatever',
    secretAccessKey: 'whatever',
    endpoint: 'http://localhost:4566', // localstack is running on port 4566. Imagine this was the real S3 endpoint
    s3ForcePathStyle: true,
  })

  const copyObjectParams = {
    Bucket: 'some-bucket',
    CopySource: 'some-bucket/some/path/myfile.json,
    Key: 'some-bucket/some/other/path/myfile.json',
  }

  return s3.copyObject(copyObjectParams).promise()
}

Here’s a unit test for the code above using Jest

We’ll be mocking S3, and asserting that S3’s copyObject function gets called with the right parameters.

Obviously, this is a simplistic function with hard-coded values, but the test is valid for a function that maybe does some transformation to the destination key, or does some validation on the CopySource, etc.

const s3 = require('./s3') // This is the file where we use aws-sdk's S3 CopyObject method

const mockS3Instance = {
  copyObject: jest.fn().mockReturnThis(),
  promise: jest.fn().mockReturnThis(),
  catch: jest.fn(),
}

jest.mock('aws-sdk', () => {
  return { S3: jest.fn(() => mockS3Instance) }
})

describe('S3', () => {
  it('calls aws-sdk copyObject method with correct parameters, async () => {
      await s3() // This is the function that uses the copyObject method

      expect(mockS3Instance.copyObject).toHaveBeenCalledWith({
        Bucket: 'some-bucket',
        CopySource: 'some-bucket/some/path/myfile.json,
        Key: 'some-bucket/some/other/path/myfile.json',
      })
      expect(mockS3Instance.copyObject).toHaveBeenCalledTimes(1)
   })
})

Some things to note

In the mockS3Instance I am using .mockReturnThis() . This is used to allow for chaining it to another method (in this case, promise which gets called like so: s3.copyObject(params).promise() in my code.

In the mockS3Instance , I have keys for promise and catch . This is because I was chaining copyObject with a promise() as well as a catch block, hence I’m mocking those out too.

Hope this helps someone! Thank you for reading.

Enjoyed this article?

Share it with your network to help others discover it

Continue Learning

Discover more articles on similar topics