enzyme: ShallowWrapper instance of Stateless React component returns null
Hello,
After update to enzyme 3 and React 16, ShallowWrapper instance()
works a bit different. For Stateless React component it returns null
. Please check test example bellow:
import { shallow } from 'enzyme';
import React from 'react';
function Stateless({ name }) {
return <div>{name}</div>;
}
class Statefull extends React.Component {
render() {
return <div>{this.props.name}</div>;
}
}
describe('enzyme 3 with React 16', () => {
const props = {
name: 'Test',
};
describe('Stateless component', () => {
test('shallow wrapper instance should not be null', () => {
const wrapper = shallow(<Stateless {...props} />);
const instance = wrapper.instance();
expect(instance).not.toBe(null);
});
});
describe('Statefull component', () => {
test('shallow wrapper instance should not be null', () => {
const wrapper = shallow(<Statefull {...props} />);
const instance = wrapper.instance();
expect(instance).not.toBe(null);
});
});
});
As a result I have an error in next test enzyme with React 16 › Stateless component › shallow wrapper instance should not be null
. Also, these tests are passed with enzyme 3 + enzyme-adapter-react-15 + React 15.
setup
const Enzyme = require('enzyme');
const Adapter = require('enzyme-adapter-react-16');
Enzyme.configure({ adapter: new Adapter() });
package.json
{
...
"dependencies": {
...
"react": "^16.0.0",
"react-dom": "^16.0.0",
...
},
"devDependencies": {
...
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.1",
"jest": "^20.0.4",
"react-test-renderer": "^16.0.0",
...
},
...
}
So, is it configuration issue, or something else?
Thanks for any help.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 18
- Comments: 24 (13 by maintainers)
For people coming to this from a search engine, if the
wrapper.props()
solution above doesn’t work for you, trywrapper.getElement().props
—it worked for me.@mrchief : I have been in the similar scenario except that it was for react-native.
wrapper.props()
in the DatePicker example is going to show props of the top level component (in your case<div>
)If you follow this, the shallowWrapper is nothing but the top level component (atleast for SFC, thats what I have deduced so far)
I would suggest doing something like this:
Why would someone want to write such a test? I write to test the wiring of callbacks/handlers
Hope this helps
@ljharb In this examples it’s just a few lines above, but I have cases where test preconditions are a bit higher. And it’s easy to read
expects
if everything is in place. But thank you forwrapper.props()
.And probably NOTE section in this doc is valid only for Statefull React Component in case of React 16. Because, as I showed in example above,
wrapper.instance().props
might work a bit unexpected (wrapper.instance() // null
) with Stateless React Component (React 16). What do you think?In case if you need some help, I can create PR with updated doc if needed.
@mrchief that all seems correct to me. Your second SFC renders an element with a
onPageChange
prop. Your first SFC, however, renders adiv
with no props. Note that a shallow wrapper is what the component renders, not the component itself - separately, it makes no sense to assert on props you literally just passed in.wrapper.find(Something).props()
works too..instance().props()
- which was always redundant - is the one that doesn’t work on SFCs in React 16.This seems answered.
wrapper.props()
orwrapper.getElement().props
(which points to same object as wrapper.props) has some funkiness going on though.E.g., with the following SFC,
I get
wrapper.props(...).handleChange is not a function
error.However, with the following SFC:
seems to work fine without any issues.
I was using
instance.props
to test the default values of props.Checking
wrapper.props()
works except for the case where the incoming prop is used to modify a prop on the rendered component of the same name. For example, I’ve usedclassName
as a prop that can be used to apply an additional class to the className of the root element:If I’m expecting the
className
prop to be null by default, asserting thatwrapper.props().className
is null will fail because its value will include the classes applied within the component itself.I suppose I can check the number of classes applied to the root element, but it was nice to be able to test the values received by the functional component.
UPDATED:
…or I could set my default props like this and write tests against SomeComponent.defaultProps:
…but only if I’m not exporting the product of a HoC. In that case, I’d need to export the component for testing and the result of the HoC for use in the application.
Is there a better way of testing default props?
Final update:
@ljharb answered my question a while ago when he wrote:
Fair enough.