首页 > 解决方案 > 使用 react-testing-library 测试材料 ui popper 时如何修复“TypeError: document.createRange is not a function”错误?

问题描述

我有一个材料用户界面TextField,它在焦点上打开一个Popper. 我正在尝试使用 react-testing-library 来测试这种行为。

组件

import ClickAwayListener from '@material-ui/core/ClickAwayListener';
import Grow from '@material-ui/core/Grow';
import Paper from '@material-ui/core/Paper';
import Popper from '@material-ui/core/Popper';
import TextField from '@material-ui/core/TextField';
import React from 'react';
import { ItemType } from './types';

export type TextFieldDropDownProps = {
    items: ItemType,
};

export function TextFieldDropDown(props: TextFieldDropDownProps) {
    const [searchTerm, setSearchTerm] = React.useState('');
    const [anchorEl, setAnchorEl] = React.useState(null);

    const handleSearchTermChange = (event: any) => {
        setSearchTerm(event.target.value);
    };

    const onFoucs = (event: any) => {
        setAnchorEl(event.currentTarget);
    };

    const handleClose = (event: any) => {
        setAnchorEl(null);
    };

    const popperTrans = ({ TransitionProps }: any) => {
        return (
          <Grow
            {...TransitionProps}
            style={{ transformOrigin: '0 0 0' }}
          >
            <Paper>
              <ul />
            </Paper>
          </Grow>
        );
    };

    const open = Boolean(anchorEl);
    return (
        <ClickAwayListener onClickAway={handleClose}>
            <div>
                <TextField
                    onChange={handleSearchTermChange}
                    onFocus={onFoucs}
                    value={searchTerm}
                    label='Search'
                />
                <Popper
                    open={open}
                    anchorEl={anchorEl}
                    transition={true}
                    disablePortal={true}
                    placement='bottom-start'
                    style={{zIndex: 999, minWidth: '100%'}}
                >
                    {popperTrans}
                </Popper>
            </div>
        </ClickAwayListener>
    );
}

测试

import { fireEvent, render, wait } from '@testing-library/react';
import { getTestData } from 'test-data';
import React from 'react';
import { TextFieldDropDown } from './TextFieldDropDown';

test('that on focus on input field, the component shows a dropdown', async () => {
    // Set up test data
    const items: any = getTestData();

    // Render component
    const props = { items };
    const { getByRole, queryByRole } = render(<TextFieldDropDown {...props} />, {});
    await wait();

    expect(queryByRole('list')).toBeNull();

    // Fire event
    const placeSelectInputField = getByRole('textbox') as HTMLInputElement;
    fireEvent.focus(placeSelectInputField);

    // Verify that dropdown is shown
    expect(queryByRole('list')).toBeInTheDocument();

});

当我运行测试时,我收到以下错误 - TypeError: document.createRange is not a function

      The above error occurred in the <div> component:
          in div (created by ForwardRef(Portal))
          in ForwardRef(Portal) (created by ForwardRef(Popper))
          in ForwardRef(Popper) (created by TextFieldDropDown)
          in div (created by ForwardRef(ClickAwayListener))
          in ForwardRef(ClickAwayListener) (created by TextFieldDropDown)
          in TextFieldDropDown
          in Provider (created by AllTheProviders)
          in AllTheProviders

      Consider adding an error boundary to your tree to customize error handling behavior.

      The above error occurred in the <ForwardRef(Popper)> component:
          in ForwardRef(Popper) (created by TextFieldDropDown)
          in div (created by ForwardRef(ClickAwayListener))
          in ForwardRef(ClickAwayListener) (created by TextFieldDropDown)
          in TextFieldDropDown
          in Provider (created by AllTheProviders)
          in AllTheProviders

      Consider adding an error boundary to your tree to customize error handling behavior.


  ● that on focus on input field, the component shows a dropdown

    TypeError: document.createRange is not a function

      46 |     // Fire event
      47 |     const TextFieldComponent = getByRole('textbox') as HTMLInputElement;
    > 48 |     fireEvent.focus(TextFieldComponent);
         |               ^
      49 |
      50 |     // Verify that dropdown is shown
      51 |     expect(queryByRole('list')).toBeInTheDocument();

我该如何进行这项工作?

标签: reactjstypescriptmaterial-uireact-testing-library

解决方案


参考这个 github 问题,我发现我们可以通过将以下代码放入测试设置文件中来修复错误。

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

推荐阅读