aws-sdk-mock
aws-sdk-mock copied to clipboard
getSignedUrl doesn't mock correctly when called asynchronously
code:
AWSMock.mock('S3', 'getSignedUrl', 'message');
const s3 = new AWS.S3({ paramValidation: true }),
const s3Url = s3.getSignedUrl('getObject', {Key: 'key', Bucket: 'Bucket'});
console.log(s3Url); //should be a string... However it looks more like an AWS Request object:
Output:
{ promise: [Function],
createReadStream: [Function: createReadStream],
on: [Function: on],
send: [Function: send] }
Please review the documentation for further information: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
It seems this has something to do with the assumption that all the AWS service methods should have the signature service(params, callback)
getSignalUrl has the following signature: getSignalUrl(method,params, callback)
I'd really appreciate it if this could be fixed
I was able to get this working by NOT using the getSignedUrlPromise:
AWSMock.setSDKInstance(AWS);
AWSMock.mock('S3','getSignedUrl', (operation,params,callback) => {
return callback(null, fixtureObject);
});
Code is:
const s3 = new AWS.S3(s3ConfigObject);
return new Promise((resolve, reject) => {
s3.getSignedUrl('putObject', params, (err, url) => {
err ? reject(err) : resolve(url);
});
});
Any update on when this is going to be fixed?
How can I mock to getSignedUrl
?
code:
public async getUrlFromS3(fileName: string): Promise<string> {
const params = {
Bucket: this.bucketName,
Key: `${fileName}.pdf`,
Expires: config.pdfUrlExpiredTime,
};
return new Promise((resolve, reject): any => {
this.s3.getSignedUrl("getObject", params, (err: Error, url: string) => {
console.log("call end");
if (err) {
reject(new HttpErrorWrapper(err));
}
resolve(url);
});
});
}
and my test:
AWSMock.mock("S3", "getSignedUrl", (operation, params, callback) => {
console.log("mock called");
callback(null, "https://example.com");
});
but it was not log and return url is not that, but https://s3.amazonaws.com/~~~~~
So I ran into this issue also, I was able to get around it for now with mocking the getSignedUrlPromise function manually:
test('will return a 200', async () => {
const listObjectsV2Mock = jest.fn().mockReturnValue({
promise: jest.fn().mockResolvedValue({
Contents: [
{
Key: 'testing/',
LastModified: '2020-03-14T01:24:24.000Z',
ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
Size: 0,
StorageClass: 'STANDARD'
}
]
})
});
const putObjectMock = jest.fn().mockReturnValue({
promise: jest.fn().mockResolvedValue({})
});
const getSignedUrlPromise = jest
.fn()
.mockResolvedValue('Successfully Mocked URL');
AWSMock.mock('S3', 'getSignedUrlPromise', (operation, params, callback) => {
return callback(null, 'test');
});
AWS.S3 = jest.fn().mockImplementation(() => ({
getSignedUrlPromise,
listObjectsV2: listObjectsV2Mock,
putObject: putObjectMock
}));
const { exportDataToCsv } = require('./exportDataToCsv');
const result = await exportDataToCsv({}, {});
expect(result).toBe({ statusCode: 200 });
});
This allowed me to mock the getSignedUrlPromise function whilst also mocking others. The issue I had with the others was when I injected the manually mocked functions whilst using aws-sdk-mock I was losing all reference to the stubs previously in place, so I have simply not used this repo for this functions unit tests. Not a great solution but might be helpful for others that need a solution now.
I created a palliative for this case
const aws = require('aws-sdk');
const sinon = require('sinon');
class AwsMock {
getSignedUrl() {
return 'signedUrl.com';
}
async getSignedUrlPromise() {
return 'signedUrlAsync.com';
}
}
const awsS3Mock = sinon.stub(aws, 'S3').returns(new AwsMock());
const s3 = new aws.S3();
const urlAsync = await s3.getSignedUrlPromise('s3.link');
console.log(urlAsync); // signedUrlAsync.com
const url = s3.getSignedUrl('s3.link');
console.log(url); // signedUrl.com
I had the same issue with this code:
const url = s3.getSignedUrl('putObject', s3Params)
and my test:
AWS.mock('S3', 'getSignedUrl', (action, _params, callback) => {
console.log('S3', 'getSignedUrl', 'mock called')
callback(null, mockSignedUrl)
})
so, I changed my code to this, and then my test worked!
const url = await s3.getSignedUrlPromise('putObject', s3Params)
we should not change implementation of our code to pass tests but rather the aws-sdk-mock should support mocking of all features of aws-sdk
Also experiencing this issue.
It seems that this library only mocks methods that return instances of the Request<D, E> class. However, there are lots of methods that don't return such instances, for example, the aforementioned getSignedUrl. Are there future plans to add the possibility to mock such methods?
Just ran over this issue on a project and @yoelfme 's approach was very helpful for my case, with the difference that i already was using the s3.getSignedUrlPromise
method, so i just had to create a mock for s3.getSignedUrl
and that was enough for the test to work without problems.
Had the same issue.
I too solved it by mocking getSignedUrl
instead of getSignedUrlPromise
.
Yes, looks like getSignedUrlPromise
method was used in your code you still have to mock getSignedUrl
method:
AWSMock.mock('S3', 'getSignedUrl', signedUrl);
Same problem here. I don't want to modify my client to use the promise version. How can I get this working in Jest
How to mock getSignedUrl
from SDK v3 using Jest?
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
...
export const handler = async (event) => {
...
const putCommand = new PutObjectCommand(myParams);
await getSignedUrl(new S3Client(), putCommand);
}
Just ran over this issue on a project and @yoelfme 's approach was very helpful for my case, with the difference that i already was using the
s3.getSignedUrlPromise
method, so i just had to create a mock fors3.getSignedUrl
and that was enough for the test to work without problems.
What SDK you use - v2 or v3 ?