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);
});
});
Related
I think i'm misunderstanding some concept about jest functions, I'm trying to test if after a click my isCartOpen is being set to true; the function is working, being called with the desired value.
The problem is that my state isn't changing at all. I tried to set a spy to dispatch but i really can't understand how spy works or if it's even necessary in this case
// cart-icons.test.tsx
import { render, screen, fireEvent } from 'utils/test'
import CartIcon from './cart-icon.component'
import store from 'app/store'
import { setIsCartOpen } from 'features/cart/cart.slice'
const mockDispatchFn = jest.fn()
jest.mock('hooks/redux', () => ({
...jest.requireActual('hooks/redux'),
useAppDispatch: () => mockDispatchFn,
}))
describe('[Component] CartIcon', () => {
beforeEach(() => render(<CartIcon />))
it('Dispatch open/close cart action when clicked', async () => {
const { isCartOpen } = store.getState().cart
const iconContainer = screen.getByText(/shopping-bag.svg/i)
.parentElement as HTMLElement
expect(isCartOpen).toBe(false)
fireEvent.click(iconContainer)
expect(mockDispatchFn).toHaveBeenCalledWith(setIsCartOpen(true))
// THIS SHOULD BE WORKING, BUT STATE ISN'T CHANGING!
expect(isCartOpen).toBe(true)
})
})
// cart-icon.component.tsx
import { useAppDispatch, useAppSelector } from 'hooks/redux'
import { selectIsCartOpen, selectCartCount } from 'features/cart/cart.selector'
import { setIsCartOpen } from 'features/cart/cart.slice'
import { ShoppingIcon, CartIconContainer, ItemCount } from './cart-icon.styles'
const CartIcon = () => {
const dispatch = useAppDispatch()
const isCartOpen = useAppSelector(selectIsCartOpen)
const cartCount = useAppSelector(selectCartCount)
const toggleIsCartOpen = () => dispatch(setIsCartOpen(!isCartOpen))
return (
<CartIconContainer onClick={toggleIsCartOpen}>
<ShoppingIcon />
<ItemCount>{cartCount}</ItemCount>
</CartIconContainer>
)
}
export default CartIcon
// utils/test.tsx
import React, { FC, ReactElement } from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import { ApolloProvider } from '#apollo/client'
import { Elements } from '#stripe/react-stripe-js'
import { render, RenderOptions } from '#testing-library/react'
import store from 'app/store'
import { apolloClient, injectStore } from 'app/api'
import { stripePromise } from './stripe/stripe.utils'
injectStore(store)
const AllTheProviders: FC<{ children: React.ReactNode }> = ({ children }) => {
return (
<Provider store={store}>
<ApolloProvider client={apolloClient}>
<BrowserRouter>
<Elements stripe={stripePromise}>{children}</Elements>
</BrowserRouter>
</ApolloProvider>
</Provider>
)
}
const customRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>
) => render(ui, { wrapper: AllTheProviders, ...options })
export * from '#testing-library/react'
export { customRender as render }
I'm trying to mock out the import { Auth0Provider } from "#auth0/auth0-react"; in a react app and keep running into issues with this error [Error: For security reasons, window.crypto is required to run auth0-spa-js.] From what I can tell this error is coming from the Auth0Client which gets imported from import { Auth0Client } from '#auth0/auth0-spa-js'; My thought is to mock out the scoped module #auth0/auth0-spa-js and do something like this
const handleRedirectCallback = jest.fn(() => ({ appState: {} }));
const buildLogoutUrl = jest.fn();
const buildAuthorizeUrl = jest.fn();
const checkSession = jest.fn();
const getTokenSilently = jest.fn();
const getTokenWithPopup = jest.fn();
const getUser = jest.fn();
const getIdTokenClaims = jest.fn();
const isAuthenticated = jest.fn(() => false);
const loginWithPopup = jest.fn();
const loginWithRedirect = jest.fn();
const logout = jest.fn();
export const Auth0Client = jest.fn(() => {
return {
buildAuthorizeUrl,
buildLogoutUrl,
checkSession,
handleRedirectCallback,
getTokenSilently,
getTokenWithPopup,
getUser,
getIdTokenClaims,
isAuthenticated,
loginWithPopup,
loginWithRedirect,
logout,
};
});
This seems to be working if I import the Auth0Client into any of my tests, but the problem is that the Auth0Provider is still importing the non mocked out client. Is there anyway to get the Auth0Provider to import the mocked out Auth0Client instead of the actual implementation? The file that uses the Auth0Provider looks like this
// test-utils.js
import React from 'react'
import { render as rtlRender } from '#testing-library/react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { MockedProvider } from '#apollo/client/testing';
import { Auth0Provider } from "#auth0/auth0-react";
import { Auth0Client } from '#auth0/auth0-spa-js';
// Import your own reducer
import applicationsReducer from "../app/slices/applications.slice";
import { UserProvider } from "../user-context";
import {getUserMock} from "../__tests__/apollo_mocks/get_user.mock"
// const MockedAuth0Provider = jest.requireActual("#auth0/auth0-react").Auth0Provider
function render(
ui,
{
initialState,
mocks,
store = createStore(applicationsReducer, initialState),
...renderOptions
} = {}
) {
function Wrapper({ children }) {
return <Auth0Provider clientId="__test_client_id__" domain="__test_domain__">
<Provider store={store}>
<MockedProvider mocks={[getUserMock, ...mocks]} addTypename={false}>
<UserProvider>{children}</UserProvider>
</MockedProvider>
</Provider>
</Auth0Provider>
}
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions })
}
// re-export everything
export * from '#testing-library/react'
// override render method
export { render }
Hopefully this helps someone else but I ended up mocking the provider as well as some of the other auth0 modules that I was using this way
jest.mock('#auth0/auth0-react', () => ({
Auth0Provider: ({ children }) => children,
withAuthenticationRequired: ((component, _) => component),
useAuth0: () => {
return {
isLoading: false,
user: { sub: "foobar" },
isAuthenticated: true,
loginWithRedirect: jest.fn()
}
}
}));
This is all in my setupTests.js file
I have a problem testing the component
import React from "react";
import { useSelector } from "react-redux";
import { PopupListWrapper, Song } from "./PopupListStyles";
const PopupList = () => {
const selectedAlbum = useSelector((state) => state.album);
return (
<PopupListWrapper data-testid="popupList-test">
{selectedAlbum.map((song) => {
const { trackName, trackTime } = song;
return (
<Song key={trackName}>
<p>{trackName}</p>
<p>{trackTime}</p>
</Song>
);
})}
</PopupListWrapper>
);
};
export default PopupList;
I want to check if it redner, but I still have a problem with its internal function
import { render } from "#testing-library/react";
import "#testing-library/jest-dom/extend-expect";
import configureStore from "redux-mock-store";
import { Provider } from "react-redux";
import * as reactRedux from "react-redux";
import PopupList from "./PopupList";
describe("<PopupAlbumInformation/>", () => {
const initialState = {
selectedAlbum: [],
};
const mockStore = configureStore();
let store;
const useSelectorMock = jest.spyOn(reactRedux, "useSelector");
beforeEach(() => {
useSelectorMock.mockClear();
});
it("whether the component PopupList is rendering", () => {
store = mockStore(initialState);
useSelectorMock.mockReturnValue({ initialState });
const { selectedAlbum } = initialState;
const { getByTestId } = render(
<Provider store={store}>
<PopupList>{selectedAlbum}</PopupList>
</Provider>
);
});
});
And here is error
TypeError: selectedAlbum.map is not a function
10 | return (
11 | <PopupListWrapper data-testid="popupList-test">
> 12 | {selectedAlbum.map((song) => {
| ^
13 | const { trackName, trackTime } = song;
14 | return (
15 | <Song key={trackName}>
yes i know i don't have an assertion yet but because of this problem i can't go any further.
Any help?
There is no need to mock nor spy on the selector. Just wrap the component in redux provider, pass correct initial state and you are absolutely gucci
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 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)
// });
});