How does one access state on a nested React component wrapped by an HOC?
Solution 1
So it seems with the latest release of Enzyme there is a potential fix for this issue of accessing state on a child component.
Let's say we have <Foo>
(note the use of React Router's <Link>
)
class Foo extends Component {
state = {
bar: 'here is the state!'
}
render () {
return (
<Link to='/'>Here is a link</Link>
)
}
}
Note: The following code is only available in Enzyme v3.
Revisiting the test code, we are now able to write the following
it('puts the lotion in the basket', () => {
const wrapper = mount(
<MemoryRouter>
<Foo />
</MemoryRouter>
)
expect(wrapper.find(Foo).instance().state).toEqual({
bar: 'here is the state!'
})
})
Using wrapper.find(Child).instance()
we are able to access Child
's state even though it is a nested component. In previous Enzyme versions we could only access instance
on the root. You can also call the setState
function on the Child
wrapper as well!
We can use a similar pattern with our shallowly rendered tests
it('puts the lotion in the basket shallowly', () => {
const wrapper = shallow(
<MemoryRouter>
<Foo />
</MemoryRouter>
)
expect(wrapper.find(Foo).dive().instance().state).toEqual({
bar: 'here is the state!'
})
})
Note the use of dive
in the shallow test, which can be run on a single, non-DOM node, and will return the node, shallow-rendered.
Refs:
- https://github.com/airbnb/enzyme/issues/361
- https://github.com/airbnb/enzyme/issues/1289
- https://github.com/airbnb/enzyme/blob/master/docs/guides/migration-from-2-to-3
Solution 2
Thought it might be useful for you guys, as I stumbled upon this and have a fix.
In my case I have a component which is connected to redux.
class ComponentName extends Component {
...
}
export default connect(
mapStateToProps,
{
...
}
)(ComponentName );
connect() is obviously a HOC component. So how do we access the "ComponentName" here?
Very simple:
component
.find(ComponentName)
.children()
.first()
.props() // returns ComponentName's props
Related videos on Youtube
indiesquidge
Updated on June 04, 2022Comments
-
indiesquidge almost 2 years
I'm using Enzyme, and we can actually use the example component given in the docs as a foundation for my question.
Let's assume this
<Foo />
component uses a<Link>
component from ReactRouter and thus we need to wrap it in a<MemoryRouter>
for testing.Herein lies the problem.
it('puts the lotion in the basket', () => { const wrapper = mount( <MemoryRouter> <Foo /> </MemoryRouter> ) wrapper.state('name') // this returns null! We are accessing the MemoryRouter's state, which isn't what we want! wrapper.find(Foo).state('name') // this breaks! state() can only be called on the root! })
So, not exactly sure how to access local component state when using
<MemoryRouter>
.Perhaps I'm performing an ignorant test? Is trying to get/set component state bad practice in testing? I can't imagine it is, as Enzyme has methods for getting/setting component state.
Just not sure how one is supposed to access the internals of a component wrapped in
<MemoryRouter>
.Any help would be greatly appreciated!
-
xploreraj about 6 yearsairbnb.io/enzyme/docs/api/ReactWrapper/instance.html Still it shows tells
Gets the instance of the component being rendered as the root node passed into mount()
, and as I am usingmount
, still unable to access the state of child component, tellsstate
is not a function. My code is like:let wrapper = mount(<Parent />);
-
xploreraj about 6 yearsHere is my question: stackoverflow.com/questions/49487409/…
-
DarkGuardsman over 4 yearsAmazed that worked, but is there a way to design the component for testing to avoid needing this?