3

I try to mock s3 upload function with this instruction but when I use this pattern a have an

TypeError: s3.upload is not a function

// upload.test.js
const AWS = require('aws-sdk');
jest.mock('aws-sdk', () => {
  const mS3 = { upload: jest.fn().mockReturnThis(), promise: jest.fn() };
  return { S3: jest.fn(() => mS3) };
});

const s3 = new AWS.S3();
s3.upload({}).promise.mockResolvedValueOnce({ Bucket: 'XXX' });

I'm using also SQS and with this pattern I have another error:

AWS.SQS is not a constructor

How I can handle with it?

// upload.js
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
s3Params = {
        Bucket: S3_BUCKET,
        Key: `example.xml`,
        ACL: 'public-read',
        ContentType: 'application/json',
        Body: Buffer.from(file)
      }
    }
await s3.upload(s3Params).promise();
skyboyer
  • 22,209
  • 7
  • 57
  • 64
Robert Rząd
  • 31
  • 1
  • 4

2 Answers2

1

when using Jest .mockReturnValueOnce, you need to execute the mock AFTER that value is set to be able to receive the value you defined in mockReturnValueOnce as a response,

for example, mocking S3:

// s3-mock.test.js
let AWS = require('aws-sdk');

jest.mock('aws-sdk', () => {
  let instance = {
    upload: jest.fn().mockReturnThis(),
    promise: jest.fn(),
  };
  return { S3: jest.fn(() => instance) };
});


describe("setup for s3.upload testing", () => {
  let testS3;
  beforeEach(() => {
    testS3 = new AWS.S3();
    testS3.promise.mockReturnValueOnce({ Bucket: 'TestBucketName' });
  })

  test('returns expected upload value', async () => {
    let params = {};
    let result = await testS3.upload(params).promise();
    expect(result).toEqual({ Bucket: 'TestBucketName' });
    expect(result.Bucket).toBe("TestBucketName")
  });
});

and mocking SQS:

// sqs-mock.test
let AWS = require('aws-sdk');

jest.mock('aws-sdk', () => {
  let instance = {
    sendMessage: jest.fn().mockReturnThis(),
    promise: jest.fn(),
  };
  return { SQS: jest.fn(() => instance) };
});


describe("setup for sqs.sendMessage testing", () => {
  let testSQS;
  beforeEach(() => {
    testSQS = new AWS.SQS();
    testSQS.promise.mockReturnValueOnce({ MessageId: 'TestSQSId' });
  })

  test('returns expected message id', async () => {
    let params = {};
    let result = await testSQS.sendMessage(params).promise();
    expect(result).toEqual({ MessageId: 'TestSQSId' });
    expect(result.MessageId).toBe("TestSQSId")
  });
});

working example on https://github.com/oieduardorabelo/jest-mock-aws-sdk

as you can see, they are identical, you can also use manual mocks in Jest with a folder __mocks__ with all packages you and to mock in your tests, have a look at the docs on: https://jestjs.io/docs/manual-mocks

oieduardorabelo
  • 2,687
  • 18
  • 21
-1

Instead of aws-sdk try using aws-sdk/clients/s3.

elcortegano
  • 2,444
  • 11
  • 40
  • 58