mocking aws-sdk-sns with jest.mock - jestjs

I have the following code (t
// mock sns
const testMock = jest.fn().mockImplementation(() => {
return {
promise: () => jest.fn()
};
});
jest.mock('aws-sdk/clients/sns', () => {
return jest.fn().mockImplementation(() => {
return { publish: testMock };
});
});
Now when I run this I get the following error
ReferenceError: Cannot access 'testMock' before initialization
Could it have something to do with jest hoisting the mock or something like that ?
Further to do this, if I move the testmock insider the scope of mock then it works fine.
// this works
jest.mock('aws-sdk/clients/sns', () => {
const testMock = jest.fn().mockImplementation(() => {
return {
promise: () => jest.fn()
};
});
return jest.fn().mockImplementation(() => {
return { publish: testMock };
});
});
However this beats the purpose since I cannot check the calls or anything.

Related

jest test async function recieving undefined

Hi I'm trying to test a post route that make loots of operations using Jest.
I'm trying to mock a class that makes a http call to another API. The problem is the response is always undefined and I have no idea whats wrong.
This is my mock comunicante-service.js (located in root/mock):
module.exports = {
getConfig: jest.fn(async () => {
Promise.resolve(dadosContaConfig);
}),
sendMessage: jest.fn(async () => {
Promise.resolve('ok');
}),
};
And that's the test
jest.mock('../src/services/comunicante-service');
describe('test /message', () => {
it('no token', async () => {
const res1 = await request(app).post('/message').set(config);
expect(res1.statusCode).toEqual(400);
});
inside of the code that handle the /result there's a call to
const aux = await comunicanteService.getConfig(conta_id);
It looks like you may have forgotten to return something from the mock service. You could try:
module.exports = {
getConfig: jest.fn(async () => {
return Promise.resolve(dadosContaConfig);
}),
sendMessage: jest.fn(async () => {
return Promise.resolve('ok');
}),
};
This can be simplified to:
module.exports = {
getConfig: jest.fn().mockResolvedValue(dadosContaConfig),
sendMessage: jest.fn().mockResolvedValue('ok'),
};

Change jest mock on class for single test

I have an issue where I want to change what a class method returns for a single test while testing a different module. I have the following:
testingModule.test.js
const { testingModuleMethod } = require('../testingModule')
jest.mock('../helperClass', () =>
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
describe('testingModule.js', () => {
describe('testingModuleMethod', () => {
describe('when errors', () => {
const consoleSpy = jest.spyOn(console, 'error');
// SOMETHING NEEDS TO GO HERE TO CHANGE THE jest.mock ON LINE 3
await expect(testingModuleMethod(data)).rejects.toThrow('Error');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
});
testingModule.js
const HelperClass = require('./helperClass');
const testingModuleMethod = async (data, callback) => {
try {
const objectToEvaluate = data.object;
const helperClassInstance = new HelperClass();
await helperClassInstance.helperClassMethod(objectToEvaluate);
log('info', "Success!");
callback(null, {});
} catch(error) {
log('error', 'Something went wrong')
}
};
No matter what I put in there I either get an error with the code (undefined) or it just ignores it and resolves due to the mock at the start. I have tried adding a spy as well as importing the class and using the prototype override.
I'm using node and "jest": "^27.0.6"
I have managed to answer this by doing the following:
Firstly I discovered that to mock a class like that I have to add a jest function into the mock like so:
describe('testingModuleMethod', () => {
describe('when errors', () => {
const consoleSpy = jest.spyOn(console, 'error');
HelperClass.mockImplementation(() => ({
helperClassMethod: jest.fn(() => { throw new Error('Error') })
}));
await expect(testingModuleMethod(data)).rejects.toThrow('Error');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
This also had a knock on effect to the rest of the tests though so I added a beforeEach at the start that looks like:
HelperClass.mockImplementation(
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
Finally I needed to require the class. The overall test looks like this now and works:
const { testingModuleMethod } = require('../testingModule');
const HelperClass = require('./helperClass');
jest.mock('../helperClass', () =>
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
describe('testingModule.js', () => {
beforeEach(() => {
HelperClass.mockImplementation(
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
});
describe('testingModuleMethod', () => {
describe('when errors', () => {
const consoleSpy = jest.spyOn(console, 'error');
HelperClass.mockImplementation(() => ({
helperClassMethod: jest.fn(() => { throw new Error('Error') })
}));
await expect(testingModuleMethod(data)).rejects.toThrow('Error');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
});

How To Spy On An Exported and Mocked Function In Jest

I am trying to mock a module (which has an exported function[and this is also mocked]).
I would like to spy on the exported function to check that it was called with something.
This is my code...
import { addNewPaymentMethod } from '../src/service'
jest.mock('../src/service', () => ({
addNewPaymentMethod : (paymentMethodInfoModel) => {
let responseFromApi = {responseStatus:{name:'blah'}};
return Promise.resolve(responseFromApi);
}
}))
import { createNewPaymentMethod } from '../src/actions/paymentMethod'
test('test expect', () => {
createNewPaymentMethod({owNickName:'nName',id:22})();
//this is the bit I don't know how to do
//...
jest.spyOn(addNewPaymentMethod);
expect(addNewPaymentMethod).toBeCalledWith({some:object});
});
You can define the mock using jest.fn().mockResolvedValue(value)
jest.mock('../src/service', () => ({
addNewPaymentMethod : jest.fn().mockResolvedValue({
responseStatus: {
name:'blah'
}
})
}))
and then since it's a jest.fn() you don't need to spyOn it :)
but note that since it's async (uses promises) you either have to chain then to the method (and use return):
it('should have been called with data', () => {
const data = {};
return service.methodWhichCallsDependencysaddNewPaymentMethod(data).then(() => {
return expect(addNewPaymentMethod).toHaveBeenCalledWith(data);
});
});
or use async/await:
it('should have been called with data', async () => {
const data = {};
await service.methodWhichCallsDependencysaddNewPaymentMethod(data);
expect(addNewPaymentMethod).toHaveBeenCalledWith(data);
});
I've set up a working example

How to properly stub out request-promise in a mocha unit test using sinon?

My unit test is:
describe.only("Validator Service Tests", function () {
let request
before((done) => {
request = sinon.stub()
done()
})
beforeEach(() => {
process.env.API_URL = "http://test"
})
it('Should return with no errors if the file matches the schema', () => {
const updateStatusSpy = sinon.spy(FileLib, 'updateStatus')
request.yields({message: 'ok'})
return ValidatorService.handleMessage({
file: 'test'
})
.then((response) => {
assert()
console.log(response)
sinon.assert.calledOnce(updateStatusSpy)
assert(response, 'f')
})
})
})
The problem is my handleMessage function, which looks like:
exports.handleMessage = (message, done) => {
return stuff()
.then((result) => {
console.log('result', result)
if(result) {
return FileLib.updateStatus(fileId, 'valid')
}
return FileLib.updateStatus(fileId, 'invalid')
})
.then(done)
}
And my updateStatus function:
exports.updateStatus = function(fileId, status) {
console.log(fileId, status)
return request.put({
uri: `${process.env.API_URL}/stuff/${fileId}`,
body: {
status: status
}
})
}
My actual request call is buried so deep in, how can I stub it out when testing?
I'm not sure I completely understand your question, but if you are just trying to stub put, try something like this:
let stub;
beforeEach(() => {
putStub = sinon.stub(request, 'put').resolves('some_val_or_object'); //or yields or callsFake, depending on what you're using
});
it('should call request with put', async () => {
await //call your code
expect(putStub.called).to.be.true;
expect(putStub.calledWith(whatever_you_want_to_check)).to.be.true;
});

Testing promise with ava

I try to test this class
class Scraper {
async run() {
return await nightmare
.goto(this.url)
.wait('...')
.evaluate(()=>{...})
.end
}
}
And my test looks like this:
test('Scraper test', t => {
new Scraper().run().then(() => {
t.is('test', 'test')
})
})
Test fails:
Test finished without running any assertions
EDIT
repository on github: https://github.com/epyx25/test
test file: https://github.com/epyx25/test/blob/master/src/test/scraper/testScraper.test.js#L12
You need to return the promise. Assertion planning is not needed:
test('Scraper test', t => {
return new Scraper().run().then(() => {
t.is('test', 'test')
})
})
Or better still, using an async test:
test('Scraper test', async t => {
await new Scraper().run()
t.is('test', 'test')
})
you must using assert-planning to blocking the test until the lambda is notified by the Promise, for example:
test('Scraper test', t => {
t.plan(1);
return new Scraper().run().then(() => {
t.is('test', 'test')
})
})
OR
test.cb('Scraper test', t => {
t.plan(1);
new Scraper().run().then(() => {
t.is('test', 'test')
t.end()
})
})

Resources