Jest - Mock Nested Function - reactjs

I am writing a JEST/Enzyme test case for module.
One of the function I am testing in my component is about saving an xml file. Which in turn calls a library function fileDownload from 'react-file-download'
const saveContentToXML = () => {
if(this.props.message && this.props.message.details){
fileDownload(this.props.message.details, this.props.message.title);
}
}
When I wrote test case, it calls saveContentToXML and in turn calls fileDownload. This results in exception.
TypeError: window.URL.createObjectURL is not a function
My test case looks like
test('Save Content as XML Test', () =>{
const component = shallow(<Message details={details} />);
component.instance().saveContentToXML();
});
How do I test this function?

You should mock react-file-download and then assert that it is being called
// Default mock will just make fileDownload a jest mock function
jest.mock('react-file-download')
import fileDownload from 'react-file-download'
test('Save Content as XML Test', () =>{
const component = shallow(<Message details={details} />);
component.instance().saveContentToXML();
expect(fileDownload).toHaveBeenCalledWith('details', 'title');
fileDownload.mockClear() // resets the mock function so the call is not used in assertions for other tests
});
The jest documentation on mock functions is a good resource to refer to: https://facebook.github.io/jest/docs/mock-functions.html

Related

Is it possible to mock functions outside of the test file for multiple tests to use?

Thanks in advance
Issue
I have some functions that need to be mocked in every test file. However, only in some of those files, do I actually care to evaluate or test those mock functions.
For example, let's say, that when my app renders, it immediately fetches some data In A.test.tsx I want to mock that fetch and verify that it was called.
But, in B.test.tsx, I still need to mock that fetch, but I don't care to verify that it was called.
Goal
I would like the setup to look something like this:
setup.ts
import * as SomeAPI from 'api';
const setup = () => {
jest.spyOn(SomeAPI, 'fetchData');
return { SomeAPI };
};
export default setup;
A.test.tsx
const { SomeAPI } = setup();
beforeEach(() => {
jest.clearAllMocks();
});
test('data should be fetched when app renders', async () => {
RenderWithProviders(<App />);
expect(SomeAPI.fetchData).toHaveBeenCalled();
});
B.test.tsx
setup(); // Don't destructure because I don't care to test the mock
beforeEach(() => {
jest.clearAllMocks();
});
test('test some other stuff', async () => {
// In this case, the fetchData still needs to be mocked<br>
// because the rest of the app depends on it
RenderWithProviders(<App />);
expect(someElement).toBeInTheDocument();
});
My Current Problem
My problem is that while I'm trying to attempt this way of returning mocked functions... If that mocked function is used more than once in the same test file, the jest.clearAllMocks() seems not to have an effect. I assume because the setup is happening outside of the test?
Is this possible to setup mocks outside of the test and only destructure them when needed?

Jest Test Failed - TypeError: window.matchMedia is not a function

I try to make a snapshot testing using react-test-renderer, I need to render a component which use the code below (in a separate file) to conditionally render different component.
let mql = window.matchMedia("(max-width: 600px)");
let mobileView = mql.matches;
export default mobileView;
This is the snapshot test
test("Your test case", () => {
const component = renderer.create(<CalendarTitle month={8} year={2021} />);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
I have tried using jest-matchmedia-mock package but it can't solve the problem, maybe it need to mock in a different file but i am not sure what to write in matchMedia.mock.ts file and what is the myMethod from "file-to-test" and how to write to complete test method.
import matchMedia from './matchMedia.mock.ts'; // Must be imported before the tested file
import { myMethod } from './file-to-test';
describe('myMethod()', () => {
// Test the method here...
});

Test inside function called or not in jest

I am writing test cases in jest recently. I have a requirement like should check whether inside function being called or not. Can anyone help me with this?
Here is the code for index.js
componentDidMount() {
this.onSetActionableStateListener = (param) => this.onSetActionableState(param[0]);
client.on('setActionableState', this.onSetActionableStateListener);
}
I am writing code in index.test.js like this
it('should call onSetActionableState in componentDidMount', () => {
wrapper.instance().componentDidMount();
// const onSetActionableState = jest.fn();
expect(wrapper.instance().onSetActionableState).toBeCalled();
});
I want to test whether onSetActionableState is called or not?

Trying to spyOn a mocked function

I am trying to perform a spyOn on a function that exists in a mocked class:
test.ts -
import Service from '../base_classes/Service';
jest.mock('../base_classes/Service');
const o: Component = new Component();
it('should load model specific information', async () => {
const getSpy = jest.spyOn(Service.prototype, 'get');
let t = await o.load(1);
expect(t.name).toEqual('test_name');
expect(getSpy).toHaveBeenCalledTimes(1);
});
__mocks__/Service.ts -
export const mockGet = jest.fn(async () => Promise.resolve({name:
'test_name'}));
const mock = jest.fn().mockImplementation(() => {
return {
get: mockGet
}
});
export default mock;
The resulting error is: Cannot spy the get property because it is not a function
I tried changing the mocked arrow function to a function(), but that didn't help.
How can I set this up so I can spy on my mocked function?
When using jest.mock it automatically creates a mock for each property of the module, replacing it's functions with jest.fn() (without implementation). And from then on you can write assertions. There should be no reason you'd want to spy on a mock function as it's already a mock function.
You should either spy on the actual implementation or write assertions for the methods on the mocked module.
e.g.
it('should load model specific information', async () => {
let t = await o.load(1);
expect(t.name).toEqual('test_name');
expect(Service.mock.instances[0].get).toHaveBeenCalledTimes(1);
});
working example

how to use jest to mock method of react class

I want to mock method of react class so that the unit test can run follow the mock function.
React: 16.8.6
jest: 24.8.0
Overview.js
import React from 'react';
export default class Overview extends Component{
test1(){
return {
// fetch api
}
}
test2(){
const result = this.test1();
// do other thing
return result
}
}
overview.test.js
import Overview from './index';
import { mount } from 'enzyme';
import React from 'react';
describe('test Overview',()=>{
const mockResult = {test1:'test1'};
console.info(Overview.prototype) // {}
Overview.prototype.test1=jest.fn(()=>{
return mockResult
});
it('func test2',()=>{
const wrapper = mount(<Overview/>);
const {test2} = wrapper.instance();
expect(mockResult).toEqual(test2())
})
})
Expect: run success
Actual result: run fail, because Overview.prototype cannot override or mock test1 function.
When I tried to print 'Overview.prototype', I get {}. That let me so confuse.
How to mock test1 function and why Overview cannot be overrode?
Please help me.
Try to do this:
it('func test2',()=>{
const wrapper = mount(<Overview/>);
wrapper.instance().test1 = jest.fn(() => mockResult);
expect(wrapper.instance().test2()).toEqual(mockResult);
})
There are plenty of reason to choose different approach than mocking internal methods and checking against internal methods:
it's hard and even impossible somtimes(once method under mock change state or even access variable by closure)
you stick to implementation details so even smallest refactoring(renaming internal method or property name in state) make you update tons of tests
it makes you even more confident in your component(say what if test1() stopped to call fetch()? but your tests with mocking it would not even know that component is broken)
Here is different approach: mock only external API and communicate only through public interface(for React component it's props and render() result you may access with Enzyme's methods like .find(), .filter(), .text() etc)
There are several packages that mocks global fetch() like fetch-mock but you actually may mock it on your own(don't forget to mock it with Promise not plain data):
global.fetch = jest.fn();
beforeEach(() => {
// important for mocks to keep them fresh on each test case run
global.fetch.mockClear();
});
it('renders error if fetching failed', async () => {
global.fetch.mockReturnValue(Promise.reject({}));
const wrapper = shallow(<Overview />);
wrapper.find('.some-button-to-click').props().onClick();
await Promise.resolve(); // let's wait till mocked fetch() is resolved
expect(wrapper.find('.error').text()).toEqual('Unable to load users. Try later.');
});

Resources