When to use "Component.WrappedComponent" when writing enzyme tests - reactjs

What I'm trying to do:
I'm trying to use shallow rendering from enzyme by following the below pattern which works for many other components in my project.
describe('>> MyComponent - Render', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<MyComponent.WrappedComponent
actions={{}}
history={}
/>);
});
it("test something", () => { expect(wrapper).toEqual(1); });
});
What's the problem I have:
I got an error saying "Cannot read property 'contextTypes' of undefined", which means wrapper is undefined. But when I change <MyComponent.WrappedComponent /> to just <MyComponent />, the tests are successful. This is my code:
describe('>> Legends - render', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<Legends textsAndColor={[]} />);
});
it('+++ render the component', () => {
expect(wrapper.length).toEqual(1);
});
it('+++ match snapshot', () => {
expect(wrapper).toMatchSnapshot();
});
});
Question I have:
What exactly does .WrappedComponent do ? And why does <MyComponent /> works but not <MyComponent.WrappedComponent /> ?

By using .WrappedComponent you are getting access to component, wrapped by redux's connect function.
I assume that most of your components are connected (since there are no problems with use of .WrappedComponent) and component that throwing described error isn't connected.
I suggest you to read redux docs to find out how to write tests for this case. Briefly said they suggest to have default export for your connected component and non-default for raw component. And then import only raw component for testing purposes, like this:
import { MyComponent } from './path/to/my/component`;
after this you will be able to mount (or shallow) your raw component like this:
describe('>> MyComponent - Render', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<MyComponent />);
}
});

Related

Why is JEST testing giving "Could not find "store" error when call setState?

I'm trying to test this:
(I need to confirm that when selectedDevice is called with DESKTOP prop, it calls openModal and that method sets the state of modalOpen to true)
openModal = () => {
this.setState({ modalOpen: true });
};
selectedDevice = () => {
const { device } = this.props;
const isMobile = device === MOBILE;
if (isMobile) {
this.closeWindow();
} else {
this.openModal();
}
};
and I'm testing like this (with JEST)
test('should openModal be called', () => {
const wrapper = mount(<Component
{...sampleProps}
deviceType={DESKTOP}
/>);
const selectedDevice = jest.spyOn(wrapper.instance(), 'selectedDevice');
selectedDevice();
expect(wrapper.state().modalActivated).toEqual(true);
});
Apparently, it seems to be reaching the openModal method in my component. However, I'm getting this error:
Invariant Violation: Could not find "store" in either the context or props of "Connect(Styled(Component))". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Styled(Component))".
36 |
37 | openModal = () => {
> 38 | this.setState({ modalOpen: true });
| ^
I saw another solutions to that error message, but nothing seems to work for this specific error.
I already tried wrapping the component inside a Provider component with no luck.
You're getting the error because you're using a component which is wrapped inside of the connect HOC from react-redux and the connect HOC needs the redux Provider component with a state.
Your code should be something like this:
test("should openModal be called", () => {
const wrapper = mount(
<Provider store={CreateANewStoreForTest}>
<Component {...sampleProps} deviceType={DESKTOP} />
</Provider>
);
const selectedDevice = jest.spyOn(wrapper.instance(), "selectedDevice");
selectedDevice();
expect(wrapper.state().modalActivated).toEqual(true);
});
and for data on how to create a store read the DOC here

I am getting error on using toHaveBeenCalled() in jest?

I am getting error on using toHaveBeenCalled, Please correct me where am going wrong
code:
jsx
<item
onClick={ load ? undefined : onClick}
>
test
test('render', () => {
const MockItems = jest.fn()
const prop = {
onClick: MockItems,
}
const onclickProp= output.find(item).props().onClick
onclickProp(undefined)
expect(props.onClick).toHaveBeenCalled()//error
}
error
expect(props.onClick).toHaveBeenCalled()
Warning: An update to null inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
If the item is inside any other component as a child component you need to dive() on the wrapper component. Shallow rendering gives you access to only outer/parent component layout.
describe('item parent Component', () => {
let wrapper,instance
beforeEach(() => {
mockProps = {
handleClick: jest.fn()
}
const component = (<parent {...mockProps} />)
wrapper = shallow(component).dive()
})
it('item is clicked', () => {
wrapper.find(item).simulate('click')
expect(handleClick).toHaveBeenCalled()
})
)}
<item onClick={ load ? undefined : onClick} >

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 to test or get value from state in react?

Hi could you please tell me How to test or get value from state in react ?
getting error
wrapper.instance(...).handleClickShowPassword is not a function
here is my code
https://codesandbox.io/s/l2lk4n794l
it("toggle showpassword value", () => {
wrapper.setState({ showPassword: false });
wrapper.instance().handleClickShowPassword();
expect(wrapper.state.showPassword).toEqual(true);
});
Since LoginContainer is an wrapped with an HOC, you either need to export the component without withStyles HOC or use dive on the wrapper to get the instance of the component. Also state is a function on component instance and hence you need to call it to access state
describe("<LoginContainer/>", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<LoginContainer />);
});
it("toggle showpassword value", () => {
const comp = wrapper.dive();
comp.dive().setState({ showPassword: false });
comp.instance().handleClickShowPassword();
expect(comp.state("showPassword")).toEqual(true);
});
});
Working demo

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