Question:
I’m having trouble getting the AWS Secrets Manager module mocked for the jest unit tests… The part it errors on is the .promise(). When I remove that, the code doesn’t work for the real Secrets Manager so I think it needs to stay there. How do I mock the getSecretData function so that getSecretData.promise() will work for the mock?
Here is the SecretsManager.js code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import AWS from 'aws-sdk'; export class SecretsManager { constructor() { AWS.config.update({ region: 'us-east-1', }); this.secretsManager = new AWS.SecretsManager(); } async getSecretData(secretName) { try { const response = await this.secretsManager.getSecretValue({ SecretId: secretName, }).promise(); const secretString = response.SecretString; const parsedSecret = JSON.parse(secretString); return parsedSecret; } catch (e) { console.log('Failed to get data from AWS Secrets Manager.'); console.log(e); throw new Error('Unable to retrieve data.'); } } } |
Here is the SecretsManager.test.js code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import { SecretsManager } from '../utils/SecretsManager'; jest.mock('aws-sdk', () => { return { config: { update(val) { }, }, SecretsManager: function () { return { async getSecretValue({ SecretId: secretName }) { return { promise: function () { return { UserName: 'test', Password: 'password', }; } }; } }; } } }); describe('SecretsManager.js', () => { describe('Given I have a valid secret name', () => { describe('When I send a request for test_creds', () => { it('Then the correct data is returned.', async () => { const mockReturnValue = { UserName: 'test', Password: 'password', }; const logger = getLogger(); const secretManager = new SecretsManager(); const result = await secretManager.getSecretData('test_creds'); expect(result).toEqual(mockReturnValue) }); }); describe('When I send a request without data', () => { it('Then an error is thrown.', async () => { const secretManager = new SecretsManager(); await expect(secretManager.getSecretData()).rejects.toThrow(); }); }); }); }); |
This is the error I get when running the tests:
1 2 |
this.secretsManager.getSecretValue(...).promise is not a function |
Any suggestions or pointers are greatly appreciated!
Thank you for looking at my post.
Answer:
I finally got it to work… figures it’d happen shortly after posting the question, but instead of deleting the post I’ll share how I changed the mock to make it work incase it helps anyone else.
Note: This is just the updated mock, the tests are the same as in the question above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// I added this because it's closer to how AWS returns data for real. const mockSecretData = { ARN: 'x', Name: 'test_creds', VersionId: 'x', SecretString: '{"UserName":"test","Password":"password"}', VersionStages: ['x'], CreatedDate: 'x' } jest.mock('aws-sdk', () => { return { config: { update(val) { }, }, SecretsManager: function () { return { getSecretValue: function ( { SecretId } ) { { // Adding function above to getSecretValue: is what made the original ".promise() is not a function" error go away. if (SecretId === 'test_creds') { return { promise: function () { return mockSecretData; } }; } else { throw new Error('mock error'); } } } }; } }}); |