dwyl / aws-sdk-mock

:rainbow: AWSomocks for Javascript/Node.js aws-sdk tested, documented & maintained. Contributions welcome!
Apache License 2.0
1.1k stars 109 forks source link

Unable to Mock DynamoDB.DocumentClient in Lambda with no explicit credentials #45

Open xavier-musy opened 8 years ago

xavier-musy commented 8 years ago

I'm trying to mock DynamoDB.DocumentClient, I've made sure to mock the nested service like the example in the help, as well as made sure DocumentClient is initialized in the function being tested.

I keep getting an error: ConfigError: Missing region in config at Request.VALIDATE_REGION

The only noteworthy detail is that I'm assuming an IAM role in in AWS, which means no credentials are explicitly set in code (this works in AWS).

b04zdotcom commented 7 years ago

I am currently experiencing the same problem, but can work around it by specifying the region like this:

const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' }); 
corroded commented 6 years ago

@boazdejong do you still do this? I feel like this defeats the purpose of mocking it? I have a feeling it actually does a request in AWS...

khrome83 commented 6 years ago

I am seeing the same issue - Response looks like ->

{"statusCode":400,"body":"{\"message\":\"Missing region in config\",\"code\":\"ConfigError\",\"time\":\"2018-07-12T01:51:30.647Z\"}"}{"statusCode":400,"body":"{\"message\":\"Missing region in config\",\"code\":\"ConfigError\",\"time\":\"2018-07-12T01:51:30.647Z\"}"}

So what is strange is that I setup my code and had everything working. The ONLY change I made was moving to a monorepo, installing lerna, and having children package.json in those folders. The root still contains the jest setup, which I run from root.

Test that mocks S3 works fine. Test that mocks DynamoDB gives me the region issue. To make things even more strange, all of these run fine on CircleCI but do not work locally.

iaindurham commented 6 years ago

The problem is most likely caused because you are initialising the service outside of the function being tested.

To quote the docs:

NB: The AWS Service needs to be initialised inside the function being tested in order for the SDK method to be mocked e.g for an AWS Lambda function example 1 will cause an error region not defined in config whereas in example 2 the sdk will be successfully mocked.

https://www.npmjs.com/package/aws-sdk-mock

The docs have examples of correct and incorrect ways of having your code setup.

To get around this issue I created a singleton that each of my DB methods call which caches the created documentClient. Then added a reset method so the tests can clear the cached documentClient.

import AWS from 'aws-sdk'

let createdClient

const createClient = () => {
  // Note: The document client needs to be created in a method so that it can be mocked in the tests
  createdClient = process.env.IS_OFFLINE ? new AWS.DynamoDB.DocumentClient({
    region: 'localhost',
    endpoint: 'http://localhost:8000'
  }) : new AWS.DynamoDB.DocumentClient()

  return createdClient
}

const client = () => (createdClient || createClient())

// This is needed for the tests to allow for the AWS.DynamoDB.DocumentClient to be mocked
export function resetClient() {
  createdClient = null
}

export const get = async ({ tableName, id }) => {
  const params = {
    TableName: tableName,
    Key: {
      id
    }
  }
  return client().get(params).promise()
}
dwjohnston commented 4 years ago

Ok, this has been driving me crazy:

I was able to reproduce this error this way:


import  * as  AWSMock from "aws-sdk-mock";
import  *  as AWS from "aws-sdk"; 

describe ("Mock invocation tests ", () => {

    it ("Should invoke the lambda", async () => {

        AWSMock.setSDKInstance(AWS);

        AWSMock.mock('Lambda', 'invoke', (params, cb) => {
            console.log("mock called", params);            
            cb(null, "hello");
        });

        const lambda = new AWS.Lambda(); 

        const result = await lambda.invoke({
          LogType: 'None',
          FunctionName: 'foo', 
          Payload: "foo"
        }).promise();       
    });

}); 
    ConfigError: Missing region in config

      at Request.VALIDATE_REGION (node_modules/aws-sdk/lib/event_listeners.js:92:45)
      at Request.callListeners (node_modules/aws-sdk/lib/sequential_executor.js:106:20)
      at callNextListener (node_modules/aws-sdk/lib/sequential_executor.js:96:12)
      at node_modules/aws-sdk/lib/event_listeners.js:86:9
      at finish (node_modules/aws-sdk/lib/config.js:386:7)
      at node_modules/aws-sdk/lib/config.js:404:9
      at SharedIniFileCredentials.get (node_modules/aws-sdk/lib/credentials.js:127:7)
      at getAsyncCredentials (node_modules/aws-sdk/lib/config.js:398:24)
      at Config.getCredentials (node_modules/aws-sdk/lib/config.js:418:9)
      at Request.VALIDATE_CREDENTIALS (node_modules/aws-sdk/lib/event_listeners.js:81:26)

The solution?

Change these:

import    AWSMock from "aws-sdk-mock";
import   AWS from "aws-sdk"; 

Anyone know why this is the case?

danshirley1 commented 3 years ago

My issue was I had two node_modules/aws-sdk/ installations:

/test/
/src/
---- node_modules/
-------- aws-sdk/

---- lambda/
-------- node_modules/
-------------- aws-sdk/

I remove the installation from /src/lambda, ran npm cache clear --force (maybe not required) and it fixed it for me.

This of course won't help you if you actually need those two separate installations.

s1mrankaur commented 3 years ago

Ok, this has been driving me crazy:

I was able to reproduce this error this way:


import  * as  AWSMock from "aws-sdk-mock";
import  *  as AWS from "aws-sdk"; 

describe ("Mock invocation tests ", () => {

    it ("Should invoke the lambda", async () => {

        AWSMock.setSDKInstance(AWS);

        AWSMock.mock('Lambda', 'invoke', (params, cb) => {
            console.log("mock called", params);            
            cb(null, "hello");
        });

        const lambda = new AWS.Lambda(); 

        const result = await lambda.invoke({
          LogType: 'None',
          FunctionName: 'foo', 
          Payload: "foo"
        }).promise();       
    });

}); 
    ConfigError: Missing region in config

      at Request.VALIDATE_REGION (node_modules/aws-sdk/lib/event_listeners.js:92:45)
      at Request.callListeners (node_modules/aws-sdk/lib/sequential_executor.js:106:20)
      at callNextListener (node_modules/aws-sdk/lib/sequential_executor.js:96:12)
      at node_modules/aws-sdk/lib/event_listeners.js:86:9
      at finish (node_modules/aws-sdk/lib/config.js:386:7)
      at node_modules/aws-sdk/lib/config.js:404:9
      at SharedIniFileCredentials.get (node_modules/aws-sdk/lib/credentials.js:127:7)
      at getAsyncCredentials (node_modules/aws-sdk/lib/config.js:398:24)
      at Config.getCredentials (node_modules/aws-sdk/lib/config.js:418:9)
      at Request.VALIDATE_CREDENTIALS (node_modules/aws-sdk/lib/event_listeners.js:81:26)

The solution?

Change these:

import    AWSMock from "aws-sdk-mock";
import   AWS from "aws-sdk"; 

Anyone know why this is the case?

Same problem. To keep the debugger working, I need to use import * as AWS from "aws-sdk" format but I started getting confg error in that case

cxk280 commented 3 years ago

My issue was I had two node_modules/aws-sdk/ installations:

/test/
/src/
---- node_modules/
-------- aws-sdk/

---- lambda/
-------- node_modules/
-------------- aws-sdk/

I remove the installation from /src/lambda, ran npm cache clear --force (maybe not required) and it fixed it for me.

This of course won't help you if you actually need those two separate installations.

This was my problem. Almost impossible to debug, yet a common pattern if you've got a folder for serverless somewhere in your repo. Never would have figured it out without seeing the above. I fixed it by adding a separate folder for tests inside my serverless folder.

shcheuk commented 3 years ago

It may also happen when you forget to mock one of the functions. It easy to happen when you have a lot of functions to mock. For example, you mocked CloudWatch.describeAlarms, Kinesis.describeStream, Kinesis.updateShardCount, CloudWatch.putMetricAlarm and 10 of others when you create the project, you also added Kinesis.describeStreamSummary recently but you haven't tested it. A few weeks later, u try a last jest test before your boss ask you to merge...boom. The error won't be "You forget to mock the last functions you just added.", but"AWS region not set"

OllyNural commented 2 years ago

My issue was I had two node_modules/aws-sdk/ installations:

/test/
/src/
---- node_modules/
-------- aws-sdk/

---- lambda/
-------- node_modules/
-------------- aws-sdk/

I remove the installation from /src/lambda, ran npm cache clear --force (maybe not required) and it fixed it for me.

This of course won't help you if you actually need those two separate installations.

Similar problem, and this solved it. I had an import of aws-lambda as a dev dependency within a child module of a lerna monorepo, with jest and aws-sdk-mock installed at the root level and linked down using link-parent-bin

Removing aws-lambda dev dependency solved the issue.

lquanx commented 1 year ago

It may also happen when you forget to mock one of the functions. It easy to happen when you have a lot of functions to mock. For example, you mocked CloudWatch.describeAlarms, Kinesis.describeStream, Kinesis.updateShardCount, CloudWatch.putMetricAlarm and 10 of others when you create the project, you also added Kinesis.describeStreamSummary recently but you haven't tested it. A few weeks later, u try a last jest test before your boss ask you to merge...boom. The error won't be "You forget to mock the last functions you just added.", but"AWS region not set"

Thanks very much. This answer and this answer solved my issue with Missing region in config