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

heikkimu picture heikkimu  路  3Comments

AdamYahid picture AdamYahid  路  3Comments

mattkauffman23 picture mattkauffman23  路  3Comments

benadamstyles picture benadamstyles  路  3Comments

ahuth picture ahuth  路  3Comments