Is there a way to mock the s3.putObject inside a promise using Jest?
// Service
module.exports.functionUnderTest = async function functionUnderTest() {
return await resolvePromise();
};
function resolvePromise() {
return new Promise((resolve, reject) => {
const params = {
Bucket: "BUCKET_NAME",
Key: "key",
Body: "1,2,3"
};
s3.putObject(params, function(err, data) {
if (err) reject(err);
else resolve(`Success`);
});
});
}
## Test
const mockS3PutObject = jest.fn();
jest.mock("aws-sdk", () => {
return {
S3: jest.fn(() => ({
putObject: mockS3PutObject
}))
};
});
test("My test", async () => {
mockS3PutObject.mockImplementation(params => {
return {
Body: "test document"
};
});
expect(await s3Service.functionUnderTest()).toEqual("test document");
});
Running the test will result in the following:
Timeout - Async callback was not invoked within the 120000ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 120000ms timeout specified by jest.setTimeout.Error:
Appreciate your help!
This is the mocker I made for mocking the aws-sdk in Jest:
type AWSClientMap = typeof import('aws-sdk/clients/all');
interface MockReturn {
promise: () => unknown;
}
/** Map of `aws-sdk` clients to their mocked endpoints */
const clientMocks: { [K in keyof AWSClientMap]?: unknown } = {};
export const mockAwsClientEndpoints = <
TClient extends keyof AWSClientMap,
TEndpoint extends keyof InstanceType<AWSClientMap[TClient]>,
TMockedEndpoints extends Partial<Record<TEndpoint, jest.Mock>>
>(
client: TClient,
mockedEndpoints: TMockedEndpoints
): TMockedEndpoints => {
const clientProxy = new Proxy(class {}, {
construct(): object {
return clientProxy;
},
get(_, property: TEndpoint & string): (...args: unknown[]) => MockReturn {
const endpointMock = mockedEndpoints[property];
if (endpointMock) {
return (...args: unknown[]): MockReturn => ({
promise: (): unknown => endpointMock(...args)
});
}
throw new Error(`${client}#${property} was called without being mocked`);
}
});
clientMocks[client] = clientProxy;
return mockedEndpoints;
};
jest.mock('aws-sdk', () => clientMocks);
It's written in TypeScript, but should work the same if you remove all the types :)
(Here's an example of how to use it](https://github.com/G-Rath/terraport/blob/master/test/src/collectors/aws/collectRoute53ZoneDetails.spec.ts#L6-L10):
import { mockAwsClientEndpoints } from '@test/setupAwsSdkMock';
import { Route53 } from 'aws-sdk';
const {
getHostedZone: getHostedZoneMock //
} = mockAwsClientEndpoints('Route53', {
getHostedZone: jest.fn<Promise<Route53.GetHostedZoneResponse>, unknown[]>()
});
describe('my-test', () => {
const HostedZone: Route53.HostedZone = {
Id: 'HostedZone/Z123456789',
Name: 'my.zone.com.',
CallerReference: 'reference'
};
beforeEach(() => getHostedZoneMock.mockResolvedValue({ HostedZone }));
}
It's designed to be completely TypeScript compatible, which other mocks of the sdk typically aren't.
It's working well in my project, but I'd love feedback on if it works well for you :)
Hey @cedricsarigumba are you able to use the code provided by @G-Rath? It seems to be accurate.
@G-Rath @ajredniwja
Thanks for the recommendation but I ended up updating the source code by removing the enclosing promise. After that, the mock works! Please see below.
// From
function resolvePromise() {
return new Promise((resolve, reject) => {
const params = {
Bucket: "BUCKET_NAME",
Key: "key",
Body: "1,2,3"
};
s3.putObject(params, function(err, data) {
if (err) reject(err);
else resolve(`Success`);
});
});
}
// To
async function resolvePromise() {
const params = {
Bucket: "BUCKET_NAME",
Key: "key",
Body: "1,2,3"
};
return await s3.putObject(params).promise();
}
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.
Most helpful comment
This is the mocker I made for mocking the
aws-sdkin Jest:It's written in TypeScript, but should work the same if you remove all the types :)
(Here's an example of how to use it](https://github.com/G-Rath/terraport/blob/master/test/src/collectors/aws/collectRoute53ZoneDetails.spec.ts#L6-L10):
It's designed to be completely TypeScript compatible, which other mocks of the sdk typically aren't.
It's working well in my project, but I'd love feedback on if it works well for you :)