0
votes

I am having an error with rendering a component in the react unit test. I have tried the same with enzyme gives the same error only for mount method.

The error message is:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

The above error occurred in the component: in div (created by Header) in li (created by ForwardRef(ButtonBase)) in ForwardRef(ButtonBase) (created by WithStyles(ForwardRef(ButtonBase))) in WithStyles(ForwardRef(ButtonBase)) (created by ForwardRef(ListItem)) in ForwardRef(ListItem) (created by WithStyles(ForwardRef(ListItem))) in WithStyles(ForwardRef(ListItem)) (created by ForwardRef(MenuItem)) in ForwardRef(MenuItem) (created by WithStyles(ForwardRef(MenuItem))) in WithStyles(ForwardRef(MenuItem)) (created by Header) in ul (created by ForwardRef(List)) in ForwardRef(List) (created by WithStyles(ForwardRef(List))) in WithStyles(ForwardRef(List)) (created by ForwardRef(MenuList)) in ForwardRef(MenuList) (created by ForwardRef(Menu)) in div (created by ForwardRef(Paper)) in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper))) in WithStyles(ForwardRef(Paper)) (created by Transition) in Transition (created by ForwardRef(Grow)) in ForwardRef(Grow) (created by Unstable_TrapFocus) in Unstable_TrapFocus (created by ForwardRef(Modal)) in div (created by ForwardRef(Modal)) in ForwardRef(Portal) (created by ForwardRef(Modal)) in ForwardRef(Modal) (created by ForwardRef(Popover)) in ForwardRef(Popover) (created by WithStyles(ForwardRef(Popover))) in WithStyles(ForwardRef(Popover)) (created by ForwardRef(Menu)) in ForwardRef(Menu) (created by WithStyles(ForwardRef(Menu))) in WithStyles(ForwardRef(Menu)) (created by Header) in div (created by Header) in div (created by Header) in Header (created by Login) in div (created by Login) in div (created by Login) in Login in Router in GlobalProvider (created by WrapperComponent) in WrapperComponent

Heres the code

1. login.js

path: src/components/login/index.js

// Login component
import React, { useState, useEffect } from 'react';
import CustomButton from '../basic-components/button';
import Textfield from '../basic-components/textfield';
import Cross from '../../images/cross-icon.svg';
import { useHistory } from 'react-router-dom';
import ErrorAlert from '../basic-components/snackbar';
import Header from '../basic-components/header';
import Cookies from 'js-cookie';
import { useGlobalState, useGlobalDispatch } from '../context/globalContext';
import './style.scss';

const Login = (props) => {
  // const [email,setEmail] = useState('');
  const [isCookieOn,setCookieOn] = useState(false);
  const [errors,setErrors] = useState({errorSeverity:'',openSnackbar:false,msg:'',isError:false}); 
  const history = useHistory();
  const { email } = useGlobalState();
  const globalDispatch = useGlobalDispatch();
  const getVerificationCode = () => {
    if(errors.isError || !email){
      setErrors(errors=>({...errors,openSnackbar:true,errorSeverity:'error',msg:"Please enter valid email"}));
      return
    }
    history.push('/emailverification');
  }
  const setSnackbar = (value) => {
    setErrors(errors=>({...errors,openSnackbar:value}));
  }
  const onEmailChange = debounce((evt) => {
    globalDispatch({type:'setEmail',payload:evt});
    validateEmail(evt);
  },500);

  const validateEmail = (value) => {
    const expression = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
    if(value && !expression.test(value))
      setErrors(errors=>({...errors,isError:true,msg:"Please enter valid email"}));
    else 
      setErrors(errors=>({...errors,isError:false}));
  }

  const setCookie = () => {
    if(!isCookieOn){
      Cookies.set("CookieConsent",true);
      setCookieOn(true);
    }
  }

  useEffect(()=>{
    let cookie = Cookies.get("CookieConsent");
    if(cookie){
      setCookieOn(cookie);
    }
    props.setPage(true);
    return () => {
      props.setPage(false);
    }
  },[])

  return (
    <div className="login">
      <div className="wrapper">
        <Header/>
        <div className="container">
          <div className='images'>
          </div>
          <p className='subtitle'>Welcome!</p>
          <h1 className='head-text'>Please Sign In</h1>
          <div className="inputs">
            <Textfield
              id="email"
              error={errors.isError}
              onChange={(e)=>onEmailChange(e.target.value)}
              label="Enter your email"
              errorMsg={errors.msg}
            />
            <CustomButton classes="code-btn" onClick={getVerificationCode} text="Get Code"/>
          </div>
        </div>
      </div>
      {!isCookieOn && <div className='cookies'>
        <div className='header'>
          <span className='text'>Cookie Talk</span><img src={Cross} className='cross' onClick={setCookie} alt="cancle cookies"/>
        </div>
        <p className='content'>We use cookies to enhance your browsing exeprience. By continuing to browse or closing this banner, you consent to our use of cookies.</p>
      </div>}
      <ErrorAlert
        openSnackbar={errors.openSnackbar} 
        msg={errors.msg} 
        errorSeverity={errors.errorSeverity} 
        setSnackbar={setSnackbar}
        value={email}
      />
    </div>
  );
};

function debounce (fn, wait) {
  let t
  return function () {
    clearTimeout(t)
    t = setTimeout(() => fn.apply(this, arguments), wait)
  }
}

export default Login;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.1/umd/react-dom.production.min.js"></script>

1. login.spec.js

path: src/components/login/login.spec.js.

//login.spec.js
import React from 'react';
import Login from './index';
import {renderHook} from '@testing-library/react-hooks';
import { render, fireEvent } from '@testing-library/react';

describe("Login",()=>{
  it("should render properly",()=>{
    const wrapper = render(<GlobalProvider><Login setPage={jest.fn()}/></GlobalProvider>);
  })
})

1. header.js

path: src/components/basic-components/header/index.js

//Header component

import React, { useState, useEffect } from 'react';
import { useGlobalState,useGlobalDispatch } from '../../context/globalContext';
// import { useProfileState } from '../../context/profileContext';
import {ReactComponent as SearchIcon}  from '../../../images/search-icon.svg';
import './header.scss';
import NavDrawer from '../drawer/drawer';
import {DashboardIcon}  from '../../SvgComponents/dashboard';
import {SupportIcon}  from '../../SvgComponents/support';
import {ProfileIcon}  from '../../SvgComponents/profile';
import {SettingsIcon}  from '../../SvgComponents/settings';
import {ContactsIcon}  from '../../SvgComponents/mycontacts';
import {ReactComponent as SignOut}  from '../../../images/signOut.svg';
import {DashboardMenuIcon} from '../../SvgComponents/dashboardmenu';
import {Link,useHistory} from 'react-router-dom';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';

const Header = () => {
  const { currentProfileImg,activePage,activeRoute } = useGlobalState();
  const [open,setDrawer] = useState(false);
  const [anchorEl, setAnchorEl] = React.useState(null);
  const globalDispatch = useGlobalDispatch();
  const history = useHistory();

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const updateNavigation = (route) => {
    globalDispatch({type:'setActiveRoute',payload:route});
    history.push(`/${route}`);
  }
  const toggleDrawer = () => {
    setDrawer(state=>!state);
  }
  return (
    <div className='header'>
      <div className="header-container" style={activePage==='dashboard'?{borderBottom:'1px solid #E0E0E0'}:{}}>
        {/* clickable navigation on arrow */}
        //removed some unnecessary code
        <Menu
          id="simple-menu"
          anchorEl={anchorEl}
          keepMounted
          open={Boolean(anchorEl)}
          onClose={handleClose}
          className='nav-desktop-menu'
        >
          <MenuItem onClick={handleClose}>
            <div className={`menu ${activeRoute==='fellowprofile' ? 'active' :''}`} onClick={()=>updateNavigation('fellowprofile')}>
              <ProfileIcon className='nav-icon' isActive={activeRoute==='fellowprofile' ? true :false}/>
              <div className='nav-title'>Profile</div>
            </div>
          </MenuItem>
          <MenuItem onClick={handleClose}>
            <div className={`menu ${activeRoute==='settings' ? 'active' :''}`}  onClick={()=>updateNavigation('settings')}>
              <SettingsIcon className='nav-icon' isActive={activeRoute==='settings' ? true :false}/>
              <div className='nav-title'>Settings</div>
            </div>
          </MenuItem>
          <MenuItem onClick={handleClose}>
            <div className='menu'>
              <SignOut className='nav-icon'/>
              <div className='nav-title'>Sign Out</div>
            </div>
          </MenuItem>
        </Menu>
      
      </div>
      <NavDrawer openDrawer={open} toggleDrawer={toggleDrawer} userProfile={currentProfileImg }/>
    </div>
  );
};

export default Header;
1
What is the content of the ./index file? - Chris
It's the Login component. - Vrushali Bhosale
Could you include the filenames and relative paths of each file (./src/components/index.js)? It looks like a wrong import statement or something similar. - Chris
Yes. I have edited with the relative paths. Though error shows an import problem when I comment out all the MenuItems from header.js file then the test gets passed, it renders the component correctly. Looks like something wrong with the material component styles. - Vrushali Bhosale
If still you are not able to resolve then share the github link and will check the issue there - Mayank Pandeyz

1 Answers

0
votes

The problem here is, I was trying the MenuItem to behave as a link and pushing a new route into the router history. Changing with the forward ref helped.

Here's the link to refer to https://material-ui.com/components/buttons/#third-party-routing-library. It was about the implementation of MenuItems.