-
-
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
Discussion: Framework "Recommendations" #472
Comments
Note that Redux already exposes the unconnected component as the |
This is a problem for anyone who uses higher-order components, if anything we might want to document how to handle those in the general case, and then maybe use Redux or something as a specific example. |
I think there are 2 issues. The first is to test the a component wrapped in a higher-order component. In that case I think the The other is to test a component that has a child that depends on context, like Redux. |
I don't want to talk for the entire MobX-community, but I personally think enzyme in conjunction with something lightweight like tape or blue-tape is all that is needed. I don't see the need for an entirely new module: // counterFactory.js
function counterFactory() {
let c = observable({
value: 0
});
c.increment = function () {
++c.value;
};
return c;
};
// IncrementButton.js
const IncrementButton = observer(['counter'], React.createClass({
render: function () {
let {counter} = this.props;
return <button onClick={counter.increment}>{counter.value}</button>;
}
}));
// App.js
const c = counterFactory();
ReactDOM.render(
<Provider counter={c}>
<div>
<IncrementButton />
</div>
</Provider>,
document.getElementById('app')
);
// test.js
import {mount} from 'enzyme';
import test from 'tape';
test('that clicking the button increments the counter', function (t) {
t.plan(2);
let c = counterFactory();
t.equal(c.value, 0);
// "If a component ask a store and receives a store via a property with the
// same name, the property takes precedence. Use this to your advantage
// when testing!"
let wrapper = mount(<IncrementButton counter={c} />);
wrapper.find('button').simulate('click');
t.equal(c.value, 1);
}); |
@EmilTholin agreed, var React = require('react');
var enzyme = require('enzyme');
var mount = enzyme.mount;
var mobx = require('mobx');
var observer = require('../').observer;
var Provider = require('../').Provider;
var test = require('tape');
var e = React.createElement;
test('basic context', t => {
var C = observer(["foo"], React.createClass({
render: function() {
return e("div", {}, "context:" + this.props.foo);
}
}));
var B = React.createClass({
render: function() {
return e(C, {});
}
});
var A = React.createClass({
render: function() {
return e(Provider, { foo: "bar" }, e(B, {}))
}
})
const wrapper = mount(e(A));
t.equal(wrapper.find("div").text(), "context:bar");
t.end();
}) |
@gaearon, do you have any docs/recommendations for redux connected component testing? @jacobrask already noted the |
I’m not sure I understand the question. It depends on what you want to test, right? |
Yes. But I think mostly you just want to test the underlying component. testing the connection is sort of like writing a test to make sure redux does it's job. So I didn't know if you had any specific recommendations. Assume a component like this: export function Comp({foo, bar}) {
...
}
export default connect(fn, fn)(Comp); I think the 3 options to test are basically this: import { Comp }, ConnectedComponent from './';
const props = { foo: true, bar: false };
mount(<Comp {...props} />);
// test exported component
mount(<ConnectedComponent.WrappedComponent {...props} />);
// access underlying component
mount(<MockProvider><ConnectedComponent /></MockProvider);
// some how mock the provider to provide the props properly So when your tests are aiming to verify UI and interaction based on props/state, is there any other way you've suggested testing? Or any part of testing a component that I'm missing? |
Hi, I don't know if it helps but I got rather lost on how to test nested React components and ended up writing some simple components and Unit Test to try both enzyme and ReactTestUtils. As a result I wrote an article called Unit Testing React components that use Redux which describes how to test React components that use Redux with enzyme test utility. It also points out the problems of testing nested components that use Redux. Hope that helps someone. |
@blainekasten, did you every land on a best option for this? Could you recommend any part of the docs/any resource for learning how to best test framework-wrapped components? Thanks! |
@lsimmons2 I've been wrestling with a similar problem with a component wrapped with polyglot/translate and simply resolved it by importing the component as usual in the test import Comp from './Comp'; Then I tested the wrapped component (the actual component) by writing like this shallow(<Comp.WrappedComponent />); Works like a charm. By logging Comp to the console you see that WrappedComponent is a part of it console.log(Comp); |
Going back to @blainekasten example, assuming I have:
I can successfully test
However, when I try to test the component
In testing, I do:
Basically, it is the same as the test code for The problem is that in testing I also tried passing a context with a mock store as the second argument to Any ideas? Thanks in advance. |
@Satyam try |
@ljharb The Anyway, it did give me an idea and it produced a funny error message that got me thinking. So, it did help, thanks. One of the many things I tried was to pass
The problem was that since it had gone into JSX mode upon finding the
Adding an extra set of parenthesis makes it work. THanks |
That doesn't sound like how JSX parsing works, but maybe you're not using the normal babel transform? At any rate, you definitely need to explicitly pass context to a component that needs it, so glad that worked 🎉 |
@Satyam what error do you get. |
@hellqvist I tried to reproduce the error and failed, which means my previous diagnostics was wrong. Good you asked so I can correct it. So I started looking into the combinations I had made before I got it working. Instead of trying things at random I made a test for each possible combination. What I found out was that the culprit was calling method
where Calling method So, the problem is with If this is expected behavior it would be nice to have a warning on it. Thanks and sorry for the confusion. |
@Satyam
I haven't had any problems using |
I've had the same issue as @Satyam, the problem is that if we wrap our component in |
Use |
@ljharb we were using We wanted to test the behavior of our code with the third-party code together, so we used Solution: In our specs, we define |
Guys, any news about this issue ? As a temporary workaround, I'm mocking the child components which connect to redux.
|
@valentinvoilean I'm confused - you're mocking out modules that export components with a string? I'd recommend not mocking out anything at all. |
@ljharb Doing This is the output I get when I do
|
Just wanted to mention one more thing.. Only the children connect to the store. The parent component it is a dumb component. This means, the children are still mounted somehow since there are displayed the store context errors. |
What happens if you move the |
@Satyam Thanks for this. I don't completely understand your following diagnostics testing logic, but I was also testing a Redux-connected component with enzyme (which I decided to disconnect from Redux anyway while testing) and, borrowing from what you did, this worked for me: import {mount} from 'enzyme';
import {ManageUserPage} from './ManageUserPage'; //disconnected version of my component
const props = {
//initialize user properties
};
const context = {
router: {}
};
//this works without errors or warnings
const wrapper = mount((<ManageUserPage {...props} />), {context});
...
... |
@skynode As I said in the my last message on the issue, I made a wrong diagnosis so it was all pointless. Sorry again. |
I think it'd be good to have a discussion to build a doc for our "recommendation" for testing framework wrapped components (redux). This comes up a lot. The real answer is that it's not this libraries scope to handle framework specifics. But it comes up a lot so we should have a discussion about how to handle it.
Personally I think there are a couple good options here:
enzyme-redux
,enzyme-coflux
,enzyme-mobx
.As far as docs go. It seems like the easiest recommendation that keeps coming up is to suggest exporting the non-framework-wrapped version of a component.
Looking to hear from the community on how they handle testing framework wrapped components. Extra curious in MobX users as it's got a lot of attention lately.
The text was updated successfully, but these errors were encountered: