1
votes

I've started using jest and enzyme recently. I'm writing simple code to learn jest & enzyme.

There is one test I can't pass. I've had this problem for a long time.

I don't understand why the first assertion below is okay while the second assertion below is not.

expect(component.find(CommentBox).dive().find('.comment-box').exists()).toBe(true);

expect(component.find(CommentList).dive().find('.comment-list').exists()).toBe(true);

These components are siblings.

<div>
    <div>Hello World!</div>
    <CommentBox />
    <CommentList />
</div>

Could anyone please help me understand what I'm doing wrong?

Here are all related codes and log.

Test Result Log

FAIL  src/__tests__/components/App.test.js

● App › shows a comment list
Method “dive” is only meant to be run on a single node. 0 found instead.

at ShallowWrapper.single (node_modules/enzyme/build/ShallowWrapper.js:1516:17)
at Object.<anonymous> (src/__tests__/components/App.test.js:38:57)
    at Promise (<anonymous>)
    at <anonymous>

App.test.js

import React, { Component } from 'react';
import { shallow, mount} from 'enzyme';

import App from '../../components/App';
jest.unmock('../../components/App');

import CommentBox from '../../components/CommentBox';
import ConnectedCommentList, { CommentList } from '../../components/CommentList';


describe('App', () => {

    let component;

    beforeEach(() => {
        component = shallow(<App />);
    });

    //This test passes!
    it('shows a comment box', () => {

        expect(component.find(CommentBox).dive().find('.comment-box').exists()).toBe(true);

    });

    //This test fails!!
    it('shows a comment list', () => {

        expect(component.find(CommentList).dive().find('.comment-list').exists()).toBe(true);

    })

});

App.js

import React, { Component } from 'react';

import CommentBox from './CommentBox';
import CommentList from './CommentList';

class App extends Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <div>Hello World!</div>
                <CommentBox />
                <CommentList />
            </div>
        )
    }
}

export default App;

CommentList.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

const propTypes = {};
const defaultProps = {};

export const CommentList = (props) => {

    const list = props.comments.map((comment) => {

        return <li key={comment}>{comment}</li>
    });

    return (
        <ul className="comment-list">
            {list}
        </ul>
    )

};

function mapStateToProps(state) {
    return {
        comments: state.comments
    }
}

CommentList.propTypes = propTypes;
CommentList.defaultProps = defaultProps;

export default connect(mapStateToProps)(CommentList);

Additional Info

I'm using shallow method instead of mount method because if I use mount method, then I get this error Invariant Violation: Could not find "store" in either the context or props of "Connect(CommentList)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(CommentList)". instead.

JSX of CommentBox

        <form onSubmit={this.handleSubmit} className="comment-box">
            <textarea
                value={this.state.comment}
                onChange={this.handleChange}
            />
            <button action="submit">Submit</button>
        </form>

JSX of CommentList

    <ul className="comment-list">
        {list}
    </ul>

UPDATE!

it('shows a comment list', () => {
    console.log(component.debug());
})

I used debug method to see what enzyme is rendering. This is the result.

<div>
  <div>
    Hello World!
  </div>
  <CommentBox />
  <Connect(CommentList) />
</div>

It seems that the problem occurs because it renders <Connect(CommentList)> instead of <CommentList>.

import ConnectedCommentList, { CommentList } from '../../components/CommentList';

But, in App.test.js, I import both ConnectedCommentList and regular CommentList and for the test, I use CommentList.

How can I make this test passes!?

1
What does your CommentBox look like?Mμ.
@D-reaper Thank you for your responce! I edited my post and added the jsx of CommentBox & CommentList on the bottom of my post. Thanks!user5809117
does it work if you use component.find('CommentList').dive()Andreas Köberle
@AndreasKöberle I tried wrapping CommentList with single quotes but I got the same error message in my test.user5809117
Seems the problem is that CommentList is wrapped into redux connect. Will provide a solution after lunch.Andreas Köberle

1 Answers

1
votes

The problem is that CommentList is a Higher Order Component, so when enzyme renders it with shallow, it does not render the real CommentList but the wrapped one, and as shallow does not render children of a component, find will not be able to get this element either by a string nor by the constructor. The easiest way to fix this is by using enzyme.mount as this will force the component to render its children as well.

Or you use ConnectedCommentList to find the element:

it('shows a comment list', () = > {
  expect(component.find(ConnectedCommentList).dive().find('.comment-list').exists()).toBe(true);
})