http://airbnb.io/enzyme/docs/api/
There are cases, where you may have a connected component, or you've had to wrap a component for one reason or another. Using
shallow
instead of mount
has less overhead, but you can't use find
since it's only one level deep. That's where dive
comes in. Imagine you have a component like this
import React from 'react';
import ComponentA from './ComponentA';
const WrappedComponent = (props) => {
return (props.retComp) ? <ComponentA {...props} /> : null;
};
export default WrappedComponent;
And in your test you want to ensure that any custom props have propagated to ComponentA
.
it('should propagate props to wrapped component', () => {
const fu = 'bar';
const wrapper = shallow(<WrappedComponent fu={fu} />);
const comp = wrapper.dive(); // go from `WrappedComponent` to `ComponentA`
const compProps = comp.props();
expect(cS.name()).toBe('ComponentA'); // ensure you're testing the correct component
expect(currProps.fu).toBe(fu);
});
For components that use forwardRef
you'll want to treat them like connected components and export the forwarded item as
the default
, and the plain component as a named export.
class MyComponent extends Component {}
MyComponent.displayName = 'MyComponent';
const Forwarded = forwardRef((props, ref) => <MyComponent {...props} refProp={ref} />);
// It's important to set the `displayName` so that you can easily targed the forwarded component in tests.
Forwarded.displayName = 'ForwardedMyComponent';
export default Forwarded;
// OR this if `refs` is an Object
const Forwarded = forwardRef((props, refs) => <MyComponent {...props} {...refs} />);
export {
MyComponent,
};
For components that call createRef
you'll have to mock out createRef
in your test.
import React, { createRef, forwardRef } from 'react';
jest.mock('react', () => {
const actualModule = jest.requireActual('react');
return {
...actualModule,
createRef: jest.fn(),
};
});
describe('Test', () => {
const Comp = forwardRef((props, ref) => <div className="child" {...props} namedRef={ref} />);
const CompWithMultipleRefs = forwardRef((props, refs) => <div className="child" {...props} {...refs} />);
let props, ref, ref1, ref2;
beforeEach(() => {
props = { fu: 'bar' };
// You can mock the same value for all calls.
ref = { current: {} };
createRef.mockReturnValue(ref);
// OR if you have multiple ordered calls to createRef, you could return a specific instance for every call.
ref1 = { current: {} };
ref2 = { current: {} };
createRef.mockReturnValueOnce(ref1);
createRef.mockReturnValueOnce(ref2);
});
describe('func', () => {
it('should forward ref', () => {
const wrapper = shallow(<Comp {...props} ref={ref} />);
expect(wrapper.find('.child').props().namedRef).toEqual(ref);
});
});
});
Imagine a scenario where you've triggered a function on your component that's triggered a state change and a render.
You should be able to call wrapper.find('Component.new-class)
(if new-class
is added on state change). However
in some cases you won't get the expected results, so you throw a console.log(wrapper.debug())
in, and sure enough
you're class wasn't added. That's where wrapper.update()
comes in. Calling that method updates the wrapper reference
and you should now get the expected results.
In most cases you can use wrapper.update()
which will wait for the instance's state to be updated, then you
execute your assetions. If this fails, continue reading.
There will be some cases where a function calls setState
internally and there's no state callback to add your
assertions to. In those cases you'll need to use process.nextTick
.
NOTE: If there are any uncaught errors within the process.nextTick
call, Jest will completely exit.
it('should do something', (done) => {
instance.setState({
toggled: true,
}, () => {
instance.someCallBackThatCallsSetState();
process.nextTick(() => {
expect(instance.state).toEqual(expect.objectContaining({
// some props
}));
done();
});
});
});
Example Class
class Component {
constructor() {
this.someMethod = this.someMethod.bind(this);
}
someMethod() {}
}
How to mock and test
jest.spyOn(Component.prototype, 'someMethod');
Component.prototype.someMethod.mockImplementation(jest.fn());
// render your component here via `mount` or `shallow`
wrapper.find('Something').simulate('click');
expect(Component.prototype.someMethod).toHaveBeenCalled();
// important to restore the function otherwise it could bleed over into other tests.
Component.prototype.someMethod.mockRestore();