2

I'm working with Jest to mock my AWS services, and more specifically DynamoDB and DynamoDBDocumentClient.

My code is currently similar to this :

import { DynamoDBClient } from "@aws-sdk/client-dynamodb"
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"
const ddbClient = new DynamoDBClient({})
const ddbDocumentClient = DynamoDBDocumentClient.from(ddbClient, config)

and the test spec looks like this:

jest.mock("@aws-sdk/client-dynamodb", () => ({
  DynamoDBClient: jest.fn(() => ({
    put: (params) => mockAwsResponse("DynamoDBClient", "GetCommand", params),
    put: (params) => mockAwsResponse("DynamoDBClient", "PutCommand", params),
  })),
}))

jest.mock("@aws-sdk/lib-dynamodb", () => ({
  DynamoDBDocumentClient: jest.fn(() => ({
    get: (params) => console.log("In DynamoDBClient get", params),
    put: (params) => mockAwsResponse("DynamoDBDocumentClient", "PutCommand", params),
    from: (params) => mockAwsResponse("DynamoDBDocumentClient", "from", params),
  })),
}))

Unfortunately Jest returns me this error : TypeError: lib_dynamodb_1.DynamoDBDocumentClient.from is not a function and I believe it's because I'm incorrectly mocking DynamoDBDocumentClient, as its constructor is a static method.

Thanks in advance for your help!

EDIT: Just noticed that it used the AWS SDK v3 for JavaScript, if that helps.

Fares
  • 893
  • 1
  • 11
  • 24
  • Have you taken a look at other questions regarding mocking DynamoDBDocumentClient? Do they not solve your problem? – Ermiya Eskandary Nov 08 '21 at 13:55
  • I have, they do not answer my question. The closest topic I've seen is [this](https://stackoverflow.com/questions/57811178/mock-the-constructor-for-aws-dynamodb-documentclient-using-jest) one but it doesn't match my situation exactly. – Fares Nov 08 '21 at 14:02
  • Do you *need* to use `DynamoDBDocumentClient.from`? – Ermiya Eskandary Nov 08 '21 at 14:11
  • I didn't develop this code, so I may be wrong. But from what I've understood, the previous developer wanted to create a `DynamoDBDocumentClient` with a specific config, and that required using a `DynamoDBClient`, hence them creating an empty one and providing the `config` in it. – Fares Nov 08 '21 at 14:27
  • I am wondering the exact same thing, any solutions yet? @Fares – BuruY Jan 11 '22 at 10:10
  • Hey @BuruY, I went with this package ("aws-sdk-client-mock"), it was very helpful! Hope I could be of help! – Fares Jan 11 '22 at 13:02

1 Answers1

2

In your example, you import your modules and run call your constructor right away (before entering any method in your script), this means that the object you are trying to mock needs to be available before entering any test methods. Try to place your mocks before (and outside of) your tests something like this:

import { DynamoDBClient } from "@aws-sdk/client-dynamodb"
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"

/* whatever constants you need for your mocks */

jest.mock('@aws-sdk/client-dynamodb', () => {
  return {
    DynamoDBClient: jest.fn().mockImplementation(() => {
      return {};
    }),
  };
});
jest.mock('@aws-sdk/lib-dynamodb', () => {
  return {
    DynamoDBDocumentClient: {
      from: jest.fn().mockImplementation(() => {
        return {
          send: jest.fn().mockImplementation((command) => {
            let res = 'something';
            if(command.name == 'GetCommand'){
               res = 'something else (a constant from earlier...)';
            }
            /* return whatever needs to be returned... */
            return Promise.resolve(res);
          }),
        };
      }),
    },
    /* Return your other docClient methods here too... */
    GetCommand: jest.fn().mockImplementation(() => {
      return { name: 'GetCommand' };
    }),
  };
});

// then you can implement your tests
describe('Endpoint something', () => {
  it('Should pass or something...', async () => {
    /* your test here... */
  });
});

Now your functions should be available when they are needed.

brainstormtrooper
  • 485
  • 2
  • 6
  • 18