简体   繁体   中英

aws-sdk-mock - Mocking s3.upload is not using mock implementation

I'm using this wrapper function to upload objects to s3

// upload.js
async function uploadToS3 (body, bucket, key) {
    console.log(`Uploading data to s3://${bucket}${key}`)
    await s3
        .upload({
                Body: body,
                Bucket: bucket,
                Key: key
            })
        .promise()
        .then((data) => {
                console.log(`Successfully uploaded data to ${data.Location}`)
            }
        )
        .catch((err) => {
            console.error(err)
        })
}

And I'm trying to use aws-sdk-mock to mock the function so when it is called it does not actually push items to s3 and I can verify that it is logging a success or failure.

Here is what I have tried

// upload.test.js

describe( 'uploadToS3', () => {
    test('should upload a file to s3', async () => {
        const body = 'test|data'
        const bucket = 'testBucket'
        const key = 'testKey'

        AWS.mock( 'S3', 'upload',function (params, callback){
            callback(null, 'successfully put item in s3');
        });

        await util.uploadToS3(body, bucket, key)
    })
})

Unfortunately, when I call the uploadToS3 function it still uses the actual s3.upload implementation and attempts to send the object to S3. I've used similar mocking methods with other AWS services with success but this one seems to be giving me issues.

How can I mock AWS.S3.upload function and the subsequent .then and .catch functions?

Maybe this is possible instead with Jest?

You don't need to use aws-sdk-mock package. You can use jest.mock(moduleName, factory, options) method to mock aws-sdk package by yourself.

Eg

upload.js :

import AWS from 'aws-sdk';

const s3 = new AWS.S3();

export async function uploadToS3(body, bucket, key) {
  console.log(`Uploading data to s3://${bucket}${key}`);
  await s3
    .upload({
      Body: body,
      Bucket: bucket,
      Key: key,
    })
    .promise()
    .then((data) => {
      console.log(`Successfully uploaded data to ${data.Location}`);
    })
    .catch((err) => {
      console.error(err);
    });
}

upload.test.js :

import { uploadToS3 } from './upload';
import AWS from 'aws-sdk';

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

describe('uploadToS3', () => {
  afterAll(() => {
    jest.resetAllMocks();
  });
  afterEach(() => {
    jest.clearAllMocks();
  });
  it('should upload file to s3', async () => {
    const mockedS3 = new AWS.S3();
    const logSpy = jest.spyOn(console, 'log');
    mockedS3.promise.mockResolvedValueOnce({ Location: 'us' });
    const body = 'test|data';
    const bucket = 'testBucket';
    const key = 'testKey';
    await uploadToS3(body, bucket, key);
    expect(mockedS3.upload).toBeCalledWith({ Body: body, Bucket: bucket, Key: key });
    expect(mockedS3.promise).toBeCalledTimes(1);
    expect(logSpy).toBeCalledWith('Successfully uploaded data to us');
  });

  it('should handle error when upload file to s3 failed', async () => {
    const mockedS3 = new AWS.S3();
    const errorLogSpy = jest.spyOn(console, 'error');
    const mError = new Error('network');
    mockedS3.promise.mockRejectedValueOnce(mError);
    const body = 'test|data';
    const bucket = 'testBucket';
    const key = 'testKey';
    await uploadToS3(body, bucket, key);
    expect(mockedS3.upload).toBeCalledWith({ Body: body, Bucket: bucket, Key: key });
    expect(mockedS3.promise).toBeCalledTimes(1);
    expect(errorLogSpy).toBeCalledWith(mError);
  });
});

unit test result:

 PASS  examples/67204024/upload.test.js (6.42 s)
  uploadToS3
    ✓ should upload file to s3 (16 ms)
    ✓ should handle error when upload file to s3 failed (6 ms)

  console.log
    Uploading data to s3://testBuckettestKey

      at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)

  console.log
    Successfully uploaded data to us

      at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)

  console.log
    Uploading data to s3://testBuckettestKey

      at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)

  console.error
    Error: network
        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:35:20
        at Generator.next (<anonymous>)
        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:8:71
        at new Promise (<anonymous>)
        at Object.<anonymous>.__awaiter (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:4:12)
        at Object.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:32:70)
        at Object.asyncJestTest (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
        at new Promise (<anonymous>)
        at mapper (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
        at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
        at processTicksAndRejections (internal/process/task_queues.js:93:5)

      16 |     })
      17 |     .catch((err) => {
    > 18 |       console.error(err);
         |               ^
      19 |     });
      20 | }
      21 | 

      at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
      at examples/67204024/upload.js:18:15

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        6.896 s, estimated 7 s

This is also an option

    const getObjectStub = AWS.S3.prototype.getObject = Sinon.stub();
    getObjectStub.yields(null, {
    AcceptRanges: "bytes", 
    ContentLength: 3191, 
    ContentType: "image/jpeg", 
    Metadata: {
    }, 
    TagCount: 2, 
    VersionId: "null"
   }
);

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