Enzyme: TypeError: p.instance(...).dispatchEvent is not a function

Created on 13 Dec 2019  路  1Comment  路  Source: enzymejs/enzyme

Current behavior

Trying to implement this method. But sporadically running into this error when the test is run.
TypeError: p.instance(...).dispatchEvent is not a function
And here is the test.

  it('clicking outside of cell deselects cell', () => {
    const callBack = jest.fn();
    const thisWrapper = mount(
      <ObjectItemEditableSelectCell
        {...mockConnectProps}
        handleClick={callBack}
      />,
    );
    const p = thisWrapper.find(Layout);
    console.log('p.debug()', p.debug());
    p.instance().dispatchEvent(new Event('click'), { bubbles: true } );
    thisWrapper.update();
    expect(thisWrapper.state('selectedCell')).toBe(true);
  });

Here is the output of p.debug

   p.debug() <Layout listen={true} onClick={[Function: bound handleClick]} el={[Function: el]} width="100%" className="table-editable-cell" node="div" listeners={{...}} tag={false} attr={{...}}>
      <div onClick={[Function: bound handleClick]} id={[undefined]} style={{...}} className="layout table-editable-cell">
        <Text listen={true} node="div" accent={false} bold={false} light={false} disabled={false} secondary={false}>
          <div id={[undefined]} style={[undefined]} className="text text-primary" />
        </Text>
      </div>
    </Layout>

and here is the entire ObjectItemEditableSelectCell component.

import React, { Component } from 'react';
import { Layout, Text, Select } from 'agile-ui';
import cx from 'classnames';
import { ObjectSelect } from '../../../common/_object_dropdown/ObjectSelect.jsx';
import { objectItemEditableSelectCellConnectService } from '../../../../business_layer/connect_services/_object_item/_table/objectItemEditableSelectCellConnectService';

