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

hasClassName throws Error if component has property className which is not a string #452

Closed
trmjoa opened this issue Jun 13, 2016 · 5 comments
Assignees

Comments

@trmjoa
Copy link

trmjoa commented Jun 13, 2016

Hi,

We use a utility like JedWatsons classnames(https://github.com/JedWatson/classnames) for setting classnames on our components. Syntax is like this:

<MyComponent className={ { classA : true, classB : false } } />

This makes the internal hasClassName and all functions in the api blow up with the exception TypeError: classes.replace is not a function since the property className is a object.

In my view the hasClassName function should not throw a exception if it encounters a custom component with a className attribute that is not a string. From my usage of enzyme I have the assumption that you are generally looking for native components when the hasClassName function is used. If that assumption is considered true I am tempted to suggest the following patch:

  • If node.type is a non-native component(function) and className is not a string return false.
  • If node.type is a non-native component and className is a string, run the check as today (for backwards compatibility)

It could probably also be possible to take the defined proptype into consideration.

/Joakim

@aweary
Copy link
Collaborator

aweary commented Jun 13, 2016

This is documented in #375, you can watch that issue for updates! Thanks!

@aweary aweary closed this as completed Jun 13, 2016
@aweary
Copy link
Collaborator

aweary commented Jun 13, 2016

Also, classnames doesn't return an object. It takes an object and returns a string based on the key's value.

import classNames from 'classnames'

const className = classNames({
  foo: true,
  bar: true,
  baz: false
});
// returns "foo bar"

@trmjoa
Copy link
Author

trmjoa commented Jun 14, 2016

Hi,

Thanks for your input. Might be that I misunderstand the proposed fix in the referenced issue, but after I looked through the PR that is connected with the ticket you referenced, it seems to me that it will not solve the issue.

They are discussing a SVG specific solution(using baseVal) which does not solve the general naming collision where a custom created component has a className attribute. You are right that the classnames utility returns a string, and how we use it, is something like this:

import classNames from 'classnames';
class MyComponent extends React.Component{
  render() {
    <div className={ classNames( this.props.className ) }> { this.props.children} </div>
  }
}

ReactDOM.render(
  React.createElement(
    MyComponent, 
    { className : { classA : true, classB : shouldIAppendClassB(), classC : false }}
  )
);

Wouldn't it be more appropriate in the hasClassName method to assume the check is not applicable if the component has no className attribute that should be a string(defined by propTypes on custom components)? The problem comes in the find methods, because they iterate all components, also non-native.

Also, in the issue you linked, it seems to me that the proposed fix only affects the full rendering functionality, not the shallow part.

Best regards
Joakim

@aweary
Copy link
Collaborator

aweary commented Jun 14, 2016

Thanks for expanding, we can re-open this as I agree that shallow shouldn't fail if a className prop is not a string.

@ljharb
Copy link
Member

ljharb commented Sep 26, 2017

Is this still an issue in v3?

@aweary aweary self-assigned this Sep 26, 2017
@ljharb ljharb closed this as completed in 3070850 Jul 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants