-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Test custom async hooks #2012
Comments
OK thank you, I check it :) :) |
Hello, I locally used the branch #2008 :
But I still get the error :
I will wait for enzyme update, Thanks 👍 :) |
Hi @helabenkhalfallah I'm still working on #2008 and currently it only has test code to verify what is not working (will fix the test in the future), so I think it won't work in your test for now. Also the |
For the record, the way I'd like to approach supporting hooks in enyzme is in this order (as separate PRs):
|
@ljharb
|
I'm pretty confident that despite the docs, hooks can be used in any kind of component. |
OK but using hooks inside a Class will not going have a big advantage because inside a Class I can directly use state, dimount for Http Call, Redux, ... But to reuse statefull logic (useState, custom Hooks, ...) inside Funtional Component here is the big advantage (single independent atomic parts : UI + Hooks). |
Whether it's an advantage or not is utterly irrelevant; if it works in React, enzyme has to support it. |
I don't know your use case but Hooks inside class doesn't work, you will get : |
Thanks, if that's indeed the case then that might make the second item in the list above much easier. |
Yes, effectively ;) |
One of the few complaints I've had about enzyme is the existence of the The reason I don't like the class Counter extends Component {
state = {
counter: 0
};
render(){
const {counter} = this.state;
return (
<div>
count: {counter}
<button onClick={() => this.setState({counter: counter + 1}}>
increment
</button>
</div>
);
}
}
//test
test('button increments counter', () => {
expect(component.state().counter).toBe(0);
component.find('button').simulate('click');
expect(component.state().counter).toBe(1);
}); That test is bad for a few reasons. First, it's testing an implementation detail. The fact that your test would break if you renamed state.counter to state.count is a sign you're testing the wrong things. State is not part of the public API of a component. It's not part of the props and not part of the return value (except where you return it in render), so you shouldn't read or manipulate it directly. In addition to the above, the test is also not necessarily correct, because testing that state.counter is correct is useless if you are not using state.counter correctly. The test would still pass if you said The correctness issue can be prevented if you add a second test like this component.setState({counter: 1});
expect(component.text()).toInclude('count: 1') but that's now two tests when you could have done one component.find('button').simulate('click');
expect(component.text()).toInclude('count: 1') This test is correct, won't break if the public API doesn't change, is concise, tests only one thing, and also simulates the actual usage of the component, which is what tests are supposed to do. I'm happy to talk about this more. But that's the gist of my argument. I think this would lead to people writing much better tests, and while I know there will be a lot of pushback, this seems like the perfect opportunity to do it. And if they are not removed from the API, I would at least encourage making them more difficult to use to make it clear they are escape hatches and not everyday methods. The same can be said for |
(turns out hooks can't be used on class components, so that's my mistake). Good tests for X should be dealing with the implementation details of X - it's everything else that shouldn't. |
Can you explain your position a bit more? Why do you think the implementation details are worth testing? To me, it's like testing private methods of a class, which can't even be tested in languages like C++, and in Java you need reflection for. Not testing them seems to be a popular opinion. And state seems like a great candidate for something private if javascript supported it. |
Certainly private things should never be tested! State, however, isn't private. Either way, it's because in order to test various states of a component, you'd have to be able to get in them - and often that requires cooperation from children that setState callbacks are passed to, or browser interaction that's difficult to test, etc. |
I definitely get the difficult browser interaction thing, but those cases
are rare enough that if they were the only reason to support it I feel like
it would be good to mark the methods like dangerouslySetState or something
to make clear they are escape hatches.
The other one though has never been a problem for me. If I want to test a
set state callback passed to a child, I just do something like `component.find(Child).props().theCallback()`. I don’t think that’s any less
convenient than calling setstate.
|
Sure, that's fine too - but it doesn't satisfy every case. |
Yea I get that. My point was that if it’s generally preferable to avoid
setState except in exceptional circumstances, maybe the api could self
document that In the name of the method somehow. It wouldn’t prevent you
from doing it, but it would make you think about it before doing it,
similar to how needing to disable a lint rule in exceptional circumstances
is fine but having to explicitly do it forces you to think about why it’s
not an ideal thing to use.
…On Sun, Feb 17, 2019 at 12:25 AM Jordan Harband ***@***.***> wrote:
Sure, that's fine too - but it doesn't satisfy every case.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2012 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ADzDDmcnt1eX-iEw-N5pXY045zVOJj-Kks5vOPXBgaJpZM4avWFU>
.
|
Seeing @gaearon say (in #1938) supporting setState for hooks would be very difficult in its current form reminded me of this thread again, so I thought I'd try one more time. It sounds like it would be a large effort to maintain support for state and setState (and other things that deal with "internals" of a component). While I think it's good to make it easier to test hard-to-test things with helpers like setState (if you make it clear they are for exceptional cases), there's also something to be said for simplicity. Whatever is necessary to support a setState method that works with hooks is likely to be extremely complex and difficult to maintain. I've already noticed enzyme start to fall behind React features a bit (new context support took a long time after it came out). I'm sure that's mostly due to needing more contributions from the community (and I'd be happy to help), but adding more complexity to support exceptional cases seems like it would hold the library back even more, and people starting new projects will see that the newest React features are not supported and will look at other libraries. I think for now, the best thing to do is to deprecate Thoughts @ljharb ? |
@bdwain I agree that the current enzyme certainly has fell behind; we went from 5 contributors down to 1 (hi!) and this is far from my only project. The main concern would be that time spent building some new hooks API is time not spent on the rest of #1553. As for whether various methods should be deprecated, I think that's a much bigger and different question. We already have some methods that only work (or are only useful) for certain kinds of components, so I don't think that split is really a problem in practice. |
Fair enough. I didn't realize there was a split between functional and class components besides the limitations of the actual components. |
That is the split - and in the case of hooks, that also differs by the component type (createClass and class components can't use hooks; only SFCs can) |
I use Enzyme version 3.8.0.
My useService make an async call to get user list data.
Test :
But I have this error :
ReactWrapper::state() can only be called on class components
The text was updated successfully, but these errors were encountered: