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.
E.g.
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