Way to test the order of elements in React - reactjs

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

Related

React - Jest Mock an inner component

I have a component that has a child component.
This child component has some rules to display its children content, and I want to mock it to display the content regardless its rules.
import MediaQuery from './component.media.query'
class Dumb extends Component { render() {
return (
<Fragment>
<div>Generic content</div>
<MediaQuery device="DESKTOP">
<div id="desktop">Specific desktop content</div>
</MediaQuery>
</Fragment>
) } }
I've tried some ways, and even the simplest is not working:
describe('Dumb component', () => {
jest.doMock('./component.media.query', () => {
const Comp = () => <div id='desktop'>Mocked</div>
return Comp
})
it('should display the desktop', () => {
const wrapper = mount(<Dumb />)
expect(wrapper.find('#desktop')).toExist()
})
})
Any ideas?
In your test you can mock it like this :
jest.mock('./component.media.query', () => () => 'MediaQuery')
//note that you have to enter the path relative to the test file.
With enzyme you can find the element like this
wrapper.find('MediaQuery')

How to get the DOM node from a Class Component ref with the React.createRef() API

I have these two components:
import { findDOMNode } from 'react-dom';
class Items extends Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.selectedItemRef = React.createRef();
}
componentDidMount() {
if (this.props.selectedItem) {
this.scrollToItem();
}
}
componentWillReceiveProps(nextProps) {
if (this.props.selectedItem !== nextProps.selectedItem) {
this.scrollToItem();
}
}
scrollToItem() {
const itemsRef = this.ref.current;
const itemRef = findDOMNode(this.selectedItemRef.current);
// Do scroll stuff here
}
render() {
return (
<div ref={this.ref}>
{this.props.items.map((item, index) => {
const itemProps = {
onClick: () => this.props.setSelectedItem(item.id)
};
if (item.id === this.props.selectedItem) {
itemProps.ref = this.selectedItemRef;
}
return <Item {...itemProps} />;
})}
</div>
);
}
}
Items.propTypes = {
items: PropTypes.array,
selectedItem: PropTypes.number,
setSelectedItem: PropTypes.func
};
and
class Item extends Component {
render() {
return (
<div onClick={() => this.props.onClick()}>item</div>
);
}
}
Item.propTypes = {
onClick: PropTypes.func
};
What is the proper way to get the DOM node of this.selectedItemRef in Items::scrollToItem()?
The React docs discourage the use of findDOMNode(), but is there any other way? Should I create the ref in Item instead? If so, how do I access the ref in Items::componentDidMount()?
Thanks
I think what you want is current e.g. this.selectedItemRef.current
It's documented on an example on this page:
https://reactjs.org/docs/refs-and-the-dom.html
And just to be safe I also tried it out on a js fiddle and it works as expected! https://jsfiddle.net/n5u2wwjg/195724/
If you want to get the DOM node for a React Component I think the preferred way of dealing with this is to get the child component to do the heavy lifting. So if you want to call focus on an input inside a component, for example, you’d get the component to set up the ref and call the method on the component, eg
this.myComponentRef.focusInput()
and then the componentRef would have a method called focusInput that then calls focus on the input.
If you don't want to do this then you can hack around using findDOMNode and I suppose that's why it's discouraged!
(Edited because I realized after answering you already knew about current and wanted to know about react components. Super sorry about that!)

Test Material UI Tabs and Enzyme

I'm having problems to test Material UI Tabs with Enzyme and Jest.
The problem is simulating the click on Tab component
I already tried with material shallow method (createShallow) and shallow of enzyme but the results are the same
My console.log on Tab component is returning my target element:
<WithStyles(Tab) label="Tab one" />
Here is my code:
const setup = (newProps) => {
const props = {
selected: 0,
changeTab: jest.fn(),
...newProps
}
const wrapper = shallowUntilTarget(<DashboardTabs { ...props } />, Base)
return {
props,
wrapper
}
}
The shallowUntilTarget is just a code snip to find the component recursively with .dive inside a HOC
https://github.com/airbnb/enzyme/issues/539
it('Should call the onChange function', () => {
const { wrapper, props } = setup()
const tab = wrapper.find({ label: 'Tab One' })
tab.simulate('click')
wrapper.update()
console.log(wrapper.debug()) // I should see a differente content after click in this tab
expect(props.changeTab.mock.calls.length).toBe(1) // the mock function call return 0 on the length
})
And nothing happens :(
You need to use WrappedComponent to dive into HOCs on components:
import { shallow } from 'enzyme';
wrapper = shallow(<DashboardTabs .WrappedComponent {...props} />).dive();
or
You can find an element like this:
wrapper.find(‘withStyles(Tab)’)
Maybe it requires a little tweaks according to your use case. But it would help you

How enzyme testing the render

How write a test for checking render element or not? For example, component like this, which render depends on existing list of cards:
class ButtonMore extends Component {
render() {
if (!this.props.listCards.length) {
return null;
}
return (
<button onClick={this.props.onClick} className="buttons button-more">
More
</button>
);
}
}
How would check render depends to props?
function setup() {
const props = {
listCards: [1, 2]
};
const wrapper = shallow(
<Provider store={store}>
<ButtonMore {...props} />
</Provider>
);
return {
props,
wrapper
};
}
describe("ButtonMore component", () => {
const { wrapper } = setup();
it("should render button if cards length more then 0", () => {
expect(wrapper.prop("listCards").length).toBe(2); // that's ok
expect(wrapper.find("button").length).toBe(1); // received 0, not 1
});
});
Unfortunately, i don't finded solution in the enzyme documentation.
First of all: "!this.props.listCards.length" checks only that listCards has the property length. You have to ensure that listCards is an array and that the length is more than 0.
Now ensure that your wrapper contains the right data: you can do it with console.log(wrapper.debug());
At the end.. If you don't need the store you can even not use the Provider. Render just ButtonMore and pass onClick and listCards as props.

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

Resources