Enzyme mount API issue: TypeError: Cannot read property 'find' of undefined

Viewed 4544

I am trying to test my component but I keep getting a this error: TypeError: Cannot read property 'find' of undefined

My tests were working fine before turning my component into a stateless component. From my understanding you can test functional stateless components as well. I don't see what I am doing wrong here.

My test file

import * as React from 'react';
import { LeftNavigation } from "../src/components/LeftNavigation";
import { mount } from 'enzyme';

describe("<LeftNavigation />", () => {
    const wrapper;

    beforeEach(() => {
        wrapper = mount(
            <LeftNavigation title="Protocol Vantage Points" path="/hello"/>
        );
    });

    it("renders the title", () => {
        expect(wrapper.find(".uk-h3 span").text()).toBe("Protocol Vantage Points");
    });

    it("renders first menu item 'On demand tests'", () => {
        expect(wrapper.find("#synth-left-nav .uk-nav li a").at(0).text()).toBe("On demand tests");
    });

    it("renders second menu item 'Feel status'", () => {
        expect(wrapper.find("#synth-left-nav .uk-nav li a").at(1).text()).toBe("Fleet status");
    });
});

My component

import * as React from "react";
import { NavLink, Link } from 'react-router-dom';

export interface LeftNavigationProps {
    title: string;
    path: string;
}

export class LeftNavigationItem {
    title: string;
    path: string;

    constructor(title: string, path: string) {
        this.title = title;
        this.path = path;
    }
}

export const LeftNavigation: React.StatelessComponent<LeftNavigationProps> = (props: LeftNavigationProps) => {

    const items: Array<LeftNavigationItem> = [
        new LeftNavigationItem('On demand tests', '/ondemandtests'),
        new LeftNavigationItem('Fleet status', '/fleetstatus')
    ];

    return (
        <div id="synth-left-nav" className="uk-margin-bottom">
            <h1 className="uk-h3">
                <span><Link id="synth-left-nav-title" to={props.path}>{props.title}</Link></span>
            </h1>
            <hr className="uk-width-1-1" />
            <ul className="uk-nav uk-margin-remove"> {
                items.map(function (m, index) {
                    return (
                        <li key={m.path}>
                            <NavLink activeClassName="uk-text-bold uk-active"
                                        to={props.path + m.path} replace>{m.title}</NavLink>
                        </li>
                    );
                })
            }
            </ul>
        </div>
    );
};
1 Answers

I figured out the problem. Testing components that renders a <Link> or a <Route>, may cause errors and warnings about context. It is recommended to wrap your tests in a <StaticRouter> or <MemoryRouter>. Check out this for reference: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/testing.md

Here is my solution:

import * as React from 'react';
import { LeftNavigation } from "../src/components/LeftNavigation";
import { mount } from 'enzyme';
import { MemoryRouter } from 'react-router-dom'

describe("<LeftNavigation />", () => {
    const wrapper;
    // Testing components that renders a <Link> or a <Route>, may cause 
    // errors and warnings about context. It is recommended to wrap your
    // tests in a <StaticRouter> or <MemoryRouter>

    beforeEach(() => {
        wrapper = mount(
            <MemoryRouter><LeftNavigation title="Protocol Vantage Points" path="/hello"/></MemoryRouter>
        );
    });

    it("renders the title", () => {
        expect(wrapper.find(".uk-h3 span").text()).toBe("Protocol Vantage Points");
    });

    it("renders first menu item 'On demand tests'", () => {
        expect(wrapper.find("#synth-left-nav .uk-nav li a").at(0).text()).toEqual("On demand tests");
    });

    it("renders second menu item 'Feel status'", () => {
        expect(wrapper.find("#synth-left-nav .uk-nav li a").at(1).text()).toBe("Fleet status");
    });
});
Related