57

I'm writing a test using Enzyme for React.

My test is extremely straightforward:

import OffCanvasMenu from '../index';
import { Link } from 'react-router';

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

describe('<OffCanvasMenu />', () => {
  it('contains 5 <Link /> components', () => {
    const wrapper = shallow(<OffCanvasMenu />);
    expect(wrapper.find(<Link />)).to.have.length(5);
  });
});

This code is basically taken directly from airbnb/enzyme docs, but returns the error:

FAILED TESTS:
  <OffCanvasMenu />
    ✖ contains 5 <Link /> components
      Chrome 52.0.2743 (Mac OS X 10.11.6)
    TypeError: Cannot read property 'have' of undefined

I'm a little unclear on what I'm doing differently from the docs. Any guidance greatly appreciated.

Toby
  • 12,743
  • 8
  • 43
  • 75

4 Answers4

56

Use Link instead of <Link />:

describe('<OffCanvasMenu />', () => {
  it('contains 5 <Link /> components', () => {
    const wrapper = shallow(<OffCanvasMenu />);
    expect(wrapper.find(Link)).to.have.length(5);
  });
});

It appears in the 1st example in the airbnb/enzyme docs:

it('should render three <Foo /> components', () => {
  const wrapper = shallow(<MyComponent />);
  expect(wrapper.find(Foo)).to.have.length(3);
});

The syntax .to.have.length is for the Chai Assertion Library. For Jest use .toHaveLength:

it('should render three <Foo /> components', () => {
  const wrapper = shallow(<MyComponent />);
  expect(wrapper.find(Foo)).toHaveLength(3);
});
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Thanks for the response - I see the same error with `Link`. And I'm following the docs, although the code I'm using imports Michael Jackson's `expect`, and I'm not sure if that's throwing it off (I've checked the docs there too). – Toby Jul 26 '16 at 18:12
  • What assertion library do you use? Try this - `console.log('length', wrapper.find(Link).length);`, and see what appears in the console. – Ori Drori Jul 26 '16 at 18:30
  • Adding this produces the expected entry in the log - "5". I'm using Karma with Chai, but with Michael Jackson's [expect](https://github.com/mjackson/expect). – Toby Jul 26 '16 at 18:34
  • 51
    So enzyme works fine. Try this - `expect(wrapper.find(Link).length).toBe(5);`. Don't use chai if you're using expect, they are doing the same thing. – Ori Drori Jul 26 '16 at 18:40
  • That works perfectly.. I think I understand now, I'll refer to MJ's `expect` docs from now on.. Many thanks! – Toby Jul 26 '16 at 18:42
  • @OriDrori Hi! I had the same issue, and `expect(wrapper.find(Link).length).toBe(5);` solved it perf. Could you explain why `.to.have.length(3);` did not work? – Mihir Sep 01 '16 at 09:44
  • 16
    @Mihir `to.have.length` is part of the chai syntax, while `.toBe(5)` is part of the expect syntax. So it depends on what you're using for assertions. – Ori Drori Sep 01 '16 at 09:48
  • @OriDrori I suspected that! Thank you! It's very confusing. – Mihir Sep 01 '16 at 09:49
  • 1
    @OriDrori Finally got my test to pass, thank you so much! Spent a couple hours on this and going through enzyme docs. Thank you!! – Quintessa Anderson May 01 '19 at 18:07
39

In their documentation Enzyme is using Chai assertion, so if you want to use expect(***).to.have.length(***) you need to install chai-enzyme and use its expect. It will, therefore, lead to issues with expect(***).toMatchSnapshot() if you use Jest snapshots, but this article will help you to solve it, so you can do both.

furcicm
  • 105
  • 6
Khrystyna Skvarok
  • 1,198
  • 13
  • 15
11

This could be because you don't have the chai assertion library installed in your dependencies or have not imported it in your tests file. Therefore, You need to install chai-enzyme and import it in your test file i.e.

npm install chai

import { expect } from 'chai';

Community
  • 1
  • 1
Awesome
  • 388
  • 3
  • 9
  • enzyme documentation doesn't say more about this. Is there any better tutorials for reactjs unit testing with enzyme, chai, and mocha? – Bhargav Tavethiya Aug 20 '20 at 14:11
  • hmmm.... it has a really bad docmentation for these testing libraries. plp mix them but their documentation doesn't consider any dependencies – newBike Apr 23 '21 at 03:52
3

This error can happen when you've got a parenthesis misplaced such that .to.have incorrectly is placed within the parenthesis of expect(...):

Correct:

expect(wrapper.find(<Link />)).to.have.length(5);

Causes TypeError: Cannot read property 'have' of undefined:

expect(wrapper.find(<Link />).to.have.length(5));
Jon Schneider
  • 25,758
  • 23
  • 142
  • 170