I am just trying to figure out how to do tests on components that are wrapped with connect. How do I properly define the redux state prop to my component?
● PendingContract with connect/Redux › +++ render the connected(SMART) component
TypeError: Cannot read property 'find' of undefined
Original Component code:
// Dependencies
import React, { Component } from 'react';
import CSSModules from 'react-css-modules';
import { connect } from 'react-redux';
import * as actions from '../../../../actions';
import PendingContractDetail from './pending-contract-
detail/PendingContractDetail';
// CSS
import styles from './PendingContract.css';
export class PendingContract extends Component {
componentWillMount() {
this.props.getSinglePendingContract(this.props.params.contract);
}
render() {
let contract;
if (this.props.contract) {
const contractDetails = this.props.contract;
contract = (
<PendingContractDetail
accepted={contractDetails.accepted}
contractId={contractDetails.contractId}
contractName={contractDetails.contractName}
details={contractDetails.details}
status={contractDetails.status}
timeCreated={contractDetails.timeCreated}
type={contractDetails.type} />
);
} else {
contract = 'Loading...'
};
return (
<div className='row'>
<div className='col-xs-12 col-sm-12 col-md-12'>
{contract}
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
contract: state.pendingContracts.contract
}
}
const PendingContractWithCSS = CSSModules(PendingContract, styles);
export default connect(mapStateToProps, actions)(PendingContractWithCSS);
Test Code as follows:
import React from 'react';
import reduxThunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { shallow, mount } from 'enzyme';
import PendingContract from './PendingContract';
import configureStore from 'redux-mock-store';
jest.mock('react-css-modules', () => Component => Component);
describe('PendingContract with connect/Redux', () => {
const initialState = {
contract: {
accepted: true,
contractId: 1234,
contractName: 'Test Contract',
details: { test: 'test'},
status: 'Accepted',
type: 'Sports'
}
};
const mockStore = configureStore([reduxThunk])
let store,wrapper;
beforeEach(()=>{
store = mockStore(initialState)
wrapper = mount(<Provider store={store}><PendingContract {...initialState} /></Provider>)
})
it('+++ render the connected(SMART) component', () => {
expect(wrapper.find(PendingContract).length).toEqual(1)
});
// it('+++ check Prop matches with initialState', () => {
// expect(wrapper.find(PendingContract).prop('contract')).toEqual(initialState.contract)
// });
});
You need to import connected component if you are trying to fully test it with mount:
import React from 'react';
import reduxThunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { shallow, mount } from 'enzyme';
import ConnectedPendingContract, { PendingContract } from './PendingContract';
import configureStore from 'redux-mock-store';
jest.mock('react-css-modules', () => Component => Component);
describe('PendingContract with connect/Redux', () => {
const initialState = {
contract: {
accepted: true,
contractId: 1234,
contractName: 'Test Contract',
details: { test: 'test'},
status: 'Accepted',
type: 'Sports'
}
};
const mockStore = configureStore([reduxThunk])
let store,wrapper;
beforeEach(()=>{
store = mockStore(initialState)
wrapper = mount(<Provider store={store}><ConnectedPendingContract {...initialState} /></Provider>)
})
it('+++ render the connected(SMART) component', () => {
expect(wrapper.find(PendingContract).length).toEqual(1)
});
// it('+++ check Prop matches with initialState', () => {
// expect(wrapper.find(PendingContract).prop('contract')).toEqual(initialState.contract)
// });
});
Related
import React from 'react';
import { Breadcrumb as AntBreadcrumb, Breadcrumb } from 'antd';
import './breadcrumb.scss';
import { Link, withRouter, RouteComponentProps } from 'react-router-dom';
import { updateBreadcrumb } from './../../../redux/actions/baseLayout';
import { connect } from 'react-redux';
import { HomeOutlined, RightOutlined } from '#ant-design/icons';
interface NewProps {
breadcrumb: any;
}
type Props = NewProps & RouteComponentProps<{}>;
// #TODO
class Render extends React.Component<Props> {
state = {
routes: [{ path: '', breadcrumbName: '' }]
};
// eslint-disable-next-line react/no-deprecated
componentWillReceiveProps(nextProps: any) {
this.setState({
routes: this.props.breadcrumb
});
}
componentDidMount = () => {
this.setState({
routes: this.props.breadcrumb
});
};
itemRender = (route: any, params: any, routes: any, paths: any) => {
const last = routes.indexOf(route) === routes.length - 1;
return last ? (
<span>{route.breadcrumbName}</span>
) : (
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
);
};
shouldComponentUpdate = () => {
return true;
};
componentDidUpdate = (prevProps: RouteComponentProps) => {
if (prevProps !== this.props) {
this.setState({
routes: this.props.breadcrumb
});
}
};
render() {
return (
<div style={{ color: 'red' }}>
<Breadcrumb
style={{ fontWeight: 600, fontSize: '15px', color: 'black' }}
separator={
<RightOutlined
style={{ transform: 'scalex(0.7)', fontSize: '16px' }}
/>
}
>
{this.state.routes.map((route, index) => {
return (
<Breadcrumb.Item key={index} href={`${route.path}`}>
{`${route.breadcrumbName}`}
{/* <HomeOutlined /> */}
</Breadcrumb.Item>
);
})}
</Breadcrumb>
</div>
);
}
}
const mapDispatchToProps = {
updateBreadcrumb: updateBreadcrumb
};
const mapStateToProps = (state: any) => {
return {
breadcrumb: state.breadcrumb.breadcrumb || []
};
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Render));
above code i wanted to write test case but i am not able to mount it i tried to mount it with just but it's not creating snapshot it's givingtest case fail please guide me to right direction or some documentations i am really new to raect and my company gave me this assignment to write test case but i am not finding anywhere any relevent documentations.
import React from 'react';
import Enzyme, { shallow, mount } from 'enzyme';
import Componnent from '../breadcrumb';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store'; //ES6 modules
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import renderer from 'react-test-renderer';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({
adapter: new Adapter()
});
const setUp = (initprops:any) => {
const wrapper = mount(<Router><Provider store={initprops}><Componnent /></Provider></Router>);
return wrapper;
};
describe('Login Component', () => {
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const initialState = {};
const props = mockStore(initialState);
let wrapper:any,instancewrapper:any;
beforeEach(() => {
wrapper = setUp(props);
instancewrapper = wrapper.instance();
});
it('should render correctly', () => {
const tree = renderer.create(<Router><Provider store={props}><Componnent /></Provider></Router>).toJSON();
expect(tree).toMatchSnapshot();
});
});
You can still shallow render a component and use .dive() function to unwrap the main component.
I am using jest and enzyme for the unit testing in the react js.
When I console log the wrapper returned by shallow function by using "console.log(wrapper.debug())" it returns [function] and I am not able to find attribute in the component.
This is my signUp component
signUp.js
import React, { Component } from 'react'
import { withStyles, Card, CardContent, Typography, MenuItem } from '#material-ui/core';
import { darken } from '#material-ui/core/styles/colorManipulator';
import { FuseAnimate } from '#fuse';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux';
import { Link, withRouter } from 'react-router-dom';
import classNames from 'classnames';
import * as Actions from '../../../auth/store/actions/register.actions';
import * as FuseActions from '../../../store/actions/fuse/message.actions';
import Formsy from 'formsy-react';
import { TextFieldFormsy } from '#fuse';
import { Button, InputAdornment, Icon, Grid } from '#material-ui/core';
const styles = theme => ({
root: {
background: 'linear-gradient(to right, ' + theme.palette.primary.dark + ' 0%, ' + darken(theme.palette.primary.dark, 0.5) + ' 100%)',
color: theme.palette.primary.contrastText
}
});
class SignUp extends Component {
render() {
const { classes } = this.props;
const { canSubmit } = this.state;
return (
<div data-test="data-component" className={classNames(classes.root, "flex flex-col flex-1 flex-no-shrink p-24 md:flex-row md:p-0")}>
.........
</div>
)
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
userSignup: Actions.userSignup,
disableErrors: Actions.disableErrors,
showMessage: FuseActions.showMessage
}, dispatch);
}
function mapStateToProps({ auth }) {
return {
register: auth.register
}
}
export default withStyles(styles, { withTheme: true })(withRouter(connect(mapStateToProps, mapDispatchToProps)(SignUp)));
This is test file
signUp.test.js
import React from 'react';
import { configure, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import SignUp from './signUp';
import AppContext from '../../../AppContext';
configure({ adapter: new Adapter() });
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
const setup = (initialState = {}) => {
const store = mockStore(initialState);
const wrapper = shallow(<SignUp store={store} />).dive().dive();
console.log(wrapper.debug());
return wrapper;
}
const findAttrByTest = (wrapper, val) => {
return wrapper.find(`[data-test="${val}"]`);
}
describe("render <SignUp>", () => {
let wrapper;
beforeEach(() => {
const initialState = {
error: '',
success: false
};
wrapper = setup(initialState);
});
test("render component without error", () => {
const component = findAttrByTest(wrapper, 'data-component');
expect(component.length).toBe(1);
});
});
Test result is
FAIL signUp.test.js (5.199s)
render <SignUp>
✕ render component without error (45ms)
● render <SignUp> › render component without error
expect(received).toBe(expected) // Object.is equality
Expected: 1
Received: 0
43 | test("render component without error", () => {
44 | const component = findAttrByTest(wrapper, 'data-component');
> 45 | expect(component.length).toBe(1);
| ^
46 | });
47 | });
48 |
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 6.722s
Ran all test suites related to changed files.
Watch Usage: Press w to show more. console.log signUp.test.js:24
<ContextConsumer>
[function]
</ContextConsumer>
I have solved this issue by using.WrappedComponent.By this, you get access to the component
import React from 'react';
import { configure, shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import SignUp from './signUp';
configure({ adapter: new Adapter() });
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
const push = jest.fn();
const historyMock = { push: jest.fn() };
const setup = (initialState = {}, props = {}) => {
const store = mockStore(initialState);
const wrapper = shallow(<SignUp.WrappedComponent history={historyMock} {...props} store={store} params={{
router:
push
}} />);
return wrapper;
}
const findAttrByTest = (wrapper, val) => {
return wrapper.find(`[data-test="${val}"]`);
}
describe("render <SignUp>", () => {
let wrapper;
beforeEach(() => {
const initialState = {
error: '',
success: false
};
wrapper = setup(initialState);
});
test("render component without error", () => {
const component = findAttrByTest(wrapper, 'data-component');
expect(component.length).toBe(1);
});
});
How can I get access to props of a root component?
import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import cartReducer from './store/cartReducer'
import AddToCart from './cart/addToCart.jsx'
const store = createStore(cartReducer);
render(<Provider store={store}><AddToCart clicked={this.props.onIncrementCounter} />
</Provider>, document.getElementById('addToCart'));
Is it possible? Because I have an error: " Cannot read property 'props' of undefined".
I am new in React.
Here is AddToCart component
import React, { Component } from 'react';
import { connect } from 'react-redux';
class AddToCart extends Component {
constructor(props) {
super(props);
}
}
const mapStateToProps = state => {
return {
items: state.cartItems,
count: state.cartItemCount
};
};
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch({ type: 'INCREMENT' })
};
}
export default connect(mapStateToProps, mapDispatchToProps)(AddToCart);
you got this error " Cannot read property 'props' of undefined" because in that part of your code : <AddToCart clicked={this.props.onIncrementCounter} />
this is referencing anything
you can try this approach:
import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import cartReducer from './store/cartReducer'
import AddToCart from './cart/addToCart.jsx'
const store = createStore(cartReducer);
render(<Provider store={store}><AddToCart/>
</Provider>, document.getElementById('addToCart'));
AddToCart.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
class AddToCart extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div onClick={this.props.onIncrementCounter}>
Increment
</div>
)
}
}
const mapStateToProps = state => {
return {
items: state.cartItems,
count: state.cartItemCount
};
};
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch({ type: 'INCREMENT' })
};
}
export default connect(mapStateToProps, mapDispatchToProps)(AddToCart);
So I want to test a component that uses React's context api and it's not working. It should be seemingly pretty simple - as stated here (React js - How to mock Context when testing component) all you would have to do is something like this:
const context = { name: 'foo' };
const wrapper = mount(<SimpleComponent />, { context });
However, I have something very similar and it doesn't seem to be picking up on it.
Here is my test file -
import * as React from 'react'
import Enzyme, { shallow, mount } from "enzyme";
import Home from '../pages/home/index'
import Adapter from "enzyme-adapter-react-16";
import stateVals from '../__mocks__/stateVals';
console.log('value of stateVals: ', stateVals)
describe('Pages', () => {
describe('Index', () => {
it('should render without throwing an error', function () {
const wrap = mount(<Home/>, { stateData: { state: stateVals } })
expect(wrap.find('div').text()).toBe('hello there main home')
})
})
})
Here is my stateVals object I import:
const stateVals = {
ContextNext: "ldjkfs",
route: "/home",
styledcomponent: "sfsdfsdfsdf",
name: "dfasfasfasdf",
renderCloseAbout: false,
aboutCardStatus: "closed",
uploadedHistory: null,
greptchaTime: Date.now(),
loginStatus: "initial",
registrationStatus: "N/A",
userEmail: "N/A",
completeRegistration: {},
pageVal: "",
addPurchaseSubsJSON: ["empty"],
admins: ['SUPERDOOPERSECRET'],
modal: {
open: false,
message: ''
}
}
export default stateVals
And here is the beginning of the component I want to test -
class Home extends Component {
render(){
return(
<MainContext.Consumer>
{stateData => {
return(
<div className='grid-container abspos'>
{renderIf(stateData.state.modal.open==true)(
<Modal/>
)}
It throws this error:
TypeError: Cannot read property 'state' of undefined
26 | return(
27 | <div className='grid-container abspos'>
> 28 | {renderIf(stateData.state.modal.open==true)(
| ^
29 | <Modal/>
30 | )}
Why is this happening?
EDIT:
This also doesn't work:
import * as React from 'react'
import Enzyme, { shallow, mount } from "enzyme";
import Home from '../pages/home/index'
import Adapter from "enzyme-adapter-react-16";
import stateVals from '../__mocks__/stateVals';
console.log('value of stateVals: ', stateVals)
let context = {state: stateVals }
console.log('value of context: ', context)
describe('Pages', () => {
describe('Index', () => {
it('should render without throwing an error', function () {
const wrap = mount(<Home/>, context )
expect(wrap.find('div').text()).toBe('hello there main home')
})
})
})
Nor this;
const wrap = mount(<Home/>, {context: stateVals})
Nor using this:
const wrap = mount(<Home/>, {context: {stateData: stateVals}})
Nor this:
const wrap = mount(<Home/>, {context: {stateData: {state: stateVals}}})
Nor this;
const wrap = mount(<Home/>, {stateData: stateVals})
The answer turns out to be to wrap the provider as the context api hasn't been finalized yet. Thanks spenguin!
import * as React from 'react'
import Enzyme, { shallow, mount } from "enzyme";
import Home from '../pages/home/index'
import Adapter from "enzyme-adapter-react-16";
import { Provider } from '../services/Context/Provider'
import stateVals from '../__mocks__/stateVals';
describe('Pages', () => {
describe('Index', () => {
it('test ', function () {
const wrap = mount(<Provider value={{stateVals}}><Home/></Provider>)
expect(wrap.find('#maintext').text()).toBe('hello there main home')
})
})
})
Here is a simplified version of my component:
import React from 'react';
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';
import { fromPromise } from 'mobx-utils';
#observer
export class MyComponent extends React.Component {
#action componentDidMount() {
const { store, params } = this.props;
this.warehouse = store.findById(params.id);
}
#observable warehouse = fromPromise(Promise.resolve());
render() {
return this.warehouse.case({
fulfilled: (value) => (
<div>
fulfilled
</div>
),
rejected: (error) => (
<div>
rejected
</div>
),
pending: () => (
<div>
pending
</div>
)
});
}
}
And here is my test (using jest and enzyme):
import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { observable, when } from 'mobx';
import { fromPromise } from 'mobx-utils';
import { MyComponent } from './MyComponent';
describe('<MyComponent>', () => {
it('should render correctly for state "fulfilled"', (done) => {
const mockStore = observable({
findById: jest.fn(() => fromPromise(Promise.resolve({ id: 'id' })))
});
const wrapper = mount(<MyComponent store={mockStore} params={{ id: '1' }} />);
const wh = wrapper.instance().warehouse;
when(
() => wh.state === 'fulfilled',
() => {
expect(wrapper.text()).toBe('fulfilled');
done();
}
);
});
});
The problem is that the handler for when in test runs before render method, so I don't have access to rendered markup there.
My question is how to run my except codes after rendering the fulfilled state.
Also I don't want to hack my component. Here I am using wrapper.instance().warehouse which I don't like very much.
Generally, the question would be how to test components with observable states in them?
I ended up with this solution:
import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { observable, when } from 'mobx';
import { fromPromise } from 'mobx-utils';
import { MyComponent } from './MyComponent';
describe('<MyComponent>', () => {
it('should render correctly for state "fulfilled"', (done) => {
const mockStore = observable({
findById: jest.fn(() => fromPromise(Promise.resolve({ id: 'id' })))
});
const wrapper = mount(<MyComponent store={mockStore} params={{ id: '1' }} />);
const wh = wrapper.instance().warehouse;
when(
() => wh.state === 'fulfilled',
() => {
process.nextTick(() => {
expect(wrapper.text()).toBe('fulfilled');
done();
});
}
);
});
});
Also there is a related question in mobx-react project issues.