Enzyme: Issues with nesting components

Created on 21 Apr 2017  Â·  7Comments  Â·  Source: enzymejs/enzyme

I am struggling to get nested components working correctly. Namely, I want to check the contents of a nested component and get a function from one.

import * as React from "react";
import { Expect, TestFixture, Test } from "alsatian";
import { shallow } from "enzyme";

class Foo extends React.Component<{
  fn: () => any
}, {}> {
  render() {
    return <div>Foo</div>;
  }
}

class Qux extends React.Component<{}, {}> {
  render() {
    return <span>{ this.props.children }</span>;
  }
}

class Bar extends React.Component<{
  title: string
}, {}> {
  render() {
    return <section>
      <h1>{ this.props.title }</h1>

      <Foo fn={ () => console.log("hello") }/>

      <section>
        <Qux>Qux number one</Qux>
        <Qux>And another Qux</Qux>
      </section>
    </section>;
  }
}

class Baz extends React.Component<{}, {}> {
  render() {
    return <Bar title="Baz" />;
  }
}

@TestFixture()
export class EnzymeNestTests {

  @Test()
  public fnShouldBeFunction() {
    const wrapper = shallow(<Baz />);

    const fooFunction = wrapper.find(Foo).prop("fn");

    Expect(typeof(fooFunction)).toBe("function");
  }

  @Test()
  public shouldContainTwoQux() {
    const wrapper = shallow(<Baz />);

    const expectedContents = <section>
      <Qux>Qux number one</Qux>
      <Qux>And another Qux</Qux>
    </section>;

    Expect(wrapper.contains(expectedContents)).toBe(true);
  }

}

Both tests fail: shouldContainTwoQux returns false for contains, but fnShouldBeFunction fails with this error:

       Error: Method “props” is only meant to be run on a single node. 0 found instead.
           at ShallowWrapper.single (C:\Code\NewOrbit.SimpleUI\NewOrbit.SimpleUI\node_modules\enzyme\build\ShallowWrapper.js:1502:17)
           at ShallowWrapper.props (C:\Code\NewOrbit.SimpleUI\NewOrbit.SimpleUI\node_modules\enzyme\build\ShallowWrapper.js:855:21)
           at ShallowWrapper.prop (C:\Code\NewOrbit.SimpleUI\NewOrbit.SimpleUI\node_modules\enzyme\build\ShallowWrapper.js:1061:21)

Am I doing something wrong with my setup?

question

Most helpful comment

Shallow-rendering is only meant to go one level deep. When you shallow-render Baz, you only get a Bar (and none of its children) - you're meant to merely assert that Baz renders a Bar with the appropriate props, and leave the testing of Bar to the Bar tests.

All 7 comments

Shallow-rendering is only meant to go one level deep. When you shallow-render Baz, you only get a Bar (and none of its children) - you're meant to merely assert that Baz renders a Bar with the appropriate props, and leave the testing of Bar to the Bar tests.

Thanks @ljharb. On a second look at the documentation of shallow that is fairly clear, but I think there could be some improvement to the docs to make it a bit clearer that there won't be any children rendered at all.

Would you like me to submit a PR?

PRs to improve the docs are always welcome!

@ljharb I have a similar problem, where I get the error:

Error: Method “props” is only meant to be run on a single node. 0 found instead.

Let's say the Bar component, being rendered in Baz, was passed a component instead of a string. For example:

class Baz extends React.Component<{}, {}> {
  render() {
    return <Bar title={<Title name="Baz"/>} />;
  }
}

Then our test looks like this:

```
@Test()
public fnShouldBeFunction() {
const wrapper = shallow();

const titleComponent = wrapper.find(Bar).prop("title");

Expect(titleComponent.props.name).toEqual("Baz");

}
```
I need to test a prop (in this case name) on the component being passed (in this case Bar) as a prop to the component being tested (in this case Baz). Is there a way to do this in enzyme?

This is a simple example, but the use of this in more complex examples can be really helpful.
I can create an issue about this if you feel it isn't a simple answer.

Yes, you have to wrap it in a div and shallow render that.

@ljharb can you help me brother??i tried to solve this problem 10 different ways but still same problem

Error: Method “props” is only meant to be run on a single node. 0 found instead.**

AddExpensePage.js

export class AddExpensePage extends React.Component {
  onSubmit = ({ id, description, note, createdat, amount }) => {
    this.props.onSubmit({ id, description, note, createdat, amount });
    this.props.history.push("/");
  };
  render() {
    return (
  <div>
        <ExpenseForm onSubmit={this.onSubmit} />
      </div>
    );
  }
}
const mapDispatchtoProps = dispatch => {
  return {
    onSubmit: ({ id, description, note, createdat, amount }) =>
      dispatch(addExpense({ id, description, note, createdat, amount }))
  };
};
export default connect(
  undefined,
  mapDispatchtoProps
)(AddExpensePage);

AddExpensePage.test.js

import toJson from 'enzyme-to-json';
import React from 'react';
import { shallow } from 'enzyme';
import {AddExpensePage} from  '../../components/AddExpensePage';
import setupTests from '../setupTests';
import getFilterExpense from '../getFilterExpense/getFilterExpense.test.js';
import { addExpense } from '../../Actions/expenses';

const expense={
    id:'1',
    description:'January',
    note:'',
    createdat:1300,
    amount:2000
  };

test("should set ExpenseForm in AddExpensePage",()=>{
  const history={push:jest.fn()};
  const dispatch=jest.fn();
  const wrapper=shallow(<AddExpensePage dispatch={dispatch} history={history.push} />);
  wrapper.find('ExpenseForm').prop('onSubmit')({...expense});
  expect(dispatch).toHaveBeenLastCalledWith(addExpense({...expense}));

})

How can i solve this problem??thanks in advance

@tanveerctg please file a new issue rather than reviving an old one; in your case, you want wrapper.dive() to get through the connect HOC.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aweary picture aweary  Â·  3Comments

nelsonchen90 picture nelsonchen90  Â·  3Comments

SandroMachado picture SandroMachado  Â·  3Comments

modemuser picture modemuser  Â·  3Comments

AdamYahid picture AdamYahid  Â·  3Comments