Skip to content

Commit

Permalink
feat: helper to mock @aws-sdk/lib-storage Upload (#47)
Browse files Browse the repository at this point in the history
* feat: helper to mock @aws-sdk/lib-storage Upload

* fix: bump tsd to ignore type errors in node_modules

* fix: add @aws-sdk/client-s3 to peerDependencies
  • Loading branch information
m-radzikowski authored Sep 16, 2021
1 parent 537380d commit 10780e8
Show file tree
Hide file tree
Showing 6 changed files with 1,020 additions and 942 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ In action:
- [Import](#import)
- [Mock](#mock)
- [DynamoDB DocumentClient](#dynamodb-documentclient)
- [Lib Storage Upload](#lib-storage-upload)
- [Paginated operations](#paginated-operations)
- [API Reference](#api-reference)
- [AWS Lambda example](#aws-lambda-example)
Expand Down Expand Up @@ -239,6 +240,39 @@ ddbMock.on(QueryCommand).resolves({
});
```

#### Lib Storage Upload

To mock `@aws-sdk/lib-storage` `Upload` you need to call
a helper function `mockLibStorageUpload()`
that will configure required S3Client command mocks:

```typescript
import {mockLibStorageUpload} from 'aws-sdk-client-mock';
import {Upload} from '@aws-sdk/lib-storage';
import {S3Client} from '@aws-sdk/client-s3';

const s3Mock = mockClient(S3Client);
mockLibStorageUpload(s3Mock);

const s3Upload = new Upload({
client: new S3Client({}),
params: {
Bucket: 'mock',
Key: 'test',
Body: 'x'.repeat(6 * 1024 * 1024), // 6 MB
},
});

s3Upload.on('httpUploadProgress', (progress) => {
console.log(progress);
});

await s3Upload.done();
```

You can call `mockLibStorageUpload()` without providing an S3Client mock.
In that case, the client mock will be created and returned from the function.

#### Paginated operations

To mock a [paginated operation](https://aws.amazon.com/blogs/developer/pagination-using-async-iterators-in-modular-aws-sdk-for-javascript/)
Expand Down
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,17 @@
"tslib": "^2.1.0"
},
"peerDependencies": {
"@aws-sdk/client-s3": "^3.0.0",
"@aws-sdk/types": "^3.0.0"
},
"devDependencies": {
"@aws-sdk/types": "^3.18.0",
"@aws-sdk/client-dynamodb": "^3.18.0",
"@aws-sdk/client-sns": "^3.18.0",
"@aws-sdk/client-sqs": "^3.18.0",
"@aws-sdk/lib-dynamodb": "^3.18.0",
"@aws-sdk/client-dynamodb": "3.31.0",
"@aws-sdk/client-s3": "3.31.0",
"@aws-sdk/client-sns": "3.31.0",
"@aws-sdk/client-sqs": "3.31.0",
"@aws-sdk/lib-dynamodb": "3.31.0",
"@aws-sdk/lib-storage": "3.31.0",
"@aws-sdk/types": "3.29.0",
"@commitlint/cli": "11.0.0",
"@commitlint/config-conventional": "11.0.0",
"@size-limit/preset-small-lib": "4.10.2",
Expand All @@ -71,7 +74,7 @@
"standard-version": "9.1.0",
"ts-jest": "26.5.0",
"ts-node": "10.0.0",
"tsd": "0.16.0",
"tsd": "0.17.0",
"typedoc": "0.20.35",
"typescript": "4.2.4"
},
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './mockClient';
export * from './awsClientStub';
export * from './libStorage';
21 changes: 21 additions & 0 deletions src/libStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {AwsClientStub} from './awsClientStub';
import {CreateMultipartUploadCommand, S3Client, UploadPartCommand} from '@aws-sdk/client-s3';
import {mockClient} from './mockClient';

/**
* Configures required command mocks of the S3Client mock to support Lib Storage Upload helper
* for multipart file upload.
*
* If S3Client mocks is not provided, a new one is created.
* @param s3Mock S3Client mock created with {@link mockClient} function
*/
export const mockLibStorageUpload = (s3Mock?: AwsClientStub<S3Client>): AwsClientStub<S3Client> => {
if (!s3Mock) {
s3Mock = mockClient(S3Client);
}

s3Mock.on(CreateMultipartUploadCommand).resolves({UploadId: '1'});
s3Mock.on(UploadPartCommand).resolves({ETag: '1'});

return s3Mock;
};
88 changes: 88 additions & 0 deletions test/libStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {Progress, Upload} from '@aws-sdk/lib-storage';
import {S3Client} from '@aws-sdk/client-s3';
import {AwsClientStub, mockClient, mockLibStorageUpload} from '../src';

let s3Mock: AwsClientStub<S3Client>;

afterEach(() => {
s3Mock.restore();
});

it('mocks small file upload to S3', async () => {
s3Mock = mockClient(S3Client);
mockLibStorageUpload(s3Mock);

const s3Upload = new Upload({
client: new S3Client({}),
params: {
Bucket: 'mock',
Key: 'test',
Body: 'qwe',
},
});

const uploadProgress: Progress[] = [];
s3Upload.on('httpUploadProgress', (progress) => {
uploadProgress.push(progress);
});

await s3Upload.done();

expect(uploadProgress).toHaveLength(1);
expect(uploadProgress[0]).toStrictEqual({
Bucket: 'mock',
Key: 'test',
loaded: 3,
total: 3,
part: 1,
});
});

it('mocks multipart upload to S3', async () => {
s3Mock = mockClient(S3Client);
mockLibStorageUpload(s3Mock);

const s3Upload = new Upload({
client: new S3Client({}),
partSize: 5 * 1024 * 1024, // 5 MB
params: {
Bucket: 'mock',
Key: 'test',
Body: 'x'.repeat(6 * 1024 * 1024), // 6 MB
},
});

const uploadProgress: Progress[] = [];
s3Upload.on('httpUploadProgress', (progress) => {
uploadProgress.push(progress);
});

await s3Upload.done();

expect(uploadProgress).toHaveLength(2);
});

it('mocks multipart upload to S3 without explicit client mock', async () => {
const localS3Mock = mockLibStorageUpload();

const s3Upload = new Upload({
client: new S3Client({}),
partSize: 5 * 1024 * 1024, // 5 MB
params: {
Bucket: 'mock',
Key: 'test',
Body: 'x'.repeat(6 * 1024 * 1024), // 6 MB
},
});

const uploadProgress: Progress[] = [];
s3Upload.on('httpUploadProgress', (progress) => {
uploadProgress.push(progress);
});

await s3Upload.done();

expect(uploadProgress).toHaveLength(2);

localS3Mock.restore();
});
Loading

0 comments on commit 10780e8

Please sign in to comment.