@objectItemEditableSelectCellConnectService
export default class ObjectItemEditableSelectCell extends Component {
  static getDerivedStateFromProps({ displayValue }, { prevDisplayValue }) {
    if (prevDisplayValue !== displayValue) {
      return {
        showField: displayValue,
        prevDisplayValue: displayValue,
      };
    }
    return null;
  }

  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      selectedCell: false,
      showDropdown: false,
      showField: props.displayValue,
      prevDisplayValue: props.displayValue,
      highlightValue: {},
    };
  }

  componentDidMount() {
    this.setState({ highlightValue: this.props.value });
  }

  componentWillUnmount() {
    const query = document.querySelector('.Grid');
    query.removeEventListener('click', this.handleOnClickOnDocument, false);
  }

  handleOnClickOnDocument = (e) => {
    if (this.node && (this.node.contains(e.target) || this.node === e.target)) {
      return;
    }
    this.handleOnClickOutsideCell(e);
  };

  handleOnClickOutsideCell = (e) => {
    const { selectedCell, showDropdown } = this.state;
    this.setState({ selectedCell: false, showDropdown: false });
    const query = document.querySelector('.Grid');
    query.removeEventListener('click', this.handleOnClickOnDocument, false);
  };

  handleClickOnCell = () => {
    const { selectedCell, showDropdown } = this.state;
    if (selectedCell) {
      this.setState({ showDropdown: true });
    } else if (!selectedCell) {
      this.setState({ selectedCell: true });
    }
  };

  handleUnsetPriority = (ev, itemId, workspaceId, onBlur, displayValue) => {
    this.setState({ showField: '' });
    this.setState({
      highlightValue: {
        displayName: '',
        id: null,
      },
    });
    if (displayValue !== null) {
      return onBlur({
        name: ev.name,
        value: null,
        itemId,
        workspaceId,
      });
    }
  };

  onBlur = (ev) => {
    const { onBlur, itemId, workspaceId, displayValue } = this.props;
    const { selectedCell, showDropdown } = this.state;
    this.setState({ showDropdown: false, selectedCell: false });
    if (ev.name === 'priority' && !ev.value) {
      this.handleUnsetPriority(ev, itemId, workspaceId, onBlur, displayValue);
    }
    if (ev && ev.value) {
      switch (ev.name) {
        case 'priority': {
          this.setState({ showField: ev.value.displayName });
          this.setState({
            highlightValue: {
              displayName: ev.value.displayName,
              id: ev.value.id,
            },
          });
          if (displayValue !== ev.value.displayName) {
            return onBlur({
              value: ev.value,
              name: ev.name,
              itemId,
              workspaceId,
            });
          }
          return;
        }

        case 'myCost': {
          this.setState({
            showField: ev.value.get('label'),
          });
          if (displayValue !== ev.value.get('value')) {
            return onBlur({
              costSize: ev.value.get('label'),
              value: ev.value.get('value'),
              name: ev.name,
              updateOboScores: true,
              inTable: true,
              itemId,
              workspaceId,
            });
          }
          return;
        }

        case 'myValidateCost': {
          this.setState({
            showField: ev.value.get('label'),
          });
          if (displayValue !== ev.value.get('value')) {
            return onBlur({
              costSize: ev.value.get('label'),
              value: ev.value.get('value'),
              name: ev.name,
              updateOboScores: true,
              inTable: true,
              itemId,
              workspaceId,
            });
          }
          return;
        }

        case 'owner': {
          const ownerName = `${ev.value.fname} ${ev.value.lname}`;
          this.setState({ showField: ownerName });
          this.setState({
            highlightValue: {
              fname: ev.value.fname,
              id: ev.value.id,
              lname: ev.value.lname,
            },
          });
          if (this.props.value.id !== ev.value.id) {
            return onBlur({
              value: ev.value,
              name: ev.name,
              itemId,
              workspaceId,
            });
          }
          break;
        }

        case 'objectItemType': {
          this.setState({ showField: ev.value.name });
          if (displayValue !== ev.value.name) {
            this.setState({
              highlightValue: { name: ev.value.name, id: ev.value.id },
            });
            return onBlur({
              value: ev.value,
              name: ev.name,
              inTable: true,
              itemId,
              workspaceId,
            });
          }
          break;
        }

        case 'status': {
          this.setState({ showField: ev.value.name });
          if (displayValue !== ev.value.name) {
            this.setState({
              highlightValue: { name: ev.value.name, id: ev.value.id },
            });
            if (ev.value.name !== '') {
              return onBlur({
                value: ev.value,
                name: ev.name,
                inTable: true,
                itemId,
                workspaceId,
              });
            }
          }
          break;
        }

        default:
          this.setState({ showField: ev.value.name });
          if (displayValue !== ev.value.name) {
            this.setState({
              highlightValue: { name: ev.value.name, id: ev.value.id },
            });
            return onBlur({
              value: ev.value,
              name: ev.name,
              itemId,
              workspaceId,
            });
          }
      }
    }
  };

  handleClick() {
    console.log('handleClick');
    const { selectedCell, showDropdown } = this.state;
    if (!selectedCell) {
      this.setState({ selectedCell: true });
      const query = document.querySelector('.Grid');
      query.addEventListener('click', this.handleOnClickOnDocument, false);
    } else if (selectedCell && !showDropdown) {
      this.setState({ showDropdown: true });
    }
  }

  render() {
    const {
      children,
      onEdit,
      className,
      columnName,
      onValueChange,
      name,
      domain,
      record,
      value,
      itemId,
      noExtendedFilters,
      accessor,
      displayValue,
      onBlur,
      filters,
      placeholder,
      narrowResizedWidth,
    } = this.props;

    const {
      selectedCell,
      showDropdown,
      showField,
      highlightValue,
    } = this.state;

    return (
      <Layout
        listen
        onClick={this.handleClick}
        el={(node) => {
          this.node = node;
        }}
        width="100%"
        className={cx(
          className,
          'table-editable-cell',
          selectedCell && 'table-editable-cell--selected',
          showDropdown && 'table-editable-cell--showDropdown',
        )}
      >
        {showDropdown ? (
          <Layout
            className={cx(
              className,
              'dropdown-layout-container',
              narrowResizedWidth &&
                'dropdown-layout-container--narrowResizedWidth',
            )}
          >
            <ObjectSelect
              minWidth="6rem"
              domain={domain}
              onBlur={this.onBlur}
              value={
                name === 'status' || name === 'myCost' ? value : highlightValue
              }
              filters={filters}
              noExtendedFilters={noExtendedFilters}
              placeholder={placeholder}
              Record={record}
              name={name}
              open
              rounded
              accessor={accessor}
            />
          </Layout>
        ) : (
          <Text listen>
            {name === 'status' || name === 'myCost' ? displayValue : showField}
          </Text>
        )}
      </Layout>
    );
  }
}

Would be grateful to anyone who can help.

I am trying to test that once I click anywhere in this component the selectedCell state will get set to true. Sometimes the tests run but the selectedCell state is still false.

Expected behavior

Click event should be registered on component.

Your environment

MacOS Mojave

API

  • [ ] shallow
  • [x] mount
  • [ ] render

Version

| library | version
| ------------------- | -------
| enzyme | 3.3.0
| react | 16.8.6
| react-dom | 16.8.6
| react-test-renderer | 15.6.2
| adapter (below) |

Adapter

  • [x] enzyme-adapter-react-16
  • [ ] enzyme-adapter-react-16.3
  • [ ] enzyme-adapter-react-16.2
  • [ ] enzyme-adapter-react-16.1
  • [x] enzyme-adapter-react-15
  • [ ] enzyme-adapter-react-15.4
  • [ ] enzyme-adapter-react-14
  • [ ] enzyme-adapter-react-13
  • [ ] enzyme-adapter-react-helper
  • [ ] others ( )
mount question

Most helpful comment

As you can see from p.debug(), p is a Layout component, which has an instance that is not a DOM element.

Since you're using mount, you can do p.getDOMNode() to get the DOM node, on which dispatchEvent should work.

>All comments

As you can see from p.debug(), p is a Layout component, which has an instance that is not a DOM element.

Since you're using mount, you can do p.getDOMNode() to get the DOM node, on which dispatchEvent should work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nelsonchen90 picture nelsonchen90  路  3Comments

timhonders picture timhonders  路  3Comments

dschinkel picture dschinkel  路  3Comments

modemuser picture modemuser  路  3Comments

abe903 picture abe903  路  3Comments