Change jest mock on class for single test - node.js

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();
});
});
});

Related

Jest, 2 describe make timeOut in test with 2 beforeEach mockClear()

I have a test file like this:
const axios = require('axios')
const Vacations = require('../../soap/vacationsSoap')
jest.mock('axios')
describe('describe a', () => {
beforeEach(() => { axios.default.post.mockClear() })
it('some it a.1', () => {
expect(Vacations.getReadXML()).toBe('something')
})
})
describe('describe b', () => {
beforeEach(() => { axios.default.post.mockClear() })
it('some it b.1', async () => {
axios.default.post.mockResolvedValueOnce({ data: 'sth' })
const client = new Vacations()
await expect(client.save()).rejects.toThrow('some error')
})
})
When I run the test, it gets hangout until I get a timeOut error.
But, if I remove the:
beforeEach(() => { axios.default.post.mockClear() })
from the second "describe" it works ok.
I copy pasted the while body from the describe 1 into 2, that's why I thought that it would works with the beforeEach. Why is happening that?

mocking aws-sdk-sns with jest.mock

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.

sinon: Cannot stub non-existent own property formatData

I'm getting the error 'Cannot stub non-existent own property formatData' but i've honestly no idea why! I'm quite new to testing and this test is the same as another one i've done which worked.
const submitDetails = require('../src/scripts/submitDetails')
const sendEmail = require('../src/lib/sendEmail')
describe('submitDetails', function () {
let sandbox = null
before(() => {
sandbox = sinon.createSandbox()
})
afterEach(() => {
sandbox.restore()
})
describe('submitDetails', () => {
let mockParams, result
beforeEach(async () => {
mockParams = {
emailName: 'Confirmation',
formName: 'Contact'
}
sandbox.stub(submitDetails, 'formatData').returns({})
result = await submitDetails.formatData(mockParams)
})
it('should call formatData', () => {
expect(submitDetails.formatData).to.be.calledWith(mockParams)
})
it('should return lowercase params', () => {
expect(result).to.deep.equal({
emailName: 'confirmation',
formName: 'contact'
})
})
it('should call sendEmail', () => {
expect(sendEmail.sendEmail).to.be.calledWith(result)
})
})
describe('formatData', () => {})
})

Fail mocha test in catch block of rejected promise

How to fail the test in catch block of promise rejection when making http call using axios?
Adding expectations, asserts, should expressions in catch block doesn't help.
The test is passing.
I's run using .\node_modules\.bin\mocha
let chai = require('chai');
var expect = chai.expect;
var axios = require('axios')
var instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'url'
instance.get(url)
.then(function(response) {
expect(response.data).not.to.be.null
} )
.catch(function(err) {
console.error(err.data)
// should fail the test
})
})
})
})
If You want to verify my suggestions, replace url value with valid url (ex: https://google.com)
You can try several ways:
1) Using assert.fail()
const axios = require('axios');
const { assert, expect } = require('chai');
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'abc'
return instance.get(url)
.then((res) => {
expect(res.data).not.to.be.null;
})
.catch((err) => {
assert.fail('expected', 'actual', err);
});
});
});
});
2) Using done() with error object
const axios = require('axios');
const { expect } = require('chai');
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', (done) => {
let url = 'abc'
instance.get(url)
.then((res) => {
expect(res.data).not.to.be.null;
done();
})
.catch((err) => {
done(err);
});
});
});
});
3) Simply just throw an error :)
const axios = require('axios');
const { expect } = require('chai');
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'abc'
return instance.get(url)
.then((res) => {
expect(res.data).not.to.be.null;
})
.catch((err) => {
throw err;
});
});
});
})
If You want to check if that method fails at all and You expect this, go that way (it requires chai-as-promised package):
const axios = require('axios');
const chai = require('chai');
chai.use(require('chai-as-promised'));
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'abc'
return chai.expect(instance.get(url)).to.be.rejected;
});
});
});

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

Resources