Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting props trough shallow rendering is not working with defaultProps #384

Closed
nehaleem opened this issue May 12, 2016 · 14 comments
Closed
Labels

Comments

@nehaleem
Copy link

nehaleem commented May 12, 2016

Issue:
When using shallow rendering and setting default props inside React component with getDefaultProps() (React.createClass) or with static defaultProps (ES7), calling wrapper.props() or wrapper.prop('myProp') does not return any values (undefined) (it should return default ones)

Although default props ARE set inside component, i cannot test them from outside with enzyme.
If i'll use mount , its working correctly.

Gist:
https://gist.github.com/nehaleem/7fc6d6b2940bc523a2009a566ebfed97

@aweary
Copy link
Collaborator

aweary commented May 12, 2016

I was able to reproduce the error here: Aweary/enzyme-test-repo/blob/issue-#384/test.js.

@stefvhuynh
Copy link

+1 it looks like shallow returns the immediate component returned by the render method while mount returns the actual component. In the original gist, shallow returns the <button>...</button> and mount returns the <AlertButton/>. Is this expected behavior?

@SimenB
Copy link
Contributor

SimenB commented May 15, 2016

@stefvhuynh #335 (comment)

@aweary
Copy link
Collaborator

aweary commented Mar 19, 2017

+1 it looks like shallow returns the immediate component returned by the render method while mount returns the actual component. In the original gist, shallow returns the ... and mount returns the . Is this expected behavior?

This is expected behavior, shallow returns the root node not the actual composite component. Closing, since this is actually expected behavior for Enzyme.

@mgenev
Copy link

mgenev commented Jun 19, 2017

mount is not returning default props either

@ljharb
Copy link
Member

ljharb commented Jun 20, 2017

You shouldn't need to assert on defaultProps; you should only assert on the props you pass in, and on the behavior of the component. defaultProps are an implementation detail.

@kdmadej
Copy link

kdmadej commented Jun 23, 2017

Even tho they are just an implementation detail, lack of them may break the component. I'm currently having a problem where the props that should have a default value are undefined and tests do not pass as the component being mounted relies on those default property values to work.

@ljharb
Copy link
Member

ljharb commented Jun 23, 2017

@zgredzik yes, but you should thus be testing the behavior that would break - not the presence or absence of default props.

@kdmadej
Copy link

kdmadej commented Jun 23, 2017

@ljharb I might have been not explicit enough: I am testing other behaviours but the component crashes while being mounted, thus making the test fail.

The component itself requires some props to exist in a specified format: either by using isRequired in propTypes and forcing the component's user to pass the data, or defaultProps to ensure the optional data that has not been passed in is still in the format required.
If I was not able to specify defaultProps, I'd have to either always pass a dummy (default) value explicitly or assume any optional property will default to undefined and add additional checks in the code to make sure that it's not.

When I want to test the behaviour of the component that does not depend on the optional properties I don't see a reason to be forced to pass them.

Unless I got the whole concept of how mount is actually supposed to work wrong.

@ljharb
Copy link
Member

ljharb commented Jun 23, 2017

The component gets the defaulted prop values; it's just .props() that isn't. I'm not seeing the issue.

@kdmadej
Copy link

kdmadej commented Jun 23, 2017

I guess I misunderstood what @mgenev was reporting and prematurely assumed that was exactly the same problem I encountered. Furthermore I've dug deeper into my own issue and it seems my lack of the default value is because of a problem in a 3rd party library I'm using and not a problem with mount. My bad.

@Stupidism
Copy link

try wrapper.instance().props

@ghost
Copy link

ghost commented Jan 11, 2018

Yes, For a shallow wrapper, you can call a wrapper.instance().props.propName to get the value of respective prop.

@tkrotoff
Copy link

tkrotoff commented Feb 7, 2018

I have the problem using context when a child accesses its parent's props:

class Parent {
  static defaultProps {
    hello: 'world'
  };

  static childContextTypes = {
    parent: PropTypes.object.isRequired
  };
  getChildContext() {
    return {
      parent: this
    };
  }
}

class Child {
  static contextTypes = {
    parent: PropTypes.object.isRequired
  };

  render() {
    console.log(this.context.parent.props.hello); // hello is undefined
  }
}

const parent = new Parent({});
shallow(
  <Child />,
  {context: {parent: parent}}
);

Hackish solution:

class ParentEnzymeFix extends Parent {
  constructor(props) {
    const defaultProps = {
      hello: 'world'
    };
    super({...defaultProps, ...props});
  }
}

const parent = new ParentEnzymeFix({});

Edit:

This generates a React warning:
Warning: ParentEnzymeFix(...): When calling super() in 'ParentEnzymeFix', make sure to pass up the same props that your component's constructor was passed.
Solution:

function new_Parent(props) {
  const defaultProps = {
    hello: 'world'
  };
  return new Parent({...defaultProps, ...props});
}

const parent = new_Parent({});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants