1

I read Jest Mock Promise with Params and am having basically the same code snippet, but it keeps throwing me error "ParameterNotFound"

// -- test code --

  it("get parameter", async done => {
    const paramsForGetParam = {
      Name: "StripeSecretKey",
      WithDecryption: true
    };

    const mockedResponseData = {
      Parameter: {
        Name: "StripeSecretKey",
        Type: "SecureString",
        Value: "myVal",
        Version: 1,
        LastModifiedDate: 1530018761.888,
        ARN: "arn:aws:ssm:us-east-1:123456789012:parameter/helloSecureWorld"
      }
    };

    // ssm.getParameter().promise = jest.fn();
    ssm.getParameter = jest.fn();
    ssm.getParameter.mockImplementation(() => ({
      promise: jest
        .fn()
        .mockImplementation(() => Promise.resolve(mockedResponseData))
    }));
    ssm
      .getParameter()
      .promise.mockImplementation(() => Promise.resolve(mockedResponseData));

    const data = await helpers.getSsmVar("StripeSecretKey");
    expect(data).toEqual(mockedResponseData.Parameter.Value);
    expect(ssm.getParameter).toHaveBeenCalledTimes(1);
    done();
  });

Here is my dev code:

const aws = require("aws-sdk");
aws.config.update({ region: "us-east-1" });
const ssm = new aws.SSM();
const baseSsm = `/mybox/`;

module.exports = {
  getSsmVar: async function(name) {
    var params = {
      Name: baseSsm + name,
      WithDecryption: true
    };
    var request = await ssm.getParameter(params).promise();
    return request;
  }
};

but it keeps failing with below without telling me what parameter is not found.aws said to check the name parameter but I think the name (params.Name) is correct?

  ● Helpers Tests › get parameter

    ParameterNotFound: 

      at Request.extractError (node_modules/aws-sdk/lib/protocol/json.js:50:27)
      at Request.callListeners (node_modules/aws-sdk/lib/sequential_executor.js:112:20)
      at Request.emit (node_modules/aws-sdk/lib/sequential_executor.js:77:10)
      at Request.emit (node_modules/aws-sdk/lib/request.js:713:14)
      at Request.transition (node_modules/aws-sdk/lib/request.js:25:10)
Lin Du
  • 88,126
  • 95
  • 281
  • 483
Gohawks
  • 361
  • 2
  • 6
  • 14
  • `ssm` seems to be local to your dev code, so it does not seem possible to mock `sms.getParameter` from your test code. Where does the `ssm` variable in your test code come from? I guess the real implementation is called, causing the error. – Sergio Mazzoleni Jun 30 '19 at 12:10
  • It’s also defined as ssm=new aws.SSM. Didn’t I have ssm.getParameter=jest.fn()? – Gohawks Jun 30 '19 at 12:58
  • So, you are mocking a method on a different instance of ssm, and your mocked implementation will never be called by your dev code. You might consider exporting the ssm instance from your dev code – Sergio Mazzoleni Jun 30 '19 at 16:20
  • I think you are spot on. I tried move line ``` const ssm = new aws.SSM() ``` from the 3rd line to the first line after ```getSsmVar: async function(name) { ``` and it magically worked! What's the difference between them? ssm works in function scope but not global scope in mocking? – Gohawks Jun 30 '19 at 17:35

2 Answers2

5

Here is the solution, you can use jest.mock() mock aws-sdk manually.

index.js:

const aws = require('aws-sdk');
aws.config.update({ region: 'us-east-1' });
const ssm = new aws.SSM();
const baseSsm = `/mybox/`;

module.exports = {
  async getSsmVar(name) {
    const params = {
      Name: baseSsm + name,
      WithDecryption: true
    };
    const request = await ssm.getParameter(params).promise();
    return request;
  }
};

index.spec.js:

jest.mock('aws-sdk', () => {
  const mockedSSM = {
    getParameter: jest.fn().mockReturnThis(),
    promise: jest.fn()
  };
  const mockedConfig = {
    update: jest.fn()
  };
  return {
    SSM: jest.fn(() => mockedSSM),
    config: mockedConfig
  };
});

const helpers = require('.');
const aws = require('aws-sdk');
const ssm = new aws.SSM();

describe('helpers', () => {
  it('get parameter', async () => {
    const mockedResponseData = {
      Parameter: {
        Name: 'StripeSecretKey',
        Type: 'SecureString',
        Value: 'myVal',
        Version: 1,
        LastModifiedDate: 1530018761.888,
        ARN: 'arn:aws:ssm:us-east-1:123456789012:parameter/helloSecureWorld'
      }
    };

    ssm.getParameter().promise.mockResolvedValueOnce(mockedResponseData);
    const data = await helpers.getSsmVar('StripeSecretKey');
    expect(data).toEqual(mockedResponseData);
    expect(ssm.getParameter).toBeCalledWith({ Name: `/mybox/StripeSecretKey`, WithDecryption: true });
    expect(ssm.getParameter().promise).toBeCalledTimes(1);
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/56821395/index.spec.js
  helpers
    ✓ get parameter (8ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.js |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.872s

Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/56821395

Lin Du
  • 88,126
  • 95
  • 281
  • 483
0

For me it works mocking the function, like this.

route53.createHostedZone = jest.fn().mockImplementation(() => ({
    promise: jest.fn().mockResolvedValue(mockCreatedHostedZone),
}));