How to mock AWS SDK with Jest
Tags: devjournal, javascript, testing, aws
Published: 2022-06-24 09:42:58

---
title: How to mock AWS SDK with Jest
published: true
tags: devjournal, javascript, testing, AWS
---

From me to future me - how to write unit test for AWS SDK S3 presigned url with Jest


Dear Journal 📖

From me to future me: how to write unit test for AWS SDK S3 by example (presigned url with Jest).

I hate mocks. 
That's why I always forgot how to use them when I need them.

Oh Rita, have you tried to `spyOn` AWS SDK service again? 🤦‍♀️

🛑 STOP 

You need to either:

- mock element on the object (when you have an object)
- mock whole file (`@aws-sdk/s3-request-presigner`). I do hate that, but I guess you don't have that much choice, unless you want to wrap it in something else 🤷‍♂️

This is one of the reasons OOP and dependency injection (even manual one) is better (personal preference). I can define unit, its dependencies and then in tests I simply **deliver something that fulfils the contract**. No need to overwrite objects, files, etc. 🚫 **No mocks**.

But sometimes there's no other option.


Let's say I have a javascript or typescript file.

```typescript
// handler.ts

import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { GetObjectCommand } from '@aws-sdk/client-s3';

export const handler: Handler = async () => {
  /* do stuff */
  const command = new GetObjectCommand(input);
  const url = await getSignedUrl(client, command, { expiresIn: 1200 });
  /* do other stuff */
}

```


Then in spec file: 
- create an mock of whole the module
- use empty mock function as you wish

```typescript
// handler.spec.ts

jest.mock('@aws-sdk/s3-request-presigner');
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

jest.mock('@aws-sdk/client-s3');
import { GetObjectCommand } from '@aws-sdk/client-s3';

import { handler } from './handler';

test('when sth do sth', async () => {
  const expectedInput = { ... };
  await handler();
  expect(GetObjectCommand).toHaveBeenCalledWith(expectedInput);
  expect(getSignedUrl).toHaveBeenCalled();
});

```

Honestly, it doesn't test this function. The fact that sth was called is not enough to confirm that expected behavior happened. It comes to the absurd: to get "real" behavior I need to mock the `getSignerUrl()` response. 

So, I come to the point, where I write the mock, to test the function response, which is response from another mock, but technically is the nearest simulation of the function response and expected output. 

```typescript
// handler.spec.ts

jest.mock('@aws-sdk/s3-request-presigner');
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

jest.mock('@aws-sdk/client-s3');
import { GetObjectCommand } from '@aws-sdk/client-s3';

import { handler } from './handler';
describe('GetUrl', () => {
  const getSignedUrlMock: jest.Mock = getSignedUrl as any; // calm down TypeScript screaming about types

  test('when sth do sth', async () => {
    getSignedUrlMock.mockResolvedValue('example-url.com');
    const expectedInput = { ... };
    const response = await handler();
  
  expect(GetObjectCommand).toHaveBeenCalledWith(expectedInput);
    expect(response).toEqual({
      statusCode: 200,
      body: JSON.stringify({ url: 'example-url.com' }),
    });
  });
});
```

Hope, that next time you will thank yourself for this

Sincerely yours 
Rita