Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to mock Secrets Manager with ESM #232

Open
1 task done
jove4015 opened this issue Jul 10, 2024 · 2 comments
Open
1 task done

Unable to mock Secrets Manager with ESM #232

jove4015 opened this issue Jul 10, 2024 · 2 comments
Labels
bug Something isn't working waiting for reply

Comments

@jove4015
Copy link

jove4015 commented Jul 10, 2024

Checklist

  • I have read Caveats documentation and didn't find a solution for this problem there.

Bug description

Using ts-jest with experimental ESM support enabled, I am struggling to mock the SecretsManager. I have been able to get other AWS services to mock properly in this same ecosystem, so I'm not sure what about SecretsManager is different.

(see Example 1 below)

This simple, all in one file test fails:

    expect(received).toBe(expected) // Object.is equality

    Expected: "test_secret"
    Received: undefined

      814 |     console.log(result);
      815 |
    > 816 |     expect(result).toBe("test_secret");
          |                    ^
      817 |   });
      818 | });
      819 |

It detects that the command was called but doesn't get the resolved value it should have.

When I try to use this in a real test, where the credentials are being pulled in a separate class that I'm testing, the test fails and I see the error "CredentialsProviderError: Could not load credentials from any providers":

(see example 2 below)

When you inspect the mock in this scenario, you'll see that the mock never registered any command being run (ie, secretsManagerMock.commandCalls(GetSecretValueCommand).length == 0).

I have also tried moving the mock creation code to a jest setup file as was suggested in this previous issue. However, that didn't change this behavior at all. The mock was not used unless it was declared in the same file with the actual invocation.

Reproduction

// Example 1:

import { mockClient } from "aws-sdk-client-mock";
import {
  SecretsManager,
  GetSecretValueCommand,
} from "@aws-sdk/client-secrets-manager";

const secretsManagerMock = mockClient(SecretsManager);

secretsManagerMock.on(GetSecretValueCommand).resolves({
  SecretString: "test_secret",
});

  it("Pulls credentials from the secrets manager", async () => {

    const client = new SecretsManager();
    const input = { SecretId: "test_api_key" };
    const result = await client.send(new GetSecretValueCommand(input));
    expect(secretsManagerMock.commandCalls(GetSecretValueCommand)).toHaveLength(
      1,
    );

    expect(result).toBe("test_secret");
  });

// Example 2:

module.test.ts

import { mockClient } from "aws-sdk-client-mock";
import {
  SecretsManager,
  GetSecretValueCommand,
} from "@aws-sdk/client-secrets-manager";

const secretsManagerMock = mockClient(SecretsManager);

secretsManagerMock.on(GetSecretValueCommand).resolves({
  SecretString: "test_secret",
});

// Import class after mock is created using dynamic top level awaited import

const TestModule = (await import("module.ts")).default;

it("Pulls credentials from the secrets manager", async () => {
  const mod = new TestModule();
  const result = await mod.run();
  expect(result).toBe("test_secret");
});

module.ts

import {
  SecretsManager,
  GetSecretValueCommand,
} from "@aws-sdk/client-secrets-manager";

export default class TestModule {
   async run() {
       
    const client = new SecretsManager();
    const input = { SecretId: "test_api_key" };
    const result = await client.send(new GetSecretValueCommand(input));
    return result.SecretString;
   } 
}

Environment

  • Node version: v20.8.1
  • Testing lib and version: Jest:
    "@types/jest": "^29.5.5",
    "jest": "^29.7.0",
    "jest-mock-extended": "^3.0.6",
    "ts-jest": "^29.1.2",
    "jest-extended": "^4.0.2",
  • Typescript version: 5.3.3

  • AWS SDK v3 Client mock version:

  • AWS JS SDK libs and versions:

    "@aws-sdk/client-secrets-manager": "^3.543.0",
    "aws-sdk-client-mock-jest": "^3.0.1",
@jove4015 jove4015 added the bug Something isn't working label Jul 10, 2024
@m-radzikowski
Copy link
Owner

Hey, can you provide a small repo with a reproduction? With Jest setup for ESM and exact commands to run to get the error (npm install and npm test in the simplest scenario).

@wayne-motorway
Copy link

Should you be mocking
const secretsManagerMock = mockClient(SecretsManagerClient);
and not
const secretsManagerMock = mockClient(SecretsManager);?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working waiting for reply
Projects
None yet
Development

No branches or pull requests

3 participants