-
Notifications
You must be signed in to change notification settings - Fork 107
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
Spying with jest.spyOn() example? #127
Comments
I'm gonna answer my own question (I solved it almost immediately after I posted it here), so hopefully someone else can make use of it. It's a roundabout way of achieving what I wanted with it('should putObject', async () => {
const putObjectMock = jest.fn(() => "your response here");
awsMock.mock('S3', 'putObject', (params, callback) => {
callback(null, putObjectMock(params));
});
const data = await functionBeingTested();
expect(putObjectMock).toHaveBeenCalledTimes(1);
expect(putObjectMock).toHaveBeenCalledWidth(/* your arguments here */);
}); |
So I felt that this left some room for clarification as I was not so sure how they actually implemented as awsMock was not defined in the example above. The other issue is that this does not explain how to achieve the same result with a module that is an alias to another like DocumentClient -> DynamoDB. The example below also shows how you might do it by using the callback. //file-to-test.js
const AWS = require('aws-sdk');
export const getData = async () => {
const dynamoDb = new AWS.DynamoDB.DocumentClient({ region: 'us-east-1' });
const params = {//your parameters}
return await new Promise((resolve, reject) => {
dynamoDb.batchGet(params, (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}; //test-file.js
import { getData } from './file-to-test';
const AWS = require('aws-sdk');
test('...', async () => {
const awsMock = jest.spyOn(AWS.DynamoDB, 'DocumentClient');
awsMock.mockImplementation(() => {
return {
batchGet: async (params, callback) => {
callback(//err object or null, //data object or null);
}
}
});
const data = await getData();
expect(awsMock).toHaveBeenCalledTimes(1);
expect(awsMock).toHaveBeenCalledWith({ region: 'us-east-1' });
expect(data).toBe(//err or data object given to implementation);
}); You can follow the same principle if you use the promise() method as well if you mock I hope this was helpful as a lot of the solutions out there either break encapsulation or do not give examples of this specific situation where you might be working with a callback function or aliased class declaration. |
Thank you very much, it worked for me, but I had an error with
Hope it helps someone :D |
Trying to spy on an SSM api function this way. Getting Error: Cannot spy the describeInstanceInformation property because it is not a function; Can you help? |
@pavian So I actually experience this problem as well just recently. I forgot that I had done this and reimplemented and resolved the problem in a different way. I do want to add the caveat that I use typescript and have adapted the code to native javascript in the first example. This example is going to keep typescript in place. The reason is to try to help more people. import { EC2 } from 'aws-sdk';
export const getSecurityGroups = async (): string[] => {
const ec2 = new EC2({apiVersion: '2016-11-15'});
const { SecurityGroups } = await ec2.describeSecurityGroups().promise();
return SecurityGroups.reduce((agg, current) => {
agg.push(current.GroupId);
return agg;
}, []);
} // Mock the library first before the import. Order of operations does matter as otherwise the library does not get mocked.
jest.mock('aws-sdk');
import { handler } from '../../../src/handlers/InsecureSecurityGroup';
// Typescript only import
import { DescribeSecurityGroupsResult } from 'aws-sdk/clients/ec2';
import * as aws from 'aws-sdk';
// The aws variable is not associated with the mocking library.
// This tells typescript and your ide to attach the mocking methods into all objects of the module
// Skip this for native javascript
const mocked = aws as jest.Mocked<typeof aws>;
test('...', async () => {
const sgList: DescribeSecurityGroupsResult = {
SecurityGroups: [
{
GroupId: 'id'
},
{
GroupId: 'another id'
}
]
};
const sgListResolve = jest.fn().mockResolvedValueOnce(sgList);
const EC2Promise = jest.fn().mockReturnValueOnce({
promise: sgListResolve
})
// ignored because we are not mocking the entire EC2 object
// @ts-ignore
mocked.EC2.mockImplementation(() => ({
describeSecurityGroups: EC2Promise
}));
const response = await handler();
expect(sgListResolve).toHaveBeenCalled();
expect(sgListResolve).toHaveBeenCalledTimes(1);
expect(EC2Promise).toHaveBeenCalled();
expect(EC2Promise).toHaveBeenCalledTimes(1);
expect(response).toEqual(['id','another id' ]);
}); If you want to read the config data sent to the EC2 constructor method, then all you would do is set it to a jest.fn() definition which would return the object with the functions being tested as currently done. I personally prefer the mock implementation over the spy for handling constructor mocking. I feel that it looks more explicit. Another thing to note is that you are going to want to not clear mocks in your jest config with this method. It still works but the entire library is mocked on each test case and exponentially increases test time. |
Thank you, but I am afraid I am missing the spying part. All expects fail to count the function calls. |
@pavian can you list what is happening in the |
@pavian try removing the |
I've figured it out. Just moved the |
If you had the ssm object instantiated outside the function call for performance reasons, then you can either cache outside the method or create a singleton and mock the singleton instead. cache
For singleton's reference this article https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ |
Can I get an example of using this library with Jest's
.spyOn()
? I basically want to make sure certain AWS functions get called with the proper arguments (via Jest's.toHaveBeenCalledTimes()
&.toHaveBeenCalledWith()
).The text was updated successfully, but these errors were encountered: