How to spy on refs in React? - reactjs

I have a component that has a MapView from react-native-maps. I want to test that I'm calling MapView.fitToSuppliedMarkers() inside componentDidUpdate of my component.
I'm using enzyme and jest for testing.
My code under test:
componentDidUpdate() {
//some other code
this.refs.map.fitToSuppliedMarkers(/* some parameters */);
}
But I struggle on how to access and spy on this.refs using enzyme and jest.

The problem was I relied on deprecated string refs which didn't allow for testing. Once, I upgraded to callback refs I was able to spy on refs using the prototype object.
code under test
componentDidUpdate() {
//some other code
this.map.fitToSuppliedMarkers(/* some parameters */);
}
render() {
return (
<MapView
ref={(map) => { this.map = map; }}
>
</MapView>
);
}
the unit test
it('zooms in on markers when receiving new data', () => {
Map.prototype.map = {
fitToSuppliedMarkers: function () { }
};
const spy = spyOn(Map.prototype.map, 'fitToSuppliedMarkers');
const testee = shallow(
<Map markers={[]} />
);
const withAnimation = true;
testee.setProps({ markers: markers });
expect(spy).toHaveBeenCalledWith(markers, withAnimation);
});

Related

How to mock unit functions using Jest in react

I have below code in my render method
render() {
let isNew = Boolean(domService.getQueryParamByName("isNew"));
if(isNew) {
return(
// soemthing
)} else {
return(// return anything)
Now how to mock the getQueryParamByName unit function in the jestUnit testcase such that it should cover if block.
If you are importing the domService from another file to your component, inside the test you can add a spy like this:
//component.test.js
import domService from "relative-path";
const mockFunction = jest.fn((obj) => {});
beforeEach(() => {
mockFunction.mockClear();
jest.spyOn(domService,"getQueryParamByName").mockReturnValue(mockFunction);
});

React-Jest Unit test an external module method that affects state

I am working on a React application using Jest.
I want to test an imported module component method (closemodal):
<Modal
visible={this.state.showModal}
closemodal={() => this.setState({ showModal: false })} // <= this one
type="slideInDown"
>
I tried in my unit test to spy Modal closemodal method like that:
import Modal from "react-animated-modal";
let spyOnCloseModal;
beforeEach(() => {
spyOnCloseModal = jest.spyOn(Modal, "closemodal");
wrapper = shallow(<App />);
});
But when UT running I get this error:
Cannot spy the closemodal property because it is not a function; undefined given instead
Try passing a mock function.
test("checks closemodel", () => {
const props = {
closemodal: jest.fn()
};
const wrapper = shallow(<Modal {...props} />);
// trigger your `closemodal` function here
expect(props.closemodal).toHaveBeenCalledTimes(1);
});

How do I test that a function is called within a method using jest+enzyme+react+typescript?

Say I have this method in my react component
handleSubmit(){
if (this.state.fireRedirect === false){
this.setState({ fireRedirect: true }, () => { this.addEndpoint() });
}
}
How do I test that addEndpoint was called using Jest and Enzyme?
Use jest.spyOn
const spy = jest.spyOn(Component.prototype, "addEndPoint");
const wrapper = shallow(<Component/>);
expect(spy).not.toHaveBeenCalled();
wrapper.instance().handleSubmit();
expect(spy).toHaveBeenCalled();

Testing input.focus() in Enzyme

How do I test input.focus() in enzyme. I am writing the script with react. My code is below:
public inputBox: any;
componentDidUpdate = () => {
setTimeout(() => {
this.inputBox.focus();
}, 200);
}
render() {
return (
<div>
<input
type = 'number'
ref = {element => this.inputBox = element } />
</div>
);
}
You can use mount instead of shallow.
Then you can compare document.activeElement and the input DOM node for equality.
const output = mount(<MyFocusingComponent/>);
assert(output.find('input').node === document.activeElement);
See https://github.com/airbnb/enzyme/issues/316 for more details.
Per React 16.3 updates... using createRef for anyone visiting this post today, if you rearrange the original component to use the new ref api
class InputBox extends PureComponent {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return (
<input
ref={this.inputRef}
/>
);
}
}
Then in your test spec
it("Gives immediate focus on to name field on load", () => {
const wrapper = mount(<InputBox />);
const { inputRef } = wrapper.instance();
jest.spyOn(inputRef.current, "focus");
wrapper.instance().componentDidMount();
expect(inputRef.current.focus).toHaveBeenCalledTimes(1);
});
Notice the use of the inputRef.current attribute which references the currently assigned DOM node.
Other approach is to test if element gains focus, i.e. focus() is called on node element. To achieve this, focused element need to be referenced via ref tag like it takes place in your example – reference was assigned to this.inputBox. Consider example below:
const wrapper = mount(<FocusingInput />);
const element = wrapper.instance().inputBox; // This is your input ref
spyOn(element, 'focus');
wrapper.simulate('mouseEnter', eventStub());
setTimeout(() => expect(element.focus).toHaveBeenCalled(), 250);
This example uses Jasmine's spyOn, though you can use any spy you like.
I just had the same issue and solved using the following approach:
My setup is Jest (react-create-app) + Enzyme:
it('should set the focus after render', () => {
// If you don't create this element you can not access the
// document.activeElement or simply returns <body/>
document.body.innerHTML = '<div></div>'
// You have to tell Enzyme to attach the component to this
// newly created element
wrapper = mount(<MyTextFieldComponent />, {
attachTo: document.getElementsByName('div')[0]
})
// In my case was easy to compare using id
// than using the whole element
expect(wrapper.find('input').props().id).toEqual(
document.activeElement.id
)
})
This worked for me when using mount and useRef hook:
expect(wrapper.find('input').get(0).ref.current).toEqual(document.activeElement)
Focus on the particular element can be checked using selectors.
const wrapper = mount(<MyComponent />);
const input = wrapper.find('input');
expect(input.is(':focus')).toBe(true);
Selecting by data-test attribute or something similar was the most straight forward solution I could come up with.
import React, { Component } from 'react'
import { mount } from 'enzyme'
class MyComponent extends Component {
componentDidMount() {
if (this.inputRef) {
this.inputRef.focus()
}
}
render() {
return (
<input data-test="my-data-test" ref={input => { this.inputRef = input } } />
)
}
}
it('should set focus on mount', () => {
mount(<MyComponent />)
expect(document.activeElement.dataset.test).toBe('my-data-test')
})
This should work
const wrapper = mount(<MyComponent />);
const input = wrapper.find('input');
expect(input).toHaveFocus();

Way to test the order of elements in React

Just want to implement the unit test for my react component with using the Jest and Enzyme.
Is there a way to test the order? Let's say I have component Button, and I want to render icon and text at the same time.
And of course it's good to provide the alignment option to the user(Icon first or Children first).
Button.js
class Button extends React.Component {
constructor() {
super();
}
render() {
let content;
const icon = (<Icon type='search' />);
if (this.props.iconAlign === 'right') {
content = (<span>{this.props.children} {icon}</span>
} else {
content = (<span>{icon} {this.props.children}</span>
}
return (
<button>{content}</button>
);
}
}
How to test the iconAlign props with Jest and Enzyme?
Check on the type of the component
Check icon first
var button = TestUtils.renderIntoDocument(<Button />);
var buttonNode = ReactDOM.findDOMNode(button);
expect(buttonNode.props.children[0].type.name).toEqual("Icon")
You could use a shallow render and compare the output. I am not familiar with the Jest syntax so that side of my example may be incorrect (I quickly referred to their website):
import { shallow } from 'enzyme';
describe(`Button`, () => {
it(`should render the icon on the right`, () => {
const children = <div>foo</div>;
const actual = shallow(
<Button iconAlign="right" children={children} />
);
const expected = (
<button><span>{children} <Icon type='search' /></span></button>
);
expect(actual.matchesElement(expected)).toBeTruthy();
});
});
And then you could create another test for the "left" align.
The enzyme version of #pshoukry's answer.
describe(`Button`, () => {
it(`should render icon on the right`, () => {
const wrapper = shallow(
<Button iconAlign="right">
<div>foo</div>
</Button>
);
const iconIsOnRight = wrapper.find('span').childAt(1).is(Icon);
expect(iconIsOnRight).toBeTruthy();
});
});
For reference, here is the enzyme shallow rendering API documentation: https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md

Resources