Is there any way to mock private functions with Jest?
I found a way to mock my private function by using the babel-plugin-rewire
module.
In package.json
I have the following:
"devDependencies": {
...
"babel-plugin-rewire": "1.0.0-beta-5",
"babel-jest": "18.0.0",
...
In .babel.rc
I have the following:
{
"presets": [
"es2015",
"stage-0",
"react"
],
"env": {
"test": {
"plugins": [
"babel-plugin-rewire"
]
}
},
...
At this point I was able to mock the private function:
import * as moduleToTest from './moduleToTest.js'
describe('#publicFunction', () => {
it('mocks private function', () => {
moduleToTest.__Rewire__('privateFunction', () => {
console.log('I am the mocked private function');
})
...
})
})
testing private functions in typescript with jest
It looks like you are wanting to verify that handleError
gets called when build
runs.
Private methods are compiled to normal JavaScript prototype methods, so you can use the any
type to let the spy creation pass through the TypeScript type checking.
Here is a highly simplified example:
class OrderBuilder {
public build() {
this.handleError()
}
private handleError() {
throw new Error('missing ... field in order')
}
}
describe('Order Builder', () => {
it('should test the handleError', () => {
const handleErrorSpy = jest.spyOn(OrderBuilder.prototype as any, 'handleError');
const orderBuilder = new OrderBuilder()
expect(() => orderBuilder.build()).toThrow('missing ... field in order'); // Success!
expect(handleErrorSpy).toHaveBeenCalled(); // Success!
});
});
How to mock a un-export (private) function inside user module using Jest
The workaround I adopted is not to mock the entire "private" function but only the "impossible" part of the functionality inside the “private” function. In this case, fetching the token from the remote service doGetSession
and calling external API using Axios lib request
method.
// Mocks
import { request } from "axios";
import { doGetSession } from "../utilities/auth/auth";
// Targets
import { requestUploadStatementFile } from "./api";
jest.mock("../utilities/auth/auth");
jest.mock("axios");
describe("requestUploadStatementFile", () => {
it("should fire request with correct reqeust configuration object", done => {
doGetSession.mockImplementationOnce(() => {
return Promise.resolve({ idToken: { jtwToken: "SAMPLE-TOKEN" } });
});
request.mockImplementationOnce(() => {
return Promise.resolve({ data: [] });
});
requestUploadStatementFile({}).then(transactions => {
const transactionsExpected = [];
const requestExpectedArgs = {
data: {},
headers: { Accept: "application/json", Authorization: undefined, "Content-Type": "application/json" },
method: "POST",
url: "https://*.*.amazonaws.com/api/upload"
};
expect(transactions).toEqual(transactionsExpected);
expect(request).toHaveBeenCalledTimes(1);
expect(request).toHaveBeenCalledWith(requestExpectedArgs);
done();
});
});
});
Thanks for the comment from @felixmosh.
It is considered a bad practice to mock private function. You should always mock only the outer layer of your app, usually public API
How to Mock private method in Class?
Thanks to @Andrei-Dragotoniu I ended up to mock the service instead.
const module: TestingModule = await Test.createTestingModule({
providers: [{
provide: OperationDocumentService,
useValue: {
findById: () => OperationDocumentMock,
},
}]
});
The private method is already called in another tested method.
How can I mock a private property in a class I'm trying to test in jest
Unless #
hard privacy is used, private properties can be accessed outside a class at runtime, TypeScript access modifiers are applied only at compilation time.
Accessing private members in tests can be considered a reflection.
Visibility can be bypassed with bracket notation, which is the preferable option:
controllerInstance['stepperMotors'] = ...;
Or with Reflect API:
Reflect.set(controllerInstance, 'stepperMotors', ...);
Or by disabling type checks:
(controllerInstance as any).stepperMotors = ...;
Since private property is set with prototype method, another approach is to mock it. It's applicable if original initialization causes undesirable side effects and needs to be avoided. BotController.prototype.someMethod = jest.fn()
should never be used in Jest as it cannot be automatically cleaned up and cross-contaminates tests. Instead it could be:
jest.spyOn(BotController.prototype, 'initalizeMotors').mockImplementation(function (this: BotController) {
this['stepperMotors'] = ...;
});
...
expect(controllerInstance['initalizeMotors']).toHaveBeenCalled();
Related Topics
How to Format Base64 Encoded String While Sending in Json
How to Disable Print-Screen Functionality for a Webpage in All Browsers
How to Include External JavaScript Library in Reactjs
How to Apply the Length Condition on the Existing Regular Expression
How to Vertically and Horizontally Center a Component in React
React-Native: Application Has Not Been Registered Error
How to Check If a Textbox Is Empty Using JavaScript
Javascript: Replace Last Occurrence of Text in a String
Dynamically Add Variable Name Value Pairs to Json Object
Check If a Number Has a Decimal Place/Is a Whole Number
Jquery Ajax Post Results in 500 Internal Server Error
Javascript - Auto Click on a Button on Page Load
Break the Loop of an Array Looping Function (Map, Foreach, etc.)
How to Stop the Iframe from Constantly Reloading After Setinterval (Jquery)
How to Make a Bot Delete Messages After a Certain Time Period