How to access App components with Jest when using Redux container? - reactjs

I am having some trouble testing components inside App because I am only exporting AppContainer.
const ConnectedApp = connect(mapStateToProps, mapDispatchToProps)(App);
const AppContainer = () => (
<Provider store={clearanceStore}>
<ConnectedApp />
</Provider>
);
export default AppContainer;
How do I test components inside App's return()? This is what I have for a test now which gives an error: Method “simulate” is meant to be run on 1 node. 0 found instead.
test('setSubmit triggered when clicking submit button', () => {
const setSubmit = jest.fn();
const wrapper = shallow(<App />);
const button = wrapper.find('#something');
button.simulate('click');
expect(setSubmit).toHaveBeenCalled();
});

Here is the Redux documentation that should help you:
In a unit test, you would normally import the App component like this:
import App from './App'
However, when you import it, you're actually holding the wrapper component returned by connect(), and not the App component itself. If you want to test its interaction with Redux, this is good news: you can wrap it in a with a store created specifically for this unit test. But sometimes you want to test just the rendering of the component, without a Redux store.
In order to be able to test the App component itself without having to deal with the decorator, we recommend you to also export the undecorated component:
import { connect } from 'react-redux'
// Use named export for unconnected component (for tests)
export class App extends Component {
/* ... */
}
// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)
Since the default export is still the decorated component, the import statement pictured above will work as before so you won't have to change your application code. However, you can now import the undecorated App components in your test file like this:
// Note the curly braces: grab the named export instead of default export
import { App } from './App'
And if you need both:
import ConnectedApp, { App } from './App'
More at https://redux.js.org/recipes/writing-tests

Related

ReactWrapper::state() can only be called on class components Unit Testing Jest and Enzyme

Writing unit testing in react using jest and enzyme. While checking with a component state , it throws an error "ReactWrapper::state() can only be called on class components ".
import React from 'react';
import { mount } from 'enzyme';
import expect from 'expect';
import CustomerAdd from '../CustomerAdd'
import MUITheme from '../../../../Utilities/MUITheme';
import { ThemeProvider } from '#material-ui/styles';
describe('<CustomerAdd />', () => {
const wrapper = mount(
<ThemeProvider theme={MUITheme}>
<CustomerAdd {...mockProps}></CustomerAdd>
</ThemeProvider>
);
test('something', () => {
expect(wrapper.find(CustomerAdd).state('addNewOnSubmit')).toEqual(true);
});
});
In the above code CustomerAdd Component is class component.I don't what wrong with my code. Can any one help me out of this problem. Thanks in advance.
So your default export
export default withStyles(styles)(CustomerAdd);
exports functional(HOC) wrapper about your class-based component. And it does not matter if name of class and import in
import CustomerAdd from '../CustomerAdd'
are equal. Your test imports wrapped version and after calling .find(CustomerAdd) returns that HOC not your class. And you're unable to work with instance.
Short time solution: export class directly as named export.
export class CustomerAdd extends React.Component{
...
}
export default withStyles(styles)(CustomerAdd);
Use named import in your tests:
import { CustomerAdd } from '../CusomerAdd';
Quick'n'dirty solution: use .dive to access your underlying class-based component:
expect(wrapper.find(CustomerAdd).dive().state('addNewOnSubmit')).toEqual(true);
It's rather antipattern since if you add any additional HOC in your default export you will need to monkey-patch all related tests with adding appropriate amount of .dive().dive()....dive() calls.
Long-term solution: avoid testing state, it's implementation details.
Instead focus on validating what's been rendered. Then you are safe in case of lot of different refactoring technics like replacing class with functional component, renaming state/instance members, lifting state up, connecting component to Redux etc.

Testing in React Redux

I have Dashboard component like below.
import React, { Component } from 'react';
import DataTable from './DataTable';
import { connect } from 'react-redux';
class Dashboard extends Component {
render() {
return <DataTable />;
}
}
export default connect()(Dashboard);
My test is like below
App.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import Dashboard from './components/Dashboard';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Dashboard />, div);
ReactDOM.unmountComponentAtNode(div);
});
describe('Addition', () => {
it('knows that 2 and 2 make 4', () => {
expect(2 + 2).toBe(4);
});
});
I am trying to run test using this command npm test App.test.js.
I am getting below error
Invariant Violation: Could not find "store" in the context of "Connect(Dashboard)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(Dashboard) in connect options.
Your Dashboard is connected to redux, which requires a store. You have a two possibilities :
use Enzyme and redux-mock-store in order to configure a store used when you're mounting your component. This is not well maintainable and leads to a strong dependency between Component and store.
export the non-connected Dashboard (in addition to the default export connected), and mount (eventually with the required props). This is much simpler and maintainable.
export class Dashboard extends Component {
render() {
return <DataTable />;
}
}
// Test :
import { Dashboard } from './components/Dashboard';
ReactDOM.render(<Dashboard />, div);
Note: I think you simplified your connect() for the example purpose, because it does not do anything here, but if this is your real implementation you could drop the connect part and still use the default export for your test.

Error while doing unit test in react-redux connected component

I am trying to test the connected component(react-redux) with jest-enzyme. I am using react-redux-mock store. When I run my test to find one div in the component it gives me this error.
Invariant Violation: Passing redux store in props has been removed and does not do anything. To use a custom Redux store for specific components, create a custom React context with React.createContext(), and pass the context object to React-Redux's Provider and specific components like: <Provider context={MyContext}><ConnectedComponent context={MyContext} /></Provider>. You may also pass a {context : MyContext} option to connect
I did mount and tested just component without redux it works but I want to do a > shallow test.
describe("Input Component", () => {
let wrapper;
let store;
beforeEach(() => {
store = mockStore(initialState);
wrapper = shallow(<Input store={store} />);
});
it("should rendder without error", () => {
expect(wrapper.find("div")).toHaveLength(1);
});
});
How do you import your component?
if your are importing it with import App from './yourpath/App' for example, ou're actually holding the wrapper component returned by connect(), and not the App component itself.
In order to be able to test the App component itself without having to deal with the decorator, you must to also export the undecorated component:
import { connect } from 'react-redux'
// Use named export for unconnected component (for tests)
export class App extends Component {
/* ... */
}
// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)
And import it in your test file like that:
import { App } from './yourpath/App'

Mocking Redux store when testing React components?

I'm using React and Redux. I have a component which loads ChildComponent and depending on Redux's state will also load MainComponent
const ChooseIndex = ({ appInitMount }) => {
return (
<>
<ChildComponent />
{!appInitMount && <MainComponent />}
</>
);
};
const mapStateToProps = ({ main }) => {
return {
appInitMount: main.appInitMount
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ChooseIndex);
I'm trying to write a test to check that ChildComponent is loaded:
import React from "react";
import { render } from "react-testing-library";
import ChooseIndex from "../choose-index";
test("ChooseIndex should call ChildComponent", () => {
const wrapper = render(
<ChooseIndex />
);
});
I get this error:
Error: Uncaught [Invariant Violation: Could not find "store" in either
the context or props of "Connect(ChooseIndex)". Either wrap the root
component in a , or explicitly pass "store" as a prop to
"Connect(ChooseIndex)".]
Should I mock Redux by passing an object literal to ChooseIndex? Or should I create a Redux store (as my real application does) for every test?
Try to render your component like this:
render(
<Provider store={store}>
<ChooseIndex />
</Provider>
)
And pass the actual store you use in your app. In this way, you're testing the real logic that you'll use in production. You also don't care what actions get dispatched and what's in the state. You look at what gets rendered and interact with the UI—which is what matters in the end.
Separating the component from Redux and testing the two in isolation is against the whole point of react-testing-library. You want to test your app as a real user would.
If you check out the writing tests section of the redux docs, there is an example of testing a connected component.
when you import it [A redux connected component], you're actually holding the wrapper component returned by connect(), and not the App component itself. If you want to test its interaction with Redux, this is good news: you can wrap it in a with a store created specifically for this unit test. But sometimes you want to test just the rendering of the component, without a Redux store.
In order to be able to test the App component itself without having to deal with the decorator, we recommend you to also export the undecorated component
As with most unit tests, you really want to be testing your components, and not that redux is working correctly. So the solution for you is to export both the component and the connected component, while only testing the component itself, and providing whatever props redux is passing to your component.
import { connect } from 'react-redux'
// Use named export for unconnected component (for tests)
export class App extends Component {
/* ... */
}
// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)

Snapshot testing react component which depends on inject mobx store

I've been trying to figure out how to do simple snapshot testing for a few components that have mobx stores injected into them. Here's an example:
At the root i have a <Provider> wrapping the whole shebang at my final ReactDOM.render() in the entry point. (not shown here)
// component.js
...{imports}...
#inject('mystore')
#observer
export default class extends React.Component {
render() {
return (
<div>Stuff</div>
)
}
}
// component.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import renderer from 'react-test-renderer';
import Component from './'
it('renders a snapshot', () => {
const tree = renderer.create(<Component/>).toJSON();
expect(tree).toMatchSnapshot();
});
I get a failed test because it's missing a store provided up the tree. I've tried exporting an "undecorated" component like so:
// in component.js
...{same as above}...
export const undecorated = Component
and then importing the undecorated component in my snapshot test, however this doesn't work.
Ideas?
You should be able to pass the store explicitly like so:
const tree = renderer.create(
<Component.wrappedComponent myStore={store}/>).toJSON();
)

Resources