enzyme test, context not rendering elements - reactjs

I am using enzyme to write my tests, before adding a context to my component which is the consumer component in this case, the snapshot rendered is not showing any elements and every time i add a dive() or shallow() I got the same error
how can i access the elements while using context
const wrapper = shallow(
<MyComponent {...initialProps} store={mockStore(initialState)} />,
{context},
);
const contents = wrapper
.dive() // dive in connect
.dive() // dive in withLogss
.dive() // dive in Motion
.find("MyComponent")
.dive(); // dive in Host
expect(contents.context()).toEqual({myBoolean: true});
it("should render properly", () => {
expect(contents).toMatchSnapshot();
});
Result:
<ContextConsumer>
<Component />
</ContextConsumer>

Enzyme prior to v3.10.0 lacked support of React's new Context API.
From the v3.10.0 Changelog:
shallow: Support rendering and dive()ing createContext() providers and consumers (#1966)
Make sure you are using enzyme v3.10.0 or later and enzyme-adapter-react-16 v1.15.1 or later.

Related

Enzyme: Test children rendering failling with mount but passes with shallow

I'm using Enzyme + Jest to test some React components.
I have the following test:
describe('<Modal />', () => {
let wrapper;
it('should render children props', () => {
wrapper = shallow(<Modal />);
wrapper.setProps({
children: <div className='should-render'>This should be rendered</div>
});
expect(wrapper.find('.should-render').length).toEqual(1);
});
});
And it works just find. But, if I replace the shallow method from enzyme with mount the test fails (can't find a element with .should-render class).
Is this the expected behavior? I though that the difference between shallow and mount was the ability to access lifecycle methods but render worked the same.
Ok. So the problem was my lack of understanding of how mount works.
My Modal component has a state variable called show that prevents the element from mounting if it's set to false (I'm wrapping react-boostrap modal component, that has this beahavior). By default, this state variable it's false and since the children are being rendered in the body of the modal, no children were found because the element wasn't beign mounted.

Test if props are passed (Without using Enzyme)

I want to test if my props are passed, but without using Enzyme,
I tried to find documentation on the internet, but all the tutorials are with Enzyme.
describe('App Component', () => {
it('renders the Counter wrapper', () => {
const wrapper = shallow(<App />);
expect(wrapper.find(Counter)).to.have.length(1);
});
it('passes all props to Counter wrapper', () => {
const wrapper = shallow(<App />);
let counterWrapper = wrapper.find(Counter);
expect(counterWrapper.props().counter).to.equal(0);
wrapper.setState({ counter: -1 });
counterWrapper = wrapper.find(Counter);
expect(counterWrapper.props().counter).to.equal(-1);
});
Could someone help me? Can I do this with jest? Or I do need a third-party library like 'react-testing-library'?
Enzyme shallow is primarily intended for isolated unit tests like the one that was listed, only the implementation of tested unit is asserted. It offers some instrumentation (and also non-compliant behaviour) that doesn't exist in React itself.
react-testing-library is primarily intended for blackbox functional tests, the effects of units on resulting DOM are asserted.
React's own ReactTestUtils also offer some basic functionality, a subset of Enzyme and react-testing-library features, including shallow renderer for isolated tests.
It's possible to do isolated tests and assert the implementation without Enzyme, this results in boilerplate code. The approach isn't specific to testing library, it could be achieved with any renderer, including React's test renderer's snapshot testing. Everything (Counter component) but tested unit (App component) should be mocked with Jest, e.g.:
it('passes all props to Counter wrapper', async () => {
const CounterMock = jest.fn(() => 'Counter');
jest.mock('./counter-module', () => CounterMock);
const App = await import('./app-module');
// render <App/> and assert that the result is <div>Counter</div>
expect(CounterMock).toBeCalledWith({ counter: 0 });
});

Enzyme Test Code Memory cleanup

I have been looking at a lot of examples for testing react and redux applications using Enzyme and Jest, and there are very few that even mention code cleanup. When using shallow or mount do you not explicitly need to call unmount or detach to try to keep the memory bloat and runtime down?
There is a case where we will want to use detach to cleanup. Let's look at the simple shallow and mount case first.
Assigning to variables
This 'simple' case is where we simply assign the render to a var/const/let.
If we look at the (cut down) example of using Jest and Enzyme from the Enzyme Github.
describe('<MyComponent />', () => {
it('renders three <Foo /> components', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper.find(Foo)).to.have.lengthOf(3);
});
it('renders an `.icon-star`', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper.find('.icon-star')).to.have.lengthOf(1);
});
});
We can see the shallow method being called and the result being assigned to a const. The result is a ShallowWrapper object.
As const has a block scope when the execution leaves the block it is defined - in this case the test arrow function - the Javascript engine will automatically deallocate the ShallowWrapper memory.
It's because of this we don't need to worry about unmounting - this is only used to test specific Component lifecycle methods.
Attaching Components to DOM
We can also attach components to the DOM.
If we look at the test case automatically generated by the create-react-scripts.
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
This example doesn't use Enzyme, but it's the same concept as to when you use attachTo in the Enzyme mount function.
We can see our Component is being attached to a div in the document and then ReactDOM.unmountComponentAtNode being called to cleanup. This is actually what detach calls.
We need to do this cleanup because a reference to our rendered Component exists outside our block scope and therefore will not be deallocated when execution exits this block.

React Native Testing - How to TDD and test components beyond snapshots?

I'm really struggling with how to test React Native components beyond using snapshots from jest. Those are great for testing the look of something based on some data passed into a component, but it doesn't seem like there is a way to test events or event handlers, checking if event listeners were setup or disconnected correctly in lifecycle methods, etc...like it feels like I'm either missing something or the tooling is not complete.
Also on a side note snapshot testing feels backwards in terms of TDD since you can only write your tests once you have your application code...any thoughts on this?
With snapshot test you can only check the values in props and styles etc. To check some logic in container i used 'shallow' from enzyme ;)
You can still use snapshots with events for things like: click a button and verify the rendered output after the click:
it('should render Markdown in preview mode', () => {
const wrapper = shallow(
<MarkdownEditor value="*Hello* Jest!" />
);
expect(wrapper).toMatchSnapshot();
wrapper.find('[name="toggle-preview"]').simulate('click');
expect(wrapper).toMatchSnapshot();
});
To test that event handler was called property you can do something like that:
it('should pass a selected value to the onChange handler', () => {
const value = '2';
const onChange = jest.fn();
const wrapper = shallow(
<Select items={ITEMS} onChange={onChange} />
);
expect(wrapper).toMatchSnapshot();
wrapper.find('select').simulate('change', {
target: { value },
});
expect(onChange).toBeCalledWith(value);
});
(Both examples are from my article on testing React components with Jest.)

TDD with Enzyme shallow and mount?

When I render a component using shallow or mount, the component is rendered in memory and is not attached to DOM.
This means that, while I run my tests, I don't actually see any output in the browser.
How am I supposed to do Test Driven Development if I can't see if the component I'm developing looks as it should? (css style, sizes etc)
If you want your component to be rendered an mounted une the "browser", than use the render() method of Enzyme. Be sure to have a window available (see jsdom to fake a window). But IMO, you should be able to do all of your test with shallow or mount, the API is nice
How am I supposed to do Test Driven Development if I can't see if the
component I'm developing looks as it should? (css style, sizes etc)
The purpose of Enzyme is not visual regression test, for that you will have to use tools like PhantomJS, related article https://css-tricks.com/visual-regression-testing-with-phantomcss/
You can achieve some kind of styling testing by checking if your component has the right selectors when they are rendered. e.g.
it( 'should add the "selected" class when a click happend to one of the Elements', () => {
const wrapper = mount( <Elements /> );
const option = wrapper.find( 'h5' );
expect( option.hasClass( 'selected' ) ).to.equal( false );
option.simulate( 'click' );
expect( option.hasClass( 'selected' ) ).to.equal( true );
} );

Resources