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

Fix bug introduced in #677 #680

Merged
merged 6 commits into from
Dec 22, 2016
Merged

Fix bug introduced in #677 #680

merged 6 commits into from
Dec 22, 2016

Conversation

nfcampos
Copy link
Collaborator

@nfcampos nfcampos commented Nov 13, 2016

PR #677 introduced a bug where calling hasClass on a component that renders null would throw an exception. This fixes that.

@@ -47,6 +47,9 @@ export function instEqual(a, b, lenComp) {

export function instHasClassName(inst, className) {
const node = findDOMNode(inst);
if (!node) { // inst renders null
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it better to check !node or node === null here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the instance renders "nothing", it could return an empty array, or null, or undefined… is there perhaps a react method we could use, like React.Children.count or something, that would cover us here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But can a react component return anything other than null or a react element? Besides, what we're talking about here is the output of findDOMNode, can it be anything other than a dom element or null, I dont know...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point - https://facebook.github.io/react/docs/react-dom.html#finddomnode makes it seem like it's only null or a node. I wonder if then it would be better to use === null specifically so that it blows up if React changes the behavior?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I've changed it to === null

@nfcampos
Copy link
Collaborator Author

same thing as in #679 (comment) applies here I believe, after #677 hasClass can be used with composites as long as they're class based (because its implementation relies on findDOMNode).
Should we introduce the logic similar to #679 or should we try to re-use it (eg. by calling getDOMNode in hasClass)?

@ljharb
Copy link
Member

ljharb commented Nov 16, 2016

I think the two PRs can coexist - hasClass is a boolean method and it seems reasonable for it to return false here, and for getDOMNode to throw.

@nfcampos
Copy link
Collaborator Author

@ljharb You wouldn't expect this test to pass?

const Foo = () => <div className="bar" />
const wrapper = mount(<Foo />)
expect(wrapper.hasClass('bar')).to.equal(true)

@ljharb
Copy link
Member

ljharb commented Nov 27, 2016

hmm, that's a good point. no, i wouldn't; that should work.

@nfcampos
Copy link
Collaborator Author

So what should we do here, throw if used on a SFC?

@ljharb
Copy link
Member

ljharb commented Nov 28, 2016

Sorry, my comment was confusing. I would indeed expect that test to pass - so SFCs should work, and not throw.

If they won't work properly, then they should throw, of course.

@nfcampos
Copy link
Collaborator Author

@ljharb sorry for the late reply, I don't think there's any way to get a ref to the dom node rendered for a stateless component so I'll update the PR to make the method throw when used on a stateless component.

@nfcampos nfcampos requested a review from ljharb December 12, 2016 22:47
@nfcampos
Copy link
Collaborator Author

nfcampos commented Dec 12, 2016

So, apparently the react documentation is not up-to-date or I misread it because findDOMNode does work on functional components, as such, I've updated the PR with tests for hasClass on SFCs and removed the previously added check on getDOMNode for SFCs. Thoughts?

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems good, but lets get lots of eyes on it prior to merging


it('should throw when wrapping an SFC', () => {
it('should return the outer most DOMComponent of the inner div wrapper', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"outermost" is one word :-p

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed it is ;) updated


it('should throw when wrapping multiple elements', () => {
const wrapper = mount(<SFC />).find('span');
expect(() => wrapper.getDOMNode()).to.throw(Error);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we test the error message like we had before? Testing that it throws any error seems brittle.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably both would be good; but if we want our error tests to be more robust we should be making error subclasses, not doing string comparisons.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error subclasses are a better solution, I'm on board with that approach. But a string comparison would be better than nothing, so I'm fine with doing that for now too.

@nfcampos
Copy link
Collaborator Author

FYI @ljharb @aweary https://twitter.com/dan_abramov/status/808781309745201152
given this, should we support these methods for SFCs while they work, potentially seeing unexpectedly them break in a way we can't fix with a future React release?

@ljharb
Copy link
Member

ljharb commented Dec 13, 2016

Yes, if it works, we should support it for SFCs.

If it breaks in a major version (since it'd be a breaking change), we'll have to conditionally support it based on the react version.

@nfcampos
Copy link
Collaborator Author

@ljharb since we're relying on "accidental" non-public behaviour of the ReactDOM API it could theoretically break in a patch version

@ljharb
Copy link
Member

ljharb commented Dec 13, 2016

Sadly "if it's reachable, it's public" isn't a philosophy React tends to follow, but in this case I think we can, since it would probably cause lots of breakage across the React ecosystem. I think we should be optimistic here that React will follow semver.

@nfcampos
Copy link
Collaborator Author

@ljharb I think we might be pretty alone in relying on this particular behaviour of findDOMNode, (especially because the usefulness of using this very convoluted way (it requires rendering the SFC as a child of a class component, ReactWrapperComponent for us, and accessing it from there) of accessing dom nodes for SFCs is next to null outside of testing (but very useful in testing obviously))

- passing test for composite component that renders composite component which itself renders a dom element
- failing test for composite component that renders null
@nfcampos
Copy link
Collaborator Author

@ljharb @aweary I've added the error message testing, this should now be ready to merge

Copy link
Collaborator

@aweary aweary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nfcampos nfcampos merged commit 3d7b68b into master Dec 22, 2016
@nfcampos nfcampos deleted the fix-677 branch December 22, 2016 21:39
@devrelm
Copy link

devrelm commented Dec 27, 2016

@ljharb Can we get a patch release to npm with these changes? We're going to have to pin to 2.6.0 as a few of our tests are currently broken due hasClass not working on empty nodes.

@ljharb
Copy link
Member

ljharb commented Dec 27, 2016

Sure, I should be able to get one out today or tomorrow.

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

Successfully merging this pull request may close these issues.

4 participants