Set URL params while testing with Jest & Enzyme - reactjs

My component has:
class Search extends Component {
constructor(props) {
super(props);
this.state = {
searchTerm:
typeof this.props.match.params.searchTerm !== "undefined"
? this.props.match.params.searchTerm
: ""
};
}
and the test is:
test("Search should render correct amount of shows", () => {
const component = shallow(<Search shows={preload.shows} />);
expect(component.find(ShowCard).length).toEqual(preload.shows.length);
});
I get
TypeError: Cannot read property 'params' of undefined
How can I fix that or how to set query params in my test?

It seems like when outside the test, the Search component receives the match props correctly.
You could pass it as props when shallow rendering it in the test:
test("Search should render correct amount of shows", () => {
const match = { params: { searchTerm: 'foo' } }
const component = shallow(<Search shows={preload.shows} match={match}/>);
expect(component.find(ShowCard).length).toEqual(preload.shows.length);
});
And in that case, you're not changing the component under test in a bad way, your test case just found a bug, which is good and should be aimed in tests, and you improved the component by implementing a default props, making it more robust.

you should defined a location first in your it/test.
it('App init', async () => {
const location = {
...window.location,
search: '?scope=3&elementId=25924',
};
Object.defineProperty(window, 'location', {
writable: true,
value: location,
})
……
})

I also faced same issue and solved by adding a match prop in the component when you pass it in shallow or mount method. Here is the code:
test("Add param in component", () => {
const match = {params : { id: 1 } };
const component = shallow(<YourComponent match={match} />);
expect(/*Write your code here */);
});
As you can see I and having a param as id, replace with whatever is your's.

Related

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

Jest: How to test prop that is an anonymous function?

I have a component that loads another component, sending it an anonymous function as a prop:
export class Header extends Component {
constructor(props) {
super(props)
this.state = { activeTab: TAB_NAMES.NEEDS_REVIEW }
}
filterByNeedsReview() {
const { filterByNeedsReviewFn } = this.props
this.setState({ activeTab: TAB_NAMES.NEEDS_REVIEW })
filterByNeedsReviewFn()
}
...
render() {
return (
<Container>
...
...
<FilterTab
active={this.state.activeTab === TAB_NAMES.NEEDS_REVIEW}
name={TAB_NAMES.NEEDS_REVIEW}
count={40}
onClick={() => this.filterByNeedsReview()}
/>
...
...
</Container>
)
}
}
I have this failing test:
it('renders a filter tab with the right props for needs review', () => {
const filterByNeedsReviewFn = jest.fn()
expect(
shallowRender({ filterByNeedsReviewFn })
.find(FilterTab)
.findWhere(node =>
_.isMatch(node.props(), {
active: true,
name: 'Needs Review',
count: 40,
onClick: filterByNeedsReviewFn, //<-------------- THIS DOESN'T WORK
})
)
).toHaveLength(1)
})
How would I test that onClick is the right thing?
I believe you don't need to check how internal event handlers look like. You might be interested in different things: if triggering event handler changes component as you expect(.toMatchSnapshot() is much better here instead of testing structure manually with .toHaveLength) and if callback you've passed through props is called when it should to(.toHaveBeenCalled). What if component is changed some day not to just call .props.filterByNeedsReviewFn() but also do some stuff like calling anything else? should your test fail just because there is named method passed somewhere inside? I believe it is not.
So I see your test to be
it('renders a filter tab with expected props after clicking', () => {
const comp = shallowRender({});
comp.find(FilterTab).simulate('click');
expect(comp).toMatchSnapshot();
});
it('calls callback passed after clicking on filter tab', () => {
const filterByNeedsReviewFn = jest.fn()
const comp = shallowRender({ filterByNeedsReviewFn });
comp.find(FilterTab).simulate('click');
// let's ensure callback has been called without any unexpected arguments
expect(filterByNeedsReviewFn ).toHaveBeenCalledWith();
});
I don't think you actually needed this code but I wanted to illustrate how clear such approach could be. Your component have API: props callback it calls and render output. So we can skip testing internals without any pitfalls

Prop function in componentDidUpdate not being called in mounted enzyme test

I have a class-based component that has the following method:
componentDidUpdate(prevProps) {
if (prevProps.location.pathname !== this.props.location.pathname) {
this.props.onDelete();
}
}
I have the following test that is failing:
it(`should call the 'onDelete' function when 'location.pathName' prop changes`, () => {
const wrapper = mount(<AlertsList.WrappedComponent {...props} />);
// test that the deleteFunction wasn't called yet
expect(deleteFunction).not.toHaveBeenCalled();
// now update the prop
wrapper.setProps({ location: { ...props.location, pathName: "/otherpath" } });
// now check that the deleteFunction was called
expect(deleteFunction).toHaveBeenCalled();
});
where props is initialized in a beforeEach statement like so:
beforeEach(() => {
props = {
...
location: { pathName: "/" }
};
});
But my test fails in the second case after the setProps is called, where I would expect the lifecycle method to have run. What am I doing wrong here?
Issue was a typo, see comments under my original post.

Checking props of a child component with shallow rendering using enzyme

I have a problem understanding shallow rendering of enzyme.
I have a component WeatherApplication which has a child component CitySelection.
The CitySelection receives a property selectedCity which is hold in the WeatherApplications state.
The component:
export default class WeatherApplication extends React.Component {
constructor(props) {
super(props);
this.state = {
city : "Hamburg"
}
}
selectCity(value) {
this.setState({
city: value
});
}
render() {
return (
<div>
<CitySelection selectCity={this.selectCity.bind(this)} selectedCity={this.state.city} />
</div>
);
}
}
I tested sussessfully that the CitySeleciton exists and that the selectedCity is "Hamburg" and the correct function is passed.
Now I want to test the behaviour of the selectCity method.
it("updates the temperature when the city is changed", () => {
var wrapper = shallow(<WeatherApplication/>);
wrapper.instance().selectCity("Bremen");
var citySelection = wrapper.find(CitySelection);
expect(citySelection.props().selectedCity).toEqual("Bremen");
});
This test fails, because the value of citySelection.props().selectedCity is still Hamburg.
I checked that the render method of WeatherApplication is called again and this.state.city has the correct value. But I cannot fetch it via the props.
Calling wrapper.update() after selectCity() should do the trick:
it("updates the temperature when the city is changed", () => {
var wrapper = shallow(<WeatherApplication/>);
wrapper.instance().selectCity("Bremen");
wrapper.update();
var citySelection = wrapper.find(CitySelection);
expect(citySelection.props().selectedCity).toEqual("Bremen");
});

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