Testing an s3 upload? The method to test is
export class ProcessData {
constructor() {}
async process(): Promise<void> {
const data = await s3Client.send(new GetObjectCommand(bucket));
await parseCsvData(data.Body)
}
This is my attempt at the test case.
import {S3Client} from '@aws-sdk/client-s3';
jest.mock("aws-sdk/clients/s3", () => {
return {
S3Client: jest.fn(() => {
send: jest.fn().mockImplementation(() => {
data: Buffer.from(require("fs").readFileSync(path.resolve(__dirname, "test.csv")));
})
})
}
});
describe("@aws-sdk/client-s3 mock", () => {
test('CSV Happy path', async () => {
const processData = new ProcessData()
await processData.process()
}
}
The process gets to the parse method and throws an error "The bucket you are attempting to access must be addressed using the specific endpoint"
For anyone who wants to mock the client directly, you can use the library aws-sdk-client-mock which is recommended by the AWS SDK team.
Here is an introductory tutorial
The initial steps:
import fs from 'fs';
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { mockClient } from 'aws-sdk-client-mock';
const mockS3Client = mockClient(S3Client);
And then you can mock it this way
mockS3Client.on(GetObjectCommand).resolves({
Body: fs.createReadStream('path/to/some/file.csv'),
});
You can also spy on the client
const s3GetObjectStub = mockS3Client.commandCalls(GetObjectCommand)
// s3GetObjectStub[0] here refers to the first call of GetObjectCommand
expect(s3GetObjectStub[0].args[0].input).toEqual({
Bucket: 'foo',
Key: 'path/to/file.csv'
});
Since version 3.188.0 (Oct 22), the S3 client supports util functions to consume and parse the response streams.
So now, to mock the response, we need to wrap it with the util function sdkStreamMixin()
from @aws-sdk/util-stream-node
As mentioned by @Matthew Woo, the @aws-sdk/util-stream-node
package is deprecated and we should use the sdkStreamMixin()
function from @smithy/util-stream
instead
import fs from 'fs';
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import {sdkStreamMixin} from '@smithy/util-stream';
import { mockClient } from 'aws-sdk-client-mock';
const mockS3Client = mockClient(S3Client);
const stream = sdkStreamMixin(fs.createReadStream('path/to/some/file.csv'))
mockS3Client.on(GetObjectCommand).resolves({
Body: stream ,
});
The current docs for aws-sdk-client-mock
for this are a little more complex:
import {GetObjectCommand, S3Client} from '@aws-sdk/client-s3';
import {sdkStreamMixin} from '@smithy/util-stream';
import {mockClient} from 'aws-sdk-client-mock';
import {Readable} from 'stream';
import {createReadStream} from 'fs';
const s3Mock = mockClient(S3Client);
it('mocks get object', async () => {
// create Stream from string
const stream = new Readable();
stream.push('hello world');
stream.push(null); // end of stream
// alternatively: create Stream from file
// const stream = createReadStream('./test/data.txt');
// wrap the Stream with SDK mixin
const sdkStream = sdkStreamMixin(stream);
s3Mock.on(GetObjectCommand).resolves({Body: sdkStream});
const s3 = new S3Client({});
const getObjectResult = await s3.send(new GetObjectCommand({Bucket: '', Key: ''}));
const str = await getObjectResult.Body?.transformToString();
expect(str).toBe('hello world');
});