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.
Related
Can someone help me cover this test case, I am not able to figure out how to cover this inline function
Note: DropdownField is a wrapper component and contains the actual which is imported from
import { Field } from "redux-form";
dropdown input inside
I have tried to call mockfunction and jest.fn() but nothing works, Any help will be appreciated because I am totally blank at the moment. Thanks in advance to all the wonderful devs
import React from "react";
import DropdownField from "components/FormFields/DropdownField";
import get from "lodash/get";
const AddressLookup = props => {
const {
change,
formValues,
fetchAddressLookup,
postalCodeOptions,
type = "delivery",
placeholder = "type_to_search",
field
} = props;
const selectedDeliveryMethod = get(formValues, "delivery_method", {});
return (
<DropdownField
placeholder={placeholder}
options={postalCodeOptions}
{...selectedDeliveryMethod.fields.zip_code}
isSearchable={true}
field={field}
onInputChange={value => {
if (value.length >= 2) fetchAddressLookup({ q: value });
}}
onChange={({ value }) => {
const [city, state, zipCode] = value.split("-");
change(field, value);
change(`${type}_state`, state);
change(`${type}_city`, city);
change(`${type}_zip_code`, zipCode);
}}
/>
);
};
export default AddressLookup;
I have tried this approach but It failed to cover. First test case covers the UI part only as you can see it is matching to snapshot. In second test cases I removed some code and commented some because nothing works
import * as React from 'react';
import { render, fireEvent, wait } from '#testing-library/react';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { reduxForm } from 'redux-form';
import configureStore from 'redux-mock-store';
import messages from '__fixtures__/messages.json';
import AddressLookup from '../index';
const DecoratedAddressLookup = reduxForm({ form: 'testForm' })(AddressLookup);
const testProps = {
change: jest.fn(),
fetchAddressLookup: jest.fn(),
postalCodeOptions: [
{
name: 'abc-abcd-1234',
value: 'abc-abcd-1234',
},
],
formValues: {
delivery_method: {
fields: {
zip_code: 'BD-BDBD-1234',
},
},
},
field: 'zip_code',
};
describe('<AddressLookup />', () => {
let testStore;
let addressField;
const mockStore = configureStore([]);
const store = mockStore({});
const spy = jest.fn();
beforeAll(() => {
testStore = store;
});
const renderComponent = () => {
return render(
<Provider store={testStore}>
<IntlProvider locale='en' messages={messages}>
<DecoratedAddressLookup
{...testProps}
onInputChange={spy}
onChange={spy}
/>
</IntlProvider>
</Provider>
);
};
it('should render and match the snapshot', () => {
const {
getByTestId,
container: { firstChild },
} = renderComponent();
addressField = getByTestId('zip_code');
expect(firstChild).toMatchSnapshot();
});
it('should type a value', async () => {
addressField = addressField.querySelector('input');
// expect(addressField).toBeTruthy();
// console.log('addressField', addressField);
// const input = screen.getByTestId('add-word-input');
fireEvent.change(addressField, { target: { value: 'abc-abcd-1234' } });
expect(addressField).toHaveValue('abc-abcd-1234');
// expect(testProps.change).toBeCalled();
await wait(() => {
expect(spy).toHaveBeenCalledTimes(1);
});
});
});
I want to write test cases for HeaderBar.jsx in the file HeaderBar.spec.jsx.
First I want to write test case for checking my history.push() is executing call then I want to check for history.push() executing with mockURL.
history.push() is found in onLogout()
here is HeaderBar.jsx
import React from 'react';
import { PropTypes } from 'prop-types';
import { bindActionCreators } from 'redux';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import { connect } from 'react-redux';
import { withTranslation } from 'react-i18next';
import { ROUTE_CONSTANTS, I18N_CONSTANTS } from '../../../../constants';
import { commonAction, sessionAction } from '../../../../redux/actions';
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1
}
}));
const HeaderBar = ({ history, t, actions }) => {
const classes = useStyles();
const onLogout = () => {
history.push(ROUTE_CONSTANTS.MEMBER.LOGOUT);
actions.logout();
};
// const onLogout = () => { throw new Error('Failed to run') };
return (
<div className={classes.root}>
<AppBar position="static" color="default">
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
{t('headerBar.title')}
</Typography>
<Button color="inherit" onClick={onLogout}>
{t('headerBar.logout')}
</Button>
</Toolbar>
</AppBar>
</div>
);
};
HeaderBar.defaultProps = {
t: () => {},
history: {
push: () => {}
}
};
const mapStateToProps = state => {
return {
isLoading: state.common.loadingIndicator.isLoading
};
};
const mapDispatchToProps = dispatch => {
return {
actions: bindActionCreators({ ...commonAction, ...sessionAction }, dispatch)
};
};
HeaderBar.propTypes = {
actions: PropTypes.shape({
logout: PropTypes.func.isRequired
}).isRequired,
t: PropTypes.func,
history: PropTypes.shape({
push: PropTypes.func
})
};
const component = connect(mapStateToProps, mapDispatchToProps)(HeaderBar);
export default withTranslation(I18N_CONSTANTS.NAMESPACE.APP)(component);
HeaderBar.spec.jsx
import React from 'react';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import configureStore from '../../../../redux/store/configureStore';
import HeaderBar from './HeaderBar';
const setup = (props = {}) => {
const store = configureStore();
window.location.replace = jest.fn();
const defaultProps = {
isLoading: false,
history: {
replace: jest.fn(x => x)
},
...props
};
return mount(
<Provider store={store}>
<HeaderBar {...defaultProps} />
</Provider>
);
};
describe('HeaderBar component', () => {
it('should call translation 2 times', () => {
const props = { t: jest.fn() };
const wrapper = setup(props);
const { t, isLoading } = wrapper.find('HeaderBar').props();
expect(t).toHaveBeenCalledTimes(2);
expect(isLoading).toBeFalsy();
});
it('should call history on onClick event', () => {
const props = { history: { replace: jest.fn(x => x) }, onLogout: jest.fn(x => x) };
const wrapper = setup(props);
// console.log(wrapper.find('button').debug());
wrapper.find('button').simulate('click');
expect(props.history.replace).toHaveBeenCalledTimes(1);
});
it('should call history with mock URL', () => {
const props = { history: { replace: jest.fn(x => x) } };
const wrapper = setup(props);
const mockURL = '/';
wrapper
.find('button')
.at(0)
.simulate('click');
expect(props.history.replace).toHaveBeenCalledWith(mockURL);
});
});
should call history on onClick event and should call history with mock URL is not working for me.
please help me out on this.
You mock history.replace, but in your component you use history.push.
You mock your functions’ implementations as (x => x), but these functions actually don’t receive any arguments.
Is your logout button really the only in this wrapper’s DOM? Maybe add some id?
I have a component that extends a generic component (custom react component). How do I unit-test using enzyme's mount? Here's the code:
Container.js
import React from 'react';
import request from 'API/request';
export default class Container extends React.Component {
componentDidMount() {
this.populateData();
}
componentDidUpdate() {
if (this.isDataStale()) {
return this.populateData();
}
}
populateData() {
const url = this.getUrl();
const params = this.getParams();
return request(this.props.dispatch, {
url,
params,
method: 'GET'
})
.then(response => {
this.dispatchData(response.data);
})
.catch(error => {
this.dispatchError(error);
});
}
render() {
if (this.getData() && !this.isDataStale()) {
return this.renderChildren();
} else {
return null;
}
}
getError() {}
getParams() {}
isDataStale() {
return false;
}
}
Here's the functional component:
import React from 'react';
import { connect } from 'react-redux';
import { Route, withRouter } from 'react-router-dom';
import CustomPage from 'Client/customPage';
import Container from 'Client/container';
import TestPanel from 'Client/testPanel/TestPanel';
import Greeting from 'Client/greeting';
import Button from '../Button';
export class Test extends Container {
constructor({ match }) {
super();
this.state = {
match: match,
id: match.params.id,
location: ''
};
}
isDataStale() {
return (
this.props.data.id !== this.props.match.params.id
);
}
getData() {
return this.props.data.values;
}
dispatchData(data) {
this.props.dispatch({
type: 'DATA_FOUND',
data: data,
id: this.state.id
});
}
dispatchError(error) {
this.props.dispatch({ type: 'CUSTOM_ERROR', data: error });
}
showDetails(url) {
this.props.history.push(url);
}
renderChildren() {
const match = this.state.match;
const testUrl = `/test/values/${this.state.id}`;
const verifyUrl = `${testUrl}/verify`;
return (
<div className="test-plan">
<Route path={verifyUrl} render={() => (
<Greeting show={true} />
)} />
<TestPanel
data={this.props.data}
id={this.props.match.params.id}
/>
<Route exact path={testUrl} render={() => (
<CustomPage id={this.state.id} />
)} />
<Route path={verifyUrl} render={() => (
<div className="next-button" ><Button label = {' NEXT '} onButtonClick = { this.showDetails.bind(this, loanUrl) } /> </div>
)} />
</div>
);
}
}
const mapStateToProps = state => {
return {
data: state.data
};
};
export default withRouter(connect(mapStateToProps)(Test));
How do I test this Test (functional) component using Enzyme? Am not sure how this mock works since the render method is inside the container which in turn invokes the renderChildren method in our functional component. Lot of functional components extends this container so we can't change this to composition pattern as of now.
Here's the test case (Not working)
import jsdomWindow from '../../test.setup';
import React from 'react';
import {BrowserRouter} from 'react-router-dom';
import { Test } from 'Client/containers/test';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Enzyme, {mount} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';
import * as api from 'API/request';
import { populateData, isDataStale } from '../../../../src/client/app/container';
Enzyme.configure({ adapter: new Adapter() });
const sandbox = sinon.sandbox.create();
describe('<Test />',() => {
beforeEach(function() {
sandbox.stub(api, 'default').returns(Promise.resolve({data: { saySomething: 'Yay Tests!'}}));
});
afterEach(function() {
sandbox.restore();
});
const match = {
params: {
id: 100
}
};
const testState = {
data : {
test: {
id:'100',
email:'someone#something.com',
first_name:'John',
home_phone:'325-555-6564',
last_name:'Doe'
}
}
};
const wrapper = mount(
<BrowserRouter>
<Provider store={createStore(state => state, { data: testState.data })}>
<Test data={testState.data} dispatch={ sinon.spy() }
match={match} />
</Provider>
</BrowserRouter>
);
jest.mock('../../../../src/client/app/container', () => ({
populateData: jest.fn(),
isDataStale: jest.fn(),
getError: jest.fn(),
getParams: jest.fn(),
}));
it('should render', () => {
console.log(wrapper.debug());
populateData.mockReturnValueOnce({});
isDataStale.mockReturnValueOnce(false);
const greetingContainer = wrapper.find('.greeting-container').find('.quick-info').find('.quick-info-heading');
expect(greetingContainer.text()).toContain('PROPER RESPONSE');
});
// it('should render greeting component by default', () => {
// expect(wrapper.find('div.greeting-container')).toBeDefined();
// expect(wrapper.find('div.info-container')).toBeDefined();
// expect(wrapper.find('div.next-button')).toBeDefined();
// });
// it('should not render greeting and next-button components on clicking next', () => {
// console.log(`Test**** ${JSON.stringify(wrapper.find('div.plan'))}`);
// });
});
Could anyone help me to unit test this using mount method of enzyme. Don't want to use shallow here as i have to test nested components' properties.
Thank you.
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)
// });
});
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.