I'm trying to test my App component which is nested inside withRouter
export default withRouter(App);
In my index.js
ReactDOM.render(
<BrowserRouter>
<App client={client}/>
</BrowserRouter>,
document.getElementById('root')
);
My Test
describe("Test: Home page", ()=>{
const client = {}
let w = shallow(<App client={client}/>)
it("Always render the header", ()=>{
expect(w.find('header').length).toBe(1)
});
});
except the header isn't found and it returns 0 instead of 1
I've looked online but the only other example is grabbing a snapshot whereas I'm trying to check for rendered components
I'm not really sure, but since you are exporting App with a router, the shallow rendering will only render the router component and not the App component itself. You could try to use the wrappedcomponent property of the router to shallow render the component itself and not the router.
source and example
If you are using enzyme use mount instead of shallow.
shallow as name suggest render shallow, which means does not render children, where as mount will completely render with children and your header will be present.
Related
I am using React-Redux, but I am not able to figure out how to access a variable in the Redux store inside of my nested components.
How can I share a variable between components, using React-Redux?
For example:
I have an 'index.js' file and 30 nested components. Managing these components becomes difficult after a while.
I have a 'C1.js' component. Let's just say I wrote this code in it.
function Reducer(state = 'example' , action) {
return state;
}
const store = createStore(Reducer)
index.js file:
<Provider store = {store}>
<App/>, document.getElementById('root')
</Provider>
How do I pass the 'store' variable to the 'C1.js' component to the index.js file?
Thanks...
You need to use something called "Connect" to connect your various components to the provider.
In the file that contains your C1.js component:
import {connect} from 'react-redux'
const MyComponent = () => {
let someData = props.someData
return(
//all of your JSX for your component here
)
}
const mapState = state => {
return {
someData: state.someData
}
}
export default connect(mapState)(MyComponent)
In the code above, notice the mapStateFunction. Connect is hooking that up with the Provider, and the state that is on the Provider. So that is where you are able to link whatever properties are on your Provider (React-Redux) state with this particular data.
Now, in your component, you will now have prop.someData
-
In the index file, you have your Provider in the wrong place, you need to change your code to this:
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
)
See, the difference there? The is the React Element (and all of its children that you are asking React to render to the DOM). It is the first parameter of the ReactDOM.render function.
The second parameter to the ReactDom.render function is the element in the DOM where you want it to put all of your React elements.
You did not configure well redux and react. You need to go over the doc of redux to setup correctly. Should get working after that.
In an application using react, redux and react-router, I'm using react-router-redux to issue navigation actions. I found that wrapping routes in a component with connect blocks navigation.
I made a sample with CodeSandbox that illustrates the issue: sample.
As is, the navigation doesn't work. However, if in ./components/Routes.jsx, this line:
export default connect(() => ({}), () => ({}))(Routes);
Is replaced by:
export default Routes;
It works.
Any idea how I could use connect in a component that wraps routes without breaking navigation?
See the troubleshooting section in react-redux docs.
If you change Routes.jsx export to:
export default connect(() => ({}), () => ({}), null, { pure: false })(Routes);
it will work.
This is because connect() implements shouldComponentUpdate by default,
assuming that your component will produce the same results given the
same props and state.
route changes, but props don't so the view doesn't update.
You could achieve same with withRouter hoc.
Not meant to be a duplicate.
I fixed it with withRouter like this
import { withRouter } from 'react-router-dom';
and
export default withRouter( connect(mapStateToProps)(App) );
See Redux, Router integration docs here
Have you ever encountered the warning message:
Warning: You cannot change <Router history>
Well use withRouter from react-router-dom
I have searched for this for so long because the Redux was recreating my App.jsx component which has <Route> </Route> as parents and this warning just freezes the routing in my app. I wanted to have React/Redux component, because I needed to pass authenticated props to the Route component, and redirect base on it, simple.
So import { withRouter } from 'react-router-dom'
and surround your component which is connected to redux with:
export default withRouter(connect(mapStateToProps)(App));
Something more:
Most of the times if you want to communicate with the router, takes some props, pass something else to it, get history, locations form it and you are using Redux in your app, surround this component with withRouter and you will have access to these properties as props.
I am using enzyme. I need to test a component that has react router Link as a child. I need the following
mount the component using mount() of enzyme since I need to test the whole component tree
test behaviours of component when it properties change.
I cannot wrap my component with StaticRouter or MemoryRouter since enzyme only allows setProps() at root level.
My current solution is to stub the Link render method with sinon. Here is a short example.
import {Link} from 'react-router-dom';
import sinon from 'sinon';
// ....
// ....
describe('test',() => {
before(() => {
sinon.stub(Link.prototype, 'render').callsFake(function reactRouterLinkRender() {
const {innerRef, replace, to } = this.props;
const _props = {href: to, ref: innerRef, replace, onClick: this.handleClick};
return (<a {..._props}>this.props.children</a>);
});
});
});
Is there a better way to avoid the error "Invariant Violation: You should not use Link outside a Router"?
Thanks
Not sure if this helps anyone but for my case I managed to get around by shallow rendering the top level component and then using dive() to get to the parts I required.
loginPage = shallow(<LoginPage />);
....
loginPage.find(LoginForm).dive().find({name:"user"}).simulate("change", userEventMock);
I'm using react native 0.40 with jest 20. When trying to test the inner method of a component I fail because I cannot get the instance of it and then call the method.
For example I can test the rendered component using the snapshots like
it('renders correctly', () => {
var store = mockStore(initialState);
const tree = renderer.create(
<Provider store={store}>
<App/>
</Provider>
).toJSON()
expect(tree).toMatchSnapshot()
})
But if I try to test an inner method of the App component I don't find any way to access it.
So the following code will not run
it("checks version number correctly", () => {
var store = mockStore(initialState);
const tree = renderer.create(
<Provider store={store}>
<App/>
</Provider>
)
expect(tree.needsUpdate("1.0.0")).toBe(true)
})
The solution some people used was "react-test-renderer/shallow" or "enzyme" to shallow render the component and access the inner method, but the first one cannot be found when I import it (maybe related to RN version?) and enzyme cannot be installed properly (maybe again, a dependency issue). So what I wonder is, what's the best way to test an inner method.
You don't have to actually wrap your component in a provider. If you just want to test your component, you can export it without connect()(). For instance:
export class App extends React.Component {
// your things
}
export default connect()(App);
Inside your test file, you can import your app like so:
import ConnectedApp, { App } from "../App";
Then when you want to test your encapsulated App, you can treat it like any other standard component:
const props = {
// mocked-out props your store would provide
};
const component = shallow(<App {...props} />);
component.instance().whateverMethodYouWant();
Personally, I never wrap a component in a mock provider unless I need to render and deeper components are connected.
I have a single component App.js where I trying to save state using redux. In index.js where I set store for only <App /> component.
index.js
let store = createStore(scoreReducer);
ReactDOM.render(
<Provider store={store}><App /></Provider>,
document.getElementById("root")
);
registerServiceWorker();
I have this method in App.js to map state to props which is available inside App.js.
App.js
function mapStateToProps(state) {
return { score: state.score, status: state.status };
}
Everything is well so far, now I am not sure how to access { this.props.score} in another component ?
What changes I need to do in index.js and second component if I want to access {this.props.score} in another component ?
When you are using Provider any component that is children of the Provider Higher Order Component can access the store properties though the use of connect function.
So you can add the following in any component that is a child of Provider and access the score prop
function mapStateToProps(state) {
return { score: state.score, status: state.status };
}
export default connect(mapStateToProps)(MyComponent)
However if this other component is a direct child of App component then you can also pass the score prop as a prop to this component from App like
<MyComponent score={this.props.score}/>
Provider component sets the context for all its children, providing the store in it. when you use the High Order Component(HOC) connect you can wrap any component and access the store through the provided mapStateToProps and mapStateToProps no matter how nested they are. You can also access the store using context context.store but this is not recommended. Using map functions and connect, similar to what you have with your App component, is the best approach.