Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooltip issue using Jest: TypeError document.createRange is not a function #15726

Closed
MorganDbs opened this issue May 16, 2019 · 15 comments
Closed
Labels
component: tooltip This is the name of the generic UI component, not the React module! support: question Community support but can be turned into an improvement test

Comments

@MorganDbs
Copy link

Hi, I'm using Jest and Enzyme to test my component.

import React, { Component, Fragment } from "react";
import equal from "fast-deep-equal";
import { TextField, Tooltip, Zoom, withStyles } from "@material-ui/core";
import { checkValue, setValue } from "./PickersFunction";
import { customVariant } from "../../MuiTheme";
import {
  valueVerificationPropType,
  cellValPropType,
  classesPropType,
  typePropType
} from "../../../proptypes";

export class TextFieldWrapper extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tooltipOpen: false,
      message: "",
      error: false
    };
  }

  componentDidMount() {
    const { valueVerification } = this.props;
    if (valueVerification) {
      const newState = checkValue({
        ...this.props,
        mounting: true
      });
      if (!equal(this.state, newState)) {
        this.setState(newState);
      }
    }
  }

  onValueChange = e => {
    const { value } = e.target;
    const newState = setValue({
      ...this.props,
      value
    });
    if (!equal(this.state, newState)) {
      this.setState(newState);
    }
  };

  toggleCloseTooltip = open => {
    const { error } = this.state;
    if (error) {
      this.setState({ tooltipOpen: open });
    }
  };

  render() {
    const { type, cellVal, classes } = this.props;
    const { tooltipOpen, message, error } = this.state;

    return (
      <Tooltip
        open={tooltipOpen}
        classes={{
          tooltip: classes.errorTooltip
        }}
        title={message}
        TransitionComponent={Zoom}
        interactive
      >
        <Fragment>
          <TextField
            value={cellVal}
            error={error}
            onFocus={() => this.toggleCloseTooltip(true)}
            onBlur={() => this.setState({ tooltipOpen: false })}
            onChange={this.onValueChange}
            type={type}
            fullWidth
          />
        </Fragment>
      </Tooltip>
    );
  }
}

TextFieldWrapper.propTypes = {
  cellVal: cellValPropType.isRequired,
  classes: classesPropType.isRequired,
  type: typePropType.isRequired,
  valueVerification: valueVerificationPropType
};

export default withStyles(customVariant)(TextFieldWrapper);

My test :

it("should render a Tootltip and Textfield", () => {
    const wrapper = mount(
      <TextFieldWrapperPureComponent
        cellVal={10}
        type="number"
        columnId="age"
        rowId={rowId}
        valueVerification={valueVerification}
        setRowEdited={setRowEdited}
        classes={{ customVariant }}
      />
    );
    wrapper.instance().onValueChange({ target: { value: 105 } });
  });

Result: ```
TypeError: document.createRange is not a function

  41 |     });
  42 |     if (!equal(this.state, newState)) {
> 43 |       this.setState(newState);
     |            ^
  44 |     }
  45 |   };
  46 | 

...
console.error node_modules/react-dom/cjs/react-dom.development.js:17117
The above error occurred in the component:
in Portal (created by Popper)
in Popper (created by Tooltip)
in Tooltip (created by WithStyles(Tooltip))
in WithStyles(Tooltip) (created by TextFieldWrapper)
in TextFieldWrapper (created by WrapperComponent)
in WrapperComponent


Any ideas ?
@eps1lon eps1lon closed this as completed May 16, 2019
@eps1lon eps1lon reopened this May 16, 2019
@eps1lon eps1lon added the status: waiting for author Issue with insufficient information label May 16, 2019
@eps1lon
Copy link
Member

eps1lon commented May 16, 2019

Please create a minimal repro. It looks like your test setup is incomplete i.e. no DOM is available.

@oliviertassinari
Copy link
Member

oliviertassinari commented May 16, 2019

@MorganDbs See jsdom/jsdom#317. We use the following patch for our tests:

  global.document.createRange = () => ({
    setStart: () => {},
    setEnd: () => {},
    commonAncestorContainer: {
      nodeName: 'BODY',
      ownerDocument: document,
    },
  });

Does it fix your problem?

Update, no longer required since Jest v26.0.0 and jestjs/jest#9606.

@oliviertassinari oliviertassinari changed the title Set tooltip to true from state using Jest causing Error: Uncaught [TypeError: document.createRange is not a function] Tooltip issue using Jest: TypeError document.createRange is not a function May 16, 2019
@oliviertassinari oliviertassinari added component: tooltip This is the name of the generic UI component, not the React module! support: question Community support but can be turned into an improvement test and removed status: waiting for author Issue with insufficient information labels May 16, 2019
@MorganDbs
Copy link
Author

@oliviertassinari Thanks you it's working now !! If I'm understanding well, my test wasn't attached to the BODY, right ?

@balazsorban44
Copy link
Contributor

balazsorban44 commented Jul 1, 2019

@oliviertassinari adding the mock for createRange seem to help, my test is passing, but I get the following console.error:

 without consent, cannot go further (190ms)

  console.error node_modules/react-dom/cjs/react-dom.development.js:506
    Warning: An update to ForwardRef(Popper) inside a test was not wrapped in act(...).        
    When testing, code that causes React state updates should be wrapped into act(...):
        act(() => {
      /* fire events that update state */
    });
    /* assert on the output */
        This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act
        in ForwardRef(Popper) (created by Tooltip)
        in Tooltip (created by WithStyles(Tooltip))
      ....

My test (using @testing-library/react):

it('without consent, cannot go further', () => {
  const {getByText} = render(<Registration/>)
  const loginButton = getByText(/Log in/)
  act(() => {
    fireEvent.mouseEnter(loginButton)
  })
  expect(getByText(/Please accept our terms and conditions/)).toBeInTheDocument()
})

@eps1lon
Copy link
Member

eps1lon commented Jul 1, 2019

@balazsorban44 There are timeouts started when hovering. You should either let all timers run out inside your act() or set the timeouts to 0 via props.

@balazsorban44
Copy link
Contributor

@eps1lon Trying like this:

+ jest.useFakeTimers()
it('without consent, cannot go further', () => {
  const {getByText} = render(<Registration/>)
  const loginButton = getByText(/Log in/)
  act(() => {
    fireEvent.mouseEnter(loginButton)
+   jest.runAllTimers()
  })
  expect(getByText(/Please accept our terms and conditions/)).toBeInTheDocument()
})

Still the same. 🤔 What do I do wrong? I would prefer this solution.
Or if not that, what do you mean by

set timeouts to 0 via props

?

@eps1lon
Copy link
Member

eps1lon commented Jul 1, 2019

Yeah sorry this was just a quick guess. Could you ask the question on stackoverflow and link it from here? I'll take a look later.

@balazsorban44
Copy link
Contributor

balazsorban44 commented Jul 1, 2019

@eps1lon

Yeah sorry this was just a quick guess. Could you ask the question on stackoverflow and link it from here? I'll take a look later.

https://stackoverflow.com/questions/56837949/act-warning-when-testing-component-with-material-ui-tooltip

UPDATE:

The warning goes away in react@16.9.0-alpha.0, don't even need the timers!

@wild-lotus
Copy link

Hey! I just found this thread. I am still reproducing this issue on react@16.13.0, so I guess it did not go way?

@oliviertassinari
Copy link
Member

The issue should have been solved in jsdom@16.0.0 now.

@tedwardmah
Copy link

I stumbled on this thread as well. As @oliviertassinari suggested, using jest-environment-jsdom-sixteen solved the issue for me. Upgrading jest to v26 works as well as jest uses jsdom v16 as of v26 https://jestjs.io/blog/2020/05/05/jest-26

@ZeroDarkThirty
Copy link

@tedwardmah Updating to jest-environment-jsdom-sixteen fixed the issue for me

@gustavo0197
Copy link

@MorganDbs See jsdom/jsdom#317. We use the following patch for our tests:

  global.document.createRange = () => ({
    setStart: () => {},
    setEnd: () => {},
    commonAncestorContainer: {
      nodeName: 'BODY',
      ownerDocument: document,
    },
  });

Does it fix your problem?

I tried this and fixed my problem, thanks

@oliviertassinari
Copy link
Member

Update, since Jest v26.0.0 (jestjs/jest#9606), the workaround in #15726 (comment) is no longer required.

@VinayRajput
Copy link

VinayRajput commented Jul 8, 2021

@MorganDbs See jsdom/jsdom#317. We use the following patch for our tests:

  global.document.createRange = () => ({
    setStart: () => {},
    setEnd: () => {},
    commonAncestorContainer: {
      nodeName: 'BODY',
      ownerDocument: document,
    },
  });

Does it fix your problem?

Update, no longer required since Jest v26.0.0 and facebook/jest#9606.

@oliviertassinari Thanks for sharing, is there any documentation around it, which I can refer to learn more?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: tooltip This is the name of the generic UI component, not the React module! support: question Community support but can be turned into an improvement test
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants