How enzyme testing the render - reactjs

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.

Related

Conditonal component still renders - ReactJS

I'm learning react and wanted to try creating a loading component that shows a loading text until a condition is met i.e. the props has the correct information.
The problem is that the element is still loading even if the condition is not met:
Leading Component:
import React from 'react';
const Loading = ({ condition, children }) => (<div>{condition ? children :
'Loading'}</div>);
export default Loading;
Here is my render method for a component that uses the Loading Component:
return
(<Loading condition={props.data && props.data.result && props.data.result.length > 1}>
<div> { ViewHelper.getCatalogItems(props.data) }</div></Loading>);
Now my problem is I'm getting an error when calling { ViewHelper.getCatalogItems(props.data) } becauuse props.data is undefined however I was hoping that the Loading Component wouldn't call the function if the ternary condition in the LoadingComponent was false.
if I change ViewHelper.getData to just some string value, everything seems to work and 'Loading ' is displayed.
Thanks
The fact that Loading component doesn't use children doesn't mean that children aren't rendered. Otherwise there would be nothing to pass as props.children to parent component.
As can be seen in this example, child expression is evaluated despite children prop ignored in parent component.
A proper way to handle this and prevent eager children rendering is to use render prop recipe, which is also known as function as a child:
const Loading = ({ condition, children }) => (
<div>{condition && children ? children() : 'Loading'}</div>
);
...
<Loading condition={props.data && props.data.result && props.data.result.length > 1}>
{() => (
<div> { ViewHelper.getCatalogItems(props.data) }</div>
)}
</Loading>
Notice that since props.children is a function, it's used as children() in ternary expression.
Or use a HOC for components:
const withLoading = (Comp) =>
({ condition, ...props }) => (
<div>{condition ? <Comp {...props} /> : 'Loading'}</div>
)
);
...
const LoadingCatalogItemsComponent = withLoading(CatalogItemsComponent);
the children parameter received in the Loading component will have already rendered in the parent (try logging the content of children from Loading)
getCatalogItems will be called regardless of the conditional
cases where props.data need to be handled here. there are multiple ways to do this:
defaultProps or type checking in general
input validation for getCatalogItems
destructuring assignment
default function parameters
Updated answer: as estus points out below, render props are probably a good way to do this. Here's an example:
import React from "react";
import ReactDOM from "react-dom";
const Loading = ({ condition, render }) => {
if (condition) {
return render();
} else {
return "Loading";
}
};
const Thing = ({ data }) => {
console.log(data);
return data.map(d => <li>{d}</li>);
};
class App extends React.Component {
state = {
data: [1, 2, 3]
};
render() {
return (
<Loading
condition={this.state.data.length > 1}
render={() => {
return <Thing data={this.state.data} />;
}}
/>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
CodeSandbox here.
As #estus said, HOCs and render props are two popular methods. Moving:
<div>{ ViewHelper.getCatalogItems(props.data)}</div>
into its own component (which is passes the prop, e.g., <CatalogItems {...props} />) will also stop you from getting errors. As long as the code isn't in the actual render method; otherwise, it's fired, regardless of whether React would have actually rendered it.
Example:
const Loading = ({ condition, children }) => (
<div>{condition ? children : "Loading in 3 seconds"}</div>
);
// now that it's in its own component the code isn't run until the component actually renders
const CatalogItems = ({ data }) => data.result.map(item => item);
class App extends React.Component {
state = {
data: null
};
// dummy API call
componentDidMount() {
setTimeout(
() => this.setState({ data: { result: ["cat ", "dog ", "mouse "] } }),
3000
);
}
render() {
const props = this.state; // let's just pretend these were inherited props
return (
<Loading
condition={
props.data && props.data.result && props.data.result.length > 1
}
data={props.data}
>
<CatalogItems {...props} />
</Loading>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<div id='root'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.1/umd/react-dom.development.js"></script>

Redux-Form : How to mock formValueSelector in Jest

I have a component Demo whose Label depends on the current value of a field in the redux-form state. I am using formValueSelector to get the current value of "param" field from the form state. It works fine. However, while running npm test, the selector function always returns undefined. How can I mock it?
Please let me know if I am doing this in a wrong way.
I have a component like
class Sample extends React.Component {
render() {
const {param, state} = this.props;
const selector = formValueSelector('sampleform');
return (
<div>
<Demo
name="name"
label={selector(state, `${param}`)}
/>
</div>
);
}
}
export default Sample;
and, testing code is like
function setup() {
const spy = jest.fn();
const store = createStore(() => ({}));
const Decorated = reduxForm({ form: 'sampleform' })(Sample);
const props = {
"param":"keyOfState",
"state":{"keyOfState":"Label"}
}
const mockedComponent = <Provider store={store}>
<MuiThemeProvider muiTheme={MuiStyles()}>
<Decorated {...props}>
<span></span>
</Decorated>
</MuiThemeProvider>
</Provider>;
return {
props,
mockedComponent}
}
describe('Sample Component', () => {
it('should render the snapshot', () => {
const { mockedComponent } = setup()
const tree = renderer.create(
mockedComponent
).toJSON();
expect(tree).toMatchSnapshot();
});
});
You aren't providing the formValueSelector with an adequate mock for the state that the selector expects.
Solution: The selector expects the global state object provided by redux. The current mocked state doesn't reflect this. Changing the mock to the shape expected fixes the issue:
It is of this shape:
{
form: {
sampleform: {
values: {
keyOfState: "Label"
}
}
}
}
Note: the object stored at the sampleform key includes more entries, but they are irrelevant for the mock.
Here is a link to a reproduction that resolves your issue:https://github.com/mjsisley/reduxFormMockIssue
Please note: I was directed here by Matt Lowe. I am the developer that has worked with him on a number of other projects.
For anyone in the future - if for some reason you actually need to mock FormValueSelector, I just exported a wrapper for it from my Helpers module:
export const tableTypeSelector = formValueSelector('toggle')
and then mocked that:
import * as Helpers from 'helpers'
...
stub = sinon.stub(Helpers, 'tableTypeSelector').returns('charges')

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

Call a React component method from outside

I want to call a method exposed by a React component from the instance of a React Element.
For example, in this jsfiddle. I want to call the alertMessage method from the HelloElement reference.
Is there a way to achieve this without having to write additional wrappers?
Edit (copied code from JSFiddle)
<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>
var onButtonClick = function () {
//call alertMessage method from the reference of a React Element! Something like HelloElement.alertMessage()
console.log("clicked!");
}
var Hello = React.createClass({displayName: 'Hello',
alertMessage: function() {
alert(this.props.name);
},
render: function() {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
var HelloElement = React.createElement(Hello, {name: "World"});
React.render(
HelloElement,
document.getElementById('container')
);
There are two ways to access an inner function. One, instance-level, like you want, another, static level.
Instance
You need to call the function on the return from React.render. See below.
Static
Take a look at ReactJS Statics. Note, however, that a static function cannot access instance-level data, so this would be undefined.
var onButtonClick = function () {
//call alertMessage method from the reference of a React Element!
HelloRendered.alertMessage();
//call static alertMessage method from the reference of a React Class!
Hello.alertMessage();
console.log("clicked!");
}
var Hello = React.createClass({
displayName: 'Hello',
statics: {
alertMessage: function () {
alert('static message');
}
},
alertMessage: function () {
alert(this.props.name);
},
render: function () {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
var HelloElement = React.createElement(Hello, {
name: "World"
});
var HelloRendered = React.render(HelloElement, document.getElementById('container'));
Then do HelloRendered.alertMessage().
You can do like
import React from 'react';
class Header extends React.Component{
constructor(){
super();
window.helloComponent = this;
}
alertMessage(){
console.log("Called from outside");
}
render(){
return (
<AppBar style={{background:'#000'}}>
Hello
</AppBar>
)
}
}
export default Header;
Now from outside of this component you can called like this below
window.helloComponent.alertMessage();
1. With React hooks - useImperativeHandle + useRef
const MyComponent = ({myRef}) => {
const handleClick = () => alert('hello world')
useImperativeHandle(myRef, () => ({
handleClick
}), [/* dependencies (if any) */])
return (<button onClick={handleClick}>Original Button</button>)
}
MyComponent.defaultProps = {
myRef: {current: {}}
}
const MyParentComponent = () => {
const myRef = React.useRef({})
return (
<>
<MyComponent
myRef={myRef}
/>
<button onClick={myRef.current.handleClick}>
Additional Button
</button>
</>
)
}
2. With only React hook - useRef
const MyComponent = ({myRef}) => {
const handleClick = () => alert('hello world')
myRef.current.handleClick = handleClick
return (<button onClick={handleClick}>Original Button</button>)
}
MyComponent.defaultProps = {
myRef: {current: {}}
}
const MyParentComponent = () => {
const myRef = React.useRef({})
return (
<>
<MyComponent
myRef={myRef}
/>
<button onClick={myRef.current.handleClick}>
Additional Button
</button>
</>
)
}
Good Luck...
I've done something like this:
class Cow extends React.Component {
constructor (props) {
super(props);
this.state = {text: 'hello'};
}
componentDidMount () {
if (this.props.onMounted) {
this.props.onMounted({
say: text => this.say(text)
});
}
}
render () {
return (
<pre>
___________________
< {this.state.text} >
-------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
</pre>
);
}
say (text) {
this.setState({text: text});
}
}
And then somewhere else:
class Pasture extends React.Component {
render () {
return (
<div>
<Cow onMounted={callbacks => this.cowMounted(callbacks)} />
<button onClick={() => this.changeCow()} />
</div>
);
}
cowMounted (callbacks) {
this.cowCallbacks = callbacks;
}
changeCow () {
this.cowCallbacks.say('moo');
}
}
I haven't tested this exact code, but this is along the lines of what I did in a project of mine and it works nicely :). Of course this is a bad example, you should just use props for this, but in my case the sub-component did an API call which I wanted to keep inside that component. In such a case this is a nice solution.
With the render method potentially deprecating the returned value, the recommended approach is now to attach a callback ref to the root element. Like this:
ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
which we can then access using window.helloComponent, and any of its methods can be accessed with window.helloComponent.METHOD.
Here's a full example:
var onButtonClick = function() {
window.helloComponent.alertMessage();
}
class Hello extends React.Component {
alertMessage() {
alert(this.props.name);
}
render() {
return React.createElement("div", null, "Hello ", this.props.name);
}
};
ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>
You can just add an onClick handler to the div with the function (onClick is React's own implementation of onClick) and you can access the property within { } curly braces, and your alert message will appear.
In case you wish to define static methods that can be called on the component class - you should use statics. Although:
"Methods defined within this block are static, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method." (source)
Some example code:
const Hello = React.createClass({
/*
The statics object allows you to define static methods that can be called on the component class. For example:
*/
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
alertMessage: function() {
alert(this.props.name);
},
render: function () {
return (
<div onClick={this.alertMessage}>
Hello {this.props.name}
</div>
);
}
});
React.render(<Hello name={'aworld'} />, document.body);
Hope this helps you a bit, because i don't know if I understood your question correctly, so correct me if i interpreted it wrong:)
It appears statics are deprecated, and the other methods of exposing some functions with render seem convoluted. Meanwhile, this Stack Overflow answer about debugging React, while seeming hack-y, did the job for me.
If you are in ES6 just use the "static" keyword on your method from your example would be the following: static alertMessage: function() {
...
},
Hope can help anyone out there :)
I use this helper method to render components and return an component instance.
Methods can be called on that instance.
static async renderComponentAt(componentClass, props, parentElementId){
let componentId = props.id;
if(!componentId){
throw Error('Component has no id property. Please include id:"...xyz..." to component properties.');
}
let parentElement = document.getElementById(parentElementId);
return await new Promise((resolve, reject) => {
props.ref = (component)=>{
resolve(component);
};
let element = React.createElement(componentClass, props, null);
ReactDOM.render(element, parentElement);
});
}
class AppProvider extends Component {
constructor() {
super();
window.alertMessage = this.alertMessage.bind(this);
}
alertMessage() {
console.log('Hello World');
}
}
You can call this method from the window by using window.alertMessage().
method 1 using ChildRef:
public childRef: any = React.createRef<Hello>();
public onButtonClick= () => {
console.log(this.childRef.current); // this will have your child reference
}
<Hello ref = { this.childRef }/>
<button onclick="onButtonClick()">Click me!</button>
Method 2: using window register
public onButtonClick= () => {
console.log(window.yourRef); // this will have your child reference
}
<Hello ref = { (ref) => {window.yourRef = ref} }/>`
<button onclick="onButtonClick()">Click me!</button>
With React17 you can use useImperativeHandle hook.
useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
In this example, a parent component that renders would be able to call inputRef.current.focus().
Though this question is closed, I would like to share another approach.
Here's what worked for me:
Child Component
Child component accepts a prop, let's call it onExportedMethods, the aim is to return the set of instance methods that this component wants to give to consumers.
The decision of what needs to be exposed is done at constructor level.
Consumer Component
pass method for prop onExportedMethods & in the handler keep copy of the set of methods Child component exposes.
Whenever required, parent component can call the exposed method
Checkout the sample here
For dynamic components I used the getDerivedStateFromProps method with props.
You can create function that update the props of the child component, The getDerivedStateFromProps in the child component will handle the update of the props for you.
For example:
class Parent extends React.Component
{
constructor(props)
{
super(props);
this.state = { selectMachine: '1' };
this.setComponent = null;
}
handleMachineChange = (e) =>{
this.setState({selectMachine: e.target.value})
}
}
class Child extends React.Component
{
state = {
programForm: {
machine_id: '1',
}
}
constructor(props)
{
super(props);
}
static getDerivedStateFromProps(props, state) {
if(props.selectMachine !== state.programForm.machine_id){
//Change in props
return{
programForm: { ...state.programForm, machine_id: props.selectMachine }
};
}
return null; // No change to state
}
}

Resources