Enzyme: ShallowWrapper.props() returns props of first child element instead of wrapped React Component

Created on 13 Apr 2018  路  22Comments  路  Source: enzymejs/enzyme

Current behavior

I have been using Enzyme already for months for tests and none of the other tests fail, it is just with this element. I have made the code very barebone to see if I could figure out if I did something wrong but with this code it is still occuring:

The only change is replacing the original path with path/to of the import

See comments for the current outputs:

import React from "react";
import { expect } from "chai";
import enzyme from "enzyme";

import { BareHeader } from "path/to/bare_header.jsx";

describe("BareHeader", function(){
  let component;

  before(function(){
    component = enzyme.shallow(<BareHeader currentStepNumber={1234}/>);
    console.dir(component.props()); // {children: ..., className: "header-container"}
    let compInst = component.instance();
    console.dir(compInst.props); // {currentStepNumber: 1234}
  });

  //Fails: expected undefined to equal 1234
  it("should have right prop", function(){
    expect(component.prop("currentStepNumber")).to.equal(1234);
  });
});

bare_header.jsx:

import React from "react";

class BareHeader extends React.Component {
  render(){
    return (
      <div className="header-container">
        <div className='header-hoverArea'>
          <p>header placeholder</p>
        </div>
      </div>
    );
  }
}
export { BareHeader };

Expected behavior

See comment for expected:

import React from "react";
import { expect } from "chai";
import enzyme from "enzyme";

import { BareHeader } from "path/to/bare_header.jsx";

describe("BareHeader", function(){
  let component;

  before(function(){
    component = enzyme.shallow(<BareHeader currentStepNumber={1234}/>);
    console.dir(component.props()); // {children: ..., currentStepNumber: 1234}
    let compInst = component.instance();
    console.dir(compInst.props); // {currentStepNumber: 1234}
  });

  //Passing
  it("should have right prop", function(){
    expect(component.prop("currentStepNumber")).to.equal(1234);
  });
});

Your environment

Mocha automated tests in MeteorJS application (1.6.1). Mocha distribution is meteortesting/meteor-mocha.

API

  • [x] shallow
  • [ ] mount
  • [ ] render

Version

| library | version
| ---------------- | -------
| Enzyme | 3.3.0
| React | 16.2.0
| Meteor Mocha | 0.5.1
| Mocha | 2.4.5

Adapter

  • [x] enzyme-adapter-react-16
  • [ ] enzyme-adapter-react-15
  • [ ] enzyme-adapter-react-15.4
  • [ ] enzyme-adapter-react-14
  • [ ] enzyme-adapter-react-13
  • [ ] enzyme-adapter-react-helper
  • [ ] others ( )
shallow Need More Information question

Most helpful comment

component.instance().props doesn't work no more with React 16 (functional components). Is there an alternative.

All 22 comments

same problem. I also got some tests failed after update enzyme to 3.3.0 and enzyme-adapter-react-16. previously it is pass:
expect(component.instance().props.title).toBe('Title 2');
now I have to make it to be like this to make it pass:
expect(component.props().children).toBe('Title 2');

I have to admit the issue started in 3.2.0 for me but stayed after updating to 3.3.0

Calling .props() on a shallow wrapper returns the props of the rendered element - not the props of the wrapper itself.

@bvanderdrift why are you writing a test that asserts on the prop value you literally just passed in a few lines prior?

I don't remember the actual code I had written for this. We currently don't have the test anymore. This example was very minimized, which is why it might look a bit weird, but could as well that I had written a very redundant test.

Thanks for the explanation, I guess the props different behaviour on instance and the object itself was confusing for me.

Thanks for replying - I'm going to close this for now, but will be happy to reopen if there's a reproducible case.

component.instance().props doesn't work no more with React 16 (functional components). Is there an alternative.

@himanshuc3 yes, component.props() - there's no reason to ever have accessed through the instance anyways.

I forgot to mention that i am using react-native. const wrapper = shallow(<Footer name="friend"/>) console.log(wrapper.props().name) console log returns null.

@himanshuc3 although enzyme doesn't have a react-native adapter; that's because a shallow wrapper of <Footer> is not actually Footer, it's what Footer renders - there's zero value in making assertions on the props you literally just passed in.

So is there any way we could make assertions by passing props in react-native.

Tons - but there's no point in making assertions on the props you literally just passed in.

That is just a debugging statement. Actually i am conditional rendering and want to check on that by passing props. How would that be possible?

I'm not sure what you mean - can you elaborate?

i am also facing this updated issue, does someone fixed this?

@kevinlucero if you can provide a repro case, please file a new issue for that.

@ljharb im writing this code like function component with specific type :)

import React from 'react';

import Enzyme, { shallow, ShallowWrapper } from 'enzyme';
import { create, ReactTestRenderer } from 'react-test-renderer';
import sinon from 'sinon';

import Button, { ButtonKind, Props } from './index';

let wrapper: ShallowWrapper<Props>;
let snapshot: ReactTestRenderer;
let buttonFn: sinon.SinonSpy<any[], any>;

beforeEach(() => {
  buttonFn = sinon.spy();
  const button = <Button text="sample" kind={ButtonKind.Danger} />;

  wrapper = shallow(button);
  snapshot = create(button);
});

describe('<Button />', () => {
  it('it should text must be sample', () => {
    expect(wrapper.props().text).toEqual('sample');
  });

  it('it should kind must be ButtonKind.Danger', () => {
    expect(wrapper.props().kind).toEqual(ButtonKind.Danger);
  });
});


//wrapper.props() is null but I pass props if you can see in button declaration

//package.json
"jest": "^24.8.0",
"ts-jest": "^24.0.2"
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.3.5",

@kevinlucero i specifically asked you to file a new issue - but the answer is the same. wrapper.props() for a shallow wrapper will NOT be the props you just passed (and thus have no need to assert on), but will be the props on the thing that Button renders.

Hey @kevinlucero

I was able to work around this using two stages in testing:

import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('should render MyComponent with an event handler', () => {
    const spy = jest.fn();
    let wrapper = shallow(<MyComponent />);

    expect(wrapper).toMatchSnapshot();

    wrapper = shallow(
      <div>
        <MyComponent onEvent={spy} />
      </div>
    );

    wrapper
      .childAt(0)
      .props()
      .onEvent();
    expect(spy).toHaveBeenCalled();
  });
})

@armin-th (btw that's really two tests, so it should be two its) I'm still confused what you're testing there. You literally are just testing that you passed spy to onEvent; you aren't testing a single thing about MyComponent - it's a useless test.

A dang, I meant to test that the event is handled by trigging something inside but wouldn't need to do any of what I wrote in the first place.

You'd do that by directly shallow-wrapping MyComponent, and not testing MyComponent's props directly (because you just passed them in; testing them is a waste of time)

I also had this problem, I was able to solve it when I used mount instead of shallow, and calling as follows .props().propName

it('should render a url property', () => {
    const url = 'https://github.com'
    const wrapper = mount(<GithubButton url={url} />)

    expect(wrapper.props().url).toEqual(url)
 })

Docs: https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/props.html

Was this page helpful?
0 / 5 - 0 ratings

Related issues

amcmillan01 picture amcmillan01  路  3Comments

rexonms picture rexonms  路  3Comments

aweary picture aweary  路  3Comments

andrewhl picture andrewhl  路  3Comments

ivanbtrujillo picture ivanbtrujillo  路  3Comments