How to mock S3 with jest?
17,950
Solution 1
Here is the unit test solution:
s3Service.ts:
import { S3 } from 'aws-sdk';
export class S3Service {
private readonly s3: S3;
private readonly bucket: string;
constructor(private readonly configService) {
this.s3 = new S3({
accessKeyId: this.configService.get(''),
secretAccessKey: this.configService.get(''),
region: this.configService.get(''),
});
this.bucket = this.configService.get('');
}
public async upload(name: string, contentType: string, buffer: Buffer): Promise<any> {
const bucket = this.bucket;
const params = { Bucket: bucket, Key: 'key', Body: buffer };
const upload = await this.s3.upload(params).promise();
return upload;
}
}
s3Service.test.ts:
import { S3Service } from './s3Service';
const mS3Instance = {
upload: jest.fn().mockReturnThis(),
promise: jest.fn(),
};
jest.mock('aws-sdk', () => {
return { S3: jest.fn(() => mS3Instance) };
});
describe('61830632', () => {
it('should upload correctly', async () => {
const configService = {
get: jest
.fn()
.mockReturnValueOnce('accessKeyId')
.mockReturnValueOnce('secretAccessKey')
.mockReturnValueOnce('us-east')
.mockReturnValueOnce('bucket-dev'),
};
mS3Instance.promise.mockResolvedValueOnce('fake response');
const s3Service = new S3Service(configService);
const actual = await s3Service.upload('name', 'contentType', Buffer.from('ok'));
expect(actual).toEqual('fake response');
expect(mS3Instance.upload).toBeCalledWith({ Bucket: 'bucket-dev', Key: 'key', Body: Buffer.from('ok') });
});
});
unit test results with 100% coverage:
PASS stackoverflow/61830632/s3Service.test.ts (11.362s)
61830632
✓ should upload correctly (6ms)
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
s3Service.ts | 100 | 100 | 100 | 100 |
--------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 12.738s
Solution 2
Here is my solution:
jest.mock('aws-sdk', () => {
class mockS3 {
getSignedUrl(op, obj) {
return 'url';
}
}
return {
...jest.requireActual('aws-sdk'),
S3: mockS3,
};
});
Author by
luickx
Updated on June 10, 2022Comments
-
luickx 12 monthsI am tryng to code a test for upload. But i am not understating how to properly use
jest.mock('aws-sdk')export class S3Service { private readonly s3: S3; private readonly bucket: string; constructor(private readonly configService: ConfigService) { this.s3 = new S3({ accessKeyId: this.configService.get(''), secretAccessKey: this.configService.get(''), region: this.configService.get(''), }); this.bucket = this.configService.get(''); } async upload(name: string, contentType: string, buffer: Buffer): Promise<string> { const upload = await this.s3.upload({params...}).promise(); return upload; } } -
cischa over 2 yearsThanks for the illustrative answer. Conceptually, what doesjest.fn().mockReturnThis()do? Does it let you chain calls? -
slideshowp2 over 2 years@cischa Yes. It let you chain calls. -
Benjamin Heinke over 2 years@slideshowp2 Copying your code in my test returns this error from jest: ReferenceError: .../__tests__/user_handler.spec.ts: The module factory ofjest.mock()is not allowed to reference any out-of-scope variables. Invalid variable access: mS3Instance Allowed objects: Array, ArrayBuffer, Atomics, BigInt, BigInt64Array, BigUint64Array, Boolean, Buffer, DTRACE_HTTP_CLIENT_REQUEST, DTRACE_HTTP_CLIENT_RESPONSE, DTRACE_HTTP_SERVER_REQUEST, DTRACE_HTTP_SERVER_RESPONSE, DTRACE_NET_SERVER_CONNECTION, DTRACE_NET_STREAM_END, DataView, Date, Error, EvalError,..... -
timomeinen over 2 years@BenjaminHeinke This is just a warning. RenamemS3Instanceto something that begins withmock- for examplemockS3. -
Elte156 over 1 yearThanks for this. I can confirm that the above works. -
Kaluk 12 monthsMan that was a life saver thank you very much. I've worked with NestJS services in my other tests but for some reason i went full retard when dealing with S3, if only i had realized sooner that there was an easier way.