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

ensure ShallowWrapper render output can't get stale #490

Merged
merged 10 commits into from
Oct 24, 2016

Conversation

jwbay
Copy link
Contributor

@jwbay jwbay commented Jul 8, 2016

Replace .node and .nodes with 'get' functions in ShallowWrapper to ensure render output is always fresh. Add equivalent functions in ReactWrapper. Removes need for ShallowWrapper's .update, fixes #360

Many thanks to @guncha for the idea in #360.

this.node = this.renderer.getRenderOutput();
this.nodes = [this.node];
Object.defineProperty(this, 'node', {
get() {
Copy link
Member

Choose a reason for hiding this comment

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

ugh :-/ getters are incredibly slow and deoptimize all code they touch. I'd rather do a breaking change to make this a method, than use a getter.

Copy link
Contributor

@blainekasten blainekasten Jul 8, 2016

Choose a reason for hiding this comment

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

I would also be down for using functions. I've always felt nervous about using .node / .nodes as I felt like it was reaching into enzyme internals that could be changed without notice.. Functions feel more like a public API.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, node and nodes aren't technically public API are they? We don't document them as far as I can see. I agree that using a function would be an improvement, so maybe we can make that change for the next breaking release and then add node() and nodes() to the API documentation?

Copy link
Member

Choose a reason for hiding this comment

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

Everything accessible - not just everything documented - is public API, even if it has a magical underscore in the front of the property name.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So any change to any object property would be considered a breaking change? If someone is using ReactWrapper.complexSelector.find and we rename/move that, would that require a major release? Maybe we're not talking about the same thing. I usually define public API as the API that we document for the public and that we support.

Copy link
Member

Choose a reason for hiding this comment

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

Getters and setters are horrifically bad for readability and maintainability. imo they should never be used, in any project. A property should be a property, not a function.

Since this is not a bug fix, there's no urgency to add this change, and I'd prefer to convert .node to a function if we want more behavior than "data property".

Copy link

Choose a reason for hiding this comment

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

While I agree that getters don't improve readability, this is definitely a bug. Ask anyone with passing familiarity with Enzyme about what this should do and compare it with what actually happens:

let wrapper = Enzyme.shallow(<MyInput debounce={ 500 } />)
wrapper.simulate("keypress", {char: "b"})
wrapper.simulate("keypress", {char: "a"})
wrapper.simulate("keypress", {char: "r"})
expect(wrapper.find(".result").text()).toBe("")
jasmine.clock().tick(1000)
expect(wrapper.find(".result").text()).toBe("bar")

Copy link
Member

Choose a reason for hiding this comment

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

The requirement to manually update() is intentional. I agree it's a UX improvement to do it automatically, but it's not a bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ljharb I can convert these to functions. Would that be acceptable? Want to make sure because it's a more involved change. 😄 I understand it would have to wait for a 3.x release.

Are there any concerns about ReactWrapper having properties for these and ShallowWrapper having functions?

Copy link
Member

Choose a reason for hiding this comment

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

I think we should convert both to functions at the same time, for consistency.

guncha added a commit to guncha/enzyme that referenced this pull request Jul 8, 2016
@jwbay jwbay force-pushed the update branch 5 times, most recently from 67699b6 to d27d5e4 Compare July 10, 2016 00:30
@jwbay jwbay changed the title use getter for .node and .nodes in ShallowWrapper, deprecate .update ensure ShallowWrapper render output can't get stale Jul 10, 2016
@jwbay
Copy link
Contributor Author

jwbay commented Jul 10, 2016

This is ready for a second look. The first commit was only updated to get tests passing on older versions of React/Node.

I didn't switch everything in ReactWrapper to use the new functions because the only benefit would've been for internal uniformity at the cost of function calls where they weren't needed. Can switch if desired.

Outstanding questions:

  • Should the new functions should be added to documentation?
  • How should ShallowWrapper's .update be handled?
    • soft deprecation (current approach), possibly with a logged warning
    • outright removed since this is already a breaking change
    • repurposed to call .instance().forceUpdate() for non-SFCs

@@ -169,9 +169,6 @@ Manually sets context of the root component.
#### [`.instance() => ReactComponent`](ShallowWrapper/instance.md)
Returns the instance of the root component.

#### [`.update() => ShallowWrapper`](ShallowWrapper/update.md)
Copy link
Member

Choose a reason for hiding this comment

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

This method still seems useful in case someone mutates state/props without calling the appropriate methods and wants to force an update.

@ljharb
Copy link
Member

ljharb commented Jul 10, 2016

fwiw I think internal uniformity is much more important than avoiding function calls, which are pretty cheap anyways.

@jwbay
Copy link
Contributor Author

jwbay commented Sep 17, 2016

Does anyone have further thoughts on this?

@ljharb
Copy link
Member

ljharb commented Sep 17, 2016

The more I think about this, the more I'm confused why there's both "getNode" and "getNodes"?

@jwbay
Copy link
Contributor Author

jwbay commented Sep 17, 2016

Don't think there's a reason besides avoiding lots of [0] when you're dealing with one node, but I'm not familiar with the reasoning for the original split between .node and .nodes

@ljharb
Copy link
Member

ljharb commented Sep 17, 2016

If it's just a convenience, perhaps getNode should throw when there's more than one? Also I don't think we need two internal sources of truth - this.nodes seems sufficient.

@jwbay
Copy link
Contributor Author

jwbay commented Sep 17, 2016

Good points, updated!

@lelandrichardson
Copy link
Collaborator

@jwbay this is a great and very welcome change!

Although I agree w/ @ljharb that with a .getNode() method, keeping track of .node and .nodes is potentially unnecessary... however, i'm worried that if we get rid of .node, then we might need to consider this a breaking change. Although .node isn't really an advertised property of the wrapper object, I know that in practice people use it.

Thoughts?

@jwbay
Copy link
Contributor Author

jwbay commented Sep 24, 2016

@lelandrichardson Thanks! I agree this is a breaking change.

@ljharb
Copy link
Member

ljharb commented Sep 24, 2016

I'd also be fine keeping the internal .node updated for now, but removing it in the next major version bump.

@jwbay
Copy link
Contributor Author

jwbay commented Sep 24, 2016

So restore the old .update functionality? Should it still call .forceUpdate on the instance as well? It didn't before this PR.

@ljharb
Copy link
Member

ljharb commented Sep 24, 2016

@jwbay ah, if the PR can't be easily made to be semver-minor, then we may as well go full semver-major :-)

@jwbay
Copy link
Contributor Author

jwbay commented Sep 24, 2016

Oh I don't mind making the change, especially if it can get this shipped sooner :) I just wasn't sure whether adding .forceUpdate calls where there weren't any before would be a breaking change as well. Seems like it would actually. I'll take a look at what's involved for back-compat.

@jwbay
Copy link
Contributor Author

jwbay commented Sep 28, 2016

@ljharb @lelandrichardson we should be semver-minor now 👍

@lencioni
Copy link
Contributor

LGTM

@jwbay jwbay force-pushed the update branch 2 times, most recently from fb76502 to 20408fd Compare October 19, 2016 04:19
@jwbay
Copy link
Contributor Author

jwbay commented Oct 19, 2016

Resolved conflicts.

@bookman25
Copy link

Is there any chance of this branch getting merged? This would reduce a lot of boilerplate code for our team.

@lencioni lencioni merged commit 47b4436 into enzymejs:master Oct 24, 2016
@jwbay jwbay deleted the update branch October 24, 2016 22:28
@kentor
Copy link

kentor commented Nov 9, 2016

hi! any timeline on releasing this?

@ljharb
Copy link
Member

ljharb commented Nov 9, 2016

I'll cut a few releases after #670 gets in.

@ChrisFindlay
Copy link

Seems to work under jest but not under jest --coverage...

ockham added a commit to Automattic/wp-calypso that referenced this pull request Oct 3, 2017
2.5.0 supports passing callbacks to `setState`, which we require for `client/auth/test/login`.
Furthermore, there's a fix in 2.6.0 that's required for this to actually work
(enzymejs/enzyme#490)
Not updating to >=3.0.0 yet since chai-expect isn't compatible (yet).
Changelog: https://github.com/airbnb/enzyme/blob/master/CHANGELOG.md#252-november-9-2016
ockham added a commit to Automattic/wp-calypso that referenced this pull request Oct 5, 2017
2.5.0 supports passing callbacks to `setState`, which we require for `client/auth/test/login`.
Furthermore, there's a fix in 2.6.0 that's required for this to actually work
(enzymejs/enzyme#490)
Not updating to >=3.0.0 yet since chai-expect isn't compatible (yet).
Changelog: https://github.com/airbnb/enzyme/blob/master/CHANGELOG.md#252-november-9-2016
ockham added a commit to Automattic/wp-calypso that referenced this pull request Oct 5, 2017
…8472)

* Auth: Prettify login.jsx
* Auth: Run i18n codemod on login.jsx
* Auth: Run react-create-class codemod on login.jsx
* Auth: Prettify login.jsx
* Auth: Simplify login.jsx
* Auth: Named export for un-localized Login component

* Framework: Upgrade enzyme to 2.9.1

2.5.0 supports passing callbacks to `setState`, which we require for `client/auth/test/login`.
Furthermore, there's a fix in 2.6.0 that's required for this to actually work
(enzymejs/enzyme#490)
Not updating to >=3.0.0 yet since chai-expect isn't compatible (yet).
Changelog: https://github.com/airbnb/enzyme/blob/master/CHANGELOG.md#252-november-9-2016

* Auth: Simplify FormTextInput ref (focus)
* Auth: Use enzyme to test login.jsx
* Auth: Remove obsolete refs from login.jsx (These were only used by tests.)
* Auth: Move SelfHostedInstructions and LostPassword to separate files
MicBosi pushed a commit to Automattic/wp-calypso that referenced this pull request Oct 5, 2017
…8472)

* Auth: Prettify login.jsx
* Auth: Run i18n codemod on login.jsx
* Auth: Run react-create-class codemod on login.jsx
* Auth: Prettify login.jsx
* Auth: Simplify login.jsx
* Auth: Named export for un-localized Login component

* Framework: Upgrade enzyme to 2.9.1

2.5.0 supports passing callbacks to `setState`, which we require for `client/auth/test/login`.
Furthermore, there's a fix in 2.6.0 that's required for this to actually work
(enzymejs/enzyme#490)
Not updating to >=3.0.0 yet since chai-expect isn't compatible (yet).
Changelog: https://github.com/airbnb/enzyme/blob/master/CHANGELOG.md#252-november-9-2016

* Auth: Simplify FormTextInput ref (focus)
* Auth: Use enzyme to test login.jsx
* Auth: Remove obsolete refs from login.jsx (These were only used by tests.)
* Auth: Move SelfHostedInstructions and LostPassword to separate files
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.

Removing or documenting the need for Shallow Renderer's .update()
10 participants