enzymejs / enzyme

JavaScript Testing utilities for React
https://enzymejs.github.io/enzyme/
MIT License
19.96k stars 2.01k forks source link

testing stateless component in react gives - TypeError: Cannot set property event of #<Window> which has only a getter #2508

Closed javatype closed 3 years ago

javatype commented 3 years ago

Current behavior

Facing this issue when I try to test react stateless functional component. Test class-

it('should call callback on click', function () {
const handleSearchCallBack = (event) => {
   console.log('please call this');
};
const wrapper = mount(<TextIconSearchButton  handleOnClick={handleSearchCallBack} />);
wrapper.find('input').at(0).simulate('change', { target: { value: 1 } });
});

and Component -

import Button from '@material-ui/core/Button';
import SearchIcon from '@material-ui/icons/Search';
import React from 'react';
const TextIconSearchButton = ({handleOnClick}) => (
<div>
    <Button
      onClick={handleOnClick}
      variant="contained"
      color="primary"
      startIcon={<SearchIcon />}
    >
    </Button>
  </div>
);

export default TextIconSearchButton; On running a test, mocha --require @babel/register --require test/testSetup.js it continuously printed below error in a long loop Error: Uncaught [TypeError: Cannot set property event of # which has only a getter]

and then finally,

Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

Its thrown at this line from react-dom.js if (typeof window.event !== 'undefined' && window.hasOwnProperty('event')) { window.event = windowEvent; }

This happens when I do enzyme's mount instead of shallow. I tried ReactDOM.render from test-utils but same result is popping up.

I tried upgrading to 17.0.1 react version but that endless loop gets worst and test case never exits.

Expected behavior

should able to mount functional component

Your environment

API

Version

library version
enzyme 3.11.0
react 16.8.2
react-dom 16.8.2
react-test-renderer
adapter (below)

Adapter

ljharb commented 3 years ago

What version of jsdom?

I'd suggest trying different ones until you can get it to work.

javatype commented 3 years ago

Hi, thanks for getting back. jsdom is 16.4.0, tried 16.5.0, no luck yet.

ljharb commented 3 years ago

I meant, try v16, v15, v14, etc, all the way down.

javatype commented 3 years ago

Thanks! with all way down to 9.12.0 jsdom, I can get rid of that exception on mount, but my find is not working anymore even if I pass 4 strings in array.

expect(wrapper.find(MenuItem)).to.have.length(4);

ljharb commented 3 years ago

Can you share the actual test and component code?

javatype commented 3 years ago

last commented line also fails to get simulate

ljharb commented 3 years ago

What is wrapper.debug()?

javatype commented 3 years ago

Can you please point out line? expect is from chai.

ljharb commented 3 years ago

What I'm asking is, after the const wrapper = mount( line, can you add console.log(wrapper.debug()) and share the resulting output here.

javatype commented 3 years ago
<GenericDropDown menuOptions={{...}} style={{...}} handleChange={[Function: handleAdvancedSearchCallBack]} dropDownID={2}>
  <div style={{...}}>
    <WithStyles(ForwardRef(Select)) value={2} onChange={[Function: handleAdvancedSearchCallBack]} autoWidth={true}>
      <ForwardRef(Select) classes={{...}} value={2} onChange={[Function: handleAdvancedSearchCallBack]} autoWidth={true}>
        <WithStyles(ForwardRef(Input)) inputComponent={{...}} inputProps={{...}} value={2} onChange={[Function: handleAdvancedSearchCallBack]}>
          <ForwardRef(Input) classes={{...}} inputComponent={{...}} inputProps={{...}} value={2} onChange={[Function: handleAdvancedSearchCallBack]}>
            <WithStyles(ForwardRef(InputBase)) classes={{...}} fullWidth={false} inputComponent={{...}} multiline={false} type="text" inputProps={{...}} value={2} onChange={[Function: handleAdvancedSearchCallBack]}>
              <ForwardRef(InputBase) classes={{...}} fullWidth={false} inputComponent={{...}} multiline={false} type="text" inputProps={{...}} value={2} onChange={[Function: handleAdvancedSearchCallBack]}>
                <div className="MuiInputBase-root MuiInput-root MuiInput-underline" onClick={[Function: handleClick]}>
                  <ForwardRef(SelectInput) aria-invalid={[undefined]} aria-describedby={[undefined]} autoComplete={[undefined]} autoFocus={[undefined]} defaultValue={[undefined]} disabled={[undefined]} id={[undefined]} onAnimationStart={[Function: handleAutoFill]} name={[undefined]} placeholder={[undefined]} readOnly={[undefined]} required={[undefined]} rows={[undefined]} value={2} onKeyDown={[undefined]} onKeyUp={[undefined]} inputRef={[Function (anonymous)]} type={[undefined]} IconComponent={{...}} variant="standard" multiple={false} autoWidth={true} displayEmpty={false} labelId={[undefined]} MenuProps={[undefined]} onClose={[undefined]} onOpen={[undefined]} open={[undefined]} renderValue={[undefined]} SelectDisplayProps={{...}} classes={{...}} className="MuiInputBase-input MuiInput-input" onBlur={[Function: handleBlur]} onChange={[Function: handleChange]} onFocus={[Function: handleFocus]}>
                    <div className="MuiSelect-root MuiSelect-select MuiSelect-selectMenu MuiInputBase-input MuiInput-input" tabIndex={0} role="button" aria-disabled={[undefined]} aria-expanded={[undefined]} aria-haspopup="listbox" aria-label={[undefined]} aria-labelledby={[undefined]} onKeyDown={[Function: handleKeyDown]} onMouseDown={[Function: handleMouseDown]} onBlur={[Function: handleBlur]} onFocus={[Function: handleFocus]} id={[undefined]}>
                      3
                    </div>
                    <input value={2} name={[undefined]} aria-hidden={true} onChange={[Function: handleChange]} tabIndex={-1} className="MuiSelect-nativeInput" autoFocus={[undefined]} aria-describedby={[undefined]} autoComplete={[undefined]} id={[undefined]} onAnimationStart={[Function: handleAutoFill]} placeholder={[undefined]} required={[undefined]} rows={[undefined]} onKeyDown={[undefined]} onKeyUp={[undefined]} />
                    <ForwardRef(ArrowDropDownIcon) className="MuiSelect-icon">
                      <WithStyles(ForwardRef(SvgIcon)) className="MuiSelect-icon">
                        <ForwardRef(SvgIcon) classes={{...}} className="MuiSelect-icon">
                          <svg className="MuiSvgIcon-root MuiSelect-icon" focusable="false" viewBox="0 0 24 24" color={[undefined]} aria-hidden={true} role={[undefined]}>
                            <path d="M7 10l5 5 5-5z" />
                          </svg>
                        </ForwardRef(SvgIcon)>
                      </WithStyles(ForwardRef(SvgIcon))>
                    </ForwardRef(ArrowDropDownIcon)>
                    <WithStyles(ForwardRef(Menu)) id="menu-" anchorEl={{...}} open={false} onClose={[Function: handleClose]} MenuListProps={{...}} PaperProps={{...}}>
                      <ForwardRef(Menu) classes={{...}} id="menu-" anchorEl={{...}} open={false} onClose={[Function: handleClose]} MenuListProps={{...}} PaperProps={{...}}>
                        <WithStyles(ForwardRef(Popover)) getContentAnchorEl={[Function: getContentAnchorEl]} classes={[undefined]} onClose={[Function: handleClose]} onEntering={[Function: handleEntering]} anchorOrigin={{...}} transformOrigin={{...}} PaperProps={{...}} open={false} transitionDuration="auto" id="menu-" anchorEl={{...}}>
                          <ForwardRef(Popover) classes={{...}} getContentAnchorEl={[Function: getContentAnchorEl]} onClose={[Function: handleClose]} onEntering={[Function: handleEntering]} anchorOrigin={{...}} transformOrigin={{...}} PaperProps={{...}} open={false} transitionDuration="auto" id="menu-" anchorEl={{...}}>
                            <ForwardRef(Modal) container={{...}} open={false} BackdropProps={{...}} className="MuiPopover-root" onClose={[Function: handleClose]} id="menu-" />
                          </ForwardRef(Popover)>
                        </WithStyles(ForwardRef(Popover))>
                      </ForwardRef(Menu)>
                    </WithStyles(ForwardRef(Menu))>
                  </ForwardRef(SelectInput)>
                </div>
              </ForwardRef(InputBase)>
            </WithStyles(ForwardRef(InputBase))>
          </ForwardRef(Input)>
        </WithStyles(ForwardRef(Input))>
      </ForwardRef(Select)>
    </WithStyles(ForwardRef(Select))>
  </div>
</GenericDropDown>
javatype commented 3 years ago

Kept trying with various versions of JSDOM to see where its breaking with original reported error. its 16.0.0 onward.

ljharb commented 3 years ago

So, in that debug output, there's no MenuItem anything listed. However, I notice that in your component code, you have import MenuItem from '@material-ui/core/MenuItem'; but in your test code you have import {MenuItem} from '@material-ui/core';. Those likely aren't the same MenuItem.

javatype commented 3 years ago

Thanks! I updated test case to have imports in sync. still no effect.

import { MenuItem } from '@material-ui/core/MenuItem';

issue in finding child component remains there. Not sure why child nodes are missing even after mount.

ljharb commented 3 years ago

It might be an implementation detail of Material UI; i'm not really sure.

javatype commented 3 years ago

You are right! Also not sure but I will choose not to test their library in detail! Other components where I am using my own components as a child are working just fine(till now!). Thanks for your help!