如何使用React测试库测试材料UI自动完成 [英] How to test material ui autocomplete with react testing library

查看:60
本文介绍了如何使用React测试库测试材料UI自动完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用material-ui 自动填充组件,并尝试使用react-测试库

I am using material-ui autocomplete component and am trying to test it using react-testing-library

组件:

/* eslint-disable no-use-before-define */
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import React from 'react';

export default function ComboBox() {
  const [autocompleteInputValue, setAutocompleteInputValue] = React.useState('');
  const [isAutocompleteOpen, setIsAutocompleteOpen] = React.useState(false);
  const renderInput = (params: any) => <TextField {...params} label='openOnFocus: false' variant='outlined' />;

  const getTitle = (option: any) => option.title;

  const handleAutocompleteInputChange = (event: any, value: string) => {
    setAutocompleteInputValue(value);
  };

  const updateAutocompletePopper = () => {
    setIsAutocompleteOpen(!isAutocompleteOpen);
  };

  return (
    <Autocomplete
      id='autocompleteSearch'
      data-testid='autocomplete-search'
      disableClearable={true}
      renderOption={getTitle}
      getOptionLabel={getTitle}
      renderInput={renderInput}
      options={top100Films}
      clearOnEscape={true}
      onInputChange={handleAutocompleteInputChange}
      inputValue={autocompleteInputValue}
      open={isAutocompleteOpen}
      onOpen={updateAutocompletePopper}
      onClose={updateAutocompletePopper}
      style={{ width: 300 }}
      ListboxProps={{ 'data-testid': 'list-box' }}
    />
  );
}

// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
export const top100Films = [
  { title: 'The Shawshank Redemption', year: 1994 },
  { title: 'The Godfather', year: 1972 },
  { title: 'The Godfather: Part II', year: 1974 },
  { title: 'The Dark Knight', year: 2008 },
  { title: '12 Angry Men', year: 1957 },
  { title: 'Schindlers List', year: 1993 },
  { title: 'Pulp Fiction', year: 1994 },
  { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
  { title: 'The Good, the Bad and the Ugly', year: 1966 },
  { title: 'Fight Club', year: 1999 },
  { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
  { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
  { title: 'Forrest Gump', year: 1994 },
  { title: 'Inception', year: 2010 },
  { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
  { title: 'One Flew Over the Cuckoos Nest', year: 1975 },
  { title: 'Goodfellas', year: 1990 },
  { title: 'The Matrix', year: 1999 },
  { title: 'Seven Samurai', year: 1954 },
  { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
  { title: 'City of God', year: 2002 },
  { title: 'Se7en', year: 1995 },
  { title: 'The Silence of the Lambs', year: 1991 },
  { title: 'Its a Wonderful Life', year: 1946 },
  { title: 'Life Is Beautiful', year: 1997 },
  { title: 'The Usual Suspects', year: 1995 },
  { title: 'Léon: The Professional', year: 1994 },
  { title: 'Spirited Away', year: 2001 },
  { title: 'Saving Private Ryan', year: 1998 },
  { title: 'Once Upon a Time in the West', year: 1968 },
  { title: 'American History X', year: 1998 },
  { title: 'Interstellar', year: 2014 },
  { title: 'Casablanca', year: 1942 },
  { title: 'City Lights', year: 1931 },
  { title: 'Psycho', year: 1960 },
  { title: 'The Green Mile', year: 1999 },
  { title: 'The Intouchables', year: 2011 },
  { title: 'Modern Times', year: 1936 },
  { title: 'Raiders of the Lost Ark', year: 1981 },
  { title: 'Rear Window', year: 1954 },
  { title: 'The Pianist', year: 2002 },
  { title: 'The Departed', year: 2006 },
  { title: 'Terminator 2: Judgment Day', year: 1991 },
  { title: 'Back to the Future', year: 1985 },
  { title: 'Whiplash', year: 2014 },
  { title: 'Gladiator', year: 2000 },
  { title: 'Memento', year: 2000 },
  { title: 'The Prestige', year: 2006 },
  { title: 'The Lion King', year: 1994 },
  { title: 'Apocalypse Now', year: 1979 },
  { title: 'Alien', year: 1979 },
  { title: 'Sunset Boulevard', year: 1950 },
  {
    title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb',
    year: 1964,
  },
  { title: 'The Great Dictator', year: 1940 },
  { title: 'Cinema Paradiso', year: 1988 },
  { title: 'The Lives of Others', year: 2006 },
  { title: 'Grave of the Fireflies', year: 1988 },
  { title: 'Paths of Glory', year: 1957 },
  { title: 'Django Unchained', year: 2012 },
  { title: 'The Shining', year: 1980 },
  { title: 'WALL·E', year: 2008 },
  { title: 'American Beauty', year: 1999 },
  { title: 'The Dark Knight Rises', year: 2012 },
  { title: 'Princess Mononoke', year: 1997 },
  { title: 'Aliens', year: 1986 },
  { title: 'Oldboy', year: 2003 },
  { title: 'Once Upon a Time in America', year: 1984 },
  { title: 'Witness for the Prosecution', year: 1957 },
  { title: 'Das Boot', year: 1981 },
  { title: 'Citizen Kane', year: 1941 },
  { title: 'North by Northwest', year: 1959 },
  { title: 'Vertigo', year: 1958 },
  { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
  { title: 'Reservoir Dogs', year: 1992 },
  { title: 'Braveheart', year: 1995 },
  { title: 'M', year: 1931 },
  { title: 'Requiem for a Dream', year: 2000 },
  { title: 'Amélie', year: 2001 },
  { title: 'A Clockwork Orange', year: 1971 },
  { title: 'Like Stars on Earth', year: 2007 },
  { title: 'Taxi Driver', year: 1976 },
  { title: 'Lawrence of Arabia', year: 1962 },
  { title: 'Double Indemnity', year: 1944 },
  { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
  { title: 'Amadeus', year: 1984 },
  { title: 'To Kill a Mockingbird', year: 1962 },
  { title: 'Toy Story 3', year: 2010 },
  { title: 'Logan', year: 2017 },
  { title: 'Full Metal Jacket', year: 1987 },
  { title: 'Dangal', year: 2016 },
  { title: 'The Sting', year: 1973 },
  { title: '2001: A Space Odyssey', year: 1968 },
  { title: 'Singin in the Rain', year: 1952 },
  { title: 'Toy Story', year: 1995 },
  { title: 'Bicycle Thieves', year: 1948 },
  { title: 'The Kid', year: 1921 },
  { title: 'Inglourious Basterds', year: 2009 },
  { title: 'Snatch', year: 2000 },
  { title: '3 Idiots', year: 2009 },
  { title: 'Monty Python and the Holy Grail', year: 1975 },
];


根据从自动完成功能中选择的选项,我正在做其他一些事情,例如渲染芯片,其他组件等.但是为了简单起见,最初我只是在用户专注于输入字段时进行测试,显示弹出窗口,以便稍后,我可以单击该弹出窗口中的一个选项,并测试其他所有功能是否均按预期工作.我正在使用通过自动完成功能的 ListboxProps 属性分配给列表框的 data-testid 验证弹出窗口:

Depending on the option chosen from the autocomplete, I am doing some other stuff, like rendering a chip, another component etc. But to make matters simple, initially I am only testing that, when user focuses in the input field, the pop up is shown so that later, I can click on an option in this popup and test that everything else is working as expected. I am verifying for the popup using data-testid I assigned to list box through ListboxProps prop of autocomplete:

测试:

import {
    fireEvent,
    getByRole as globalGetByRole,
    getByText as globalGetByText,
    render,
} from '@testing-library/react';
import React from 'react';
import ComboBox, { top100Films } from './AutoComplete';

test('that autocomplete works', async () => {
    const { getByTestId, getByRole, queryByRole } = render(<ComboBox />, {});

    const AutoCompleteSearch = getByTestId('autocomplete-search');
    const Input = globalGetByRole(AutoCompleteSearch, 'textbox');

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

    fireEvent.mouseDown(Input);
    const ListBox = getByRole('listbox');
    expect(ListBox).toBeDefined();
    const menuItem1 = globalGetByText(ListBox, top100Films[0].title);
    fireEvent.click(menuItem1);
    expect(queryByRole('listbox')).toBeNull();

    fireEvent.mouseDown(Input);
    const ListBoxAfter = getByRole('listbox');
    expect(ListBoxAfter).toBeDefined();
    const menuItem2 = globalGetByText(ListBoxAfter, top100Films[1].title);
    fireEvent.click(menuItem2);
    expect(queryByRole('listbox')).toBeNull();
});

但这失败了:无法通过以下方式找到元素:[data-testid ="list-box"] .我在做什么错了?

But this is failing with: Unable to find an element by: [data-testid="list-box"]. What am I doing wrong?

编辑:我在 Input 上触发了 mouseDown ,并成功测试了弹出窗口是否打开.我使用了 listbox 角色而不是 data-testid 来验证弹出窗口是否已打开.使用 data-testid 也可以完成相同的操作.然后,我从自动完成选项中选择了一个项目,然后弹出窗口关闭.现在,我尝试第二次再次打开弹出窗口,在这里,它再次失败.使用 mouseDown 事件无法第二次打开.

EDIT: I fired mouseDown on Input and was successfully able to test that the popup is opened. I used listbox role instead of a data-testid to verify that the popup has opened. The same can be done with data-testid as well. Then, I chose an item from autocomplete options and the popup closed. Now, I tried to open the popup again for the 2nd time and here, it fails again. Not able to open in for the 2nd time using mouseDown event.

推荐答案

由于列表项不是可见"的,在DOM本身中,您需要使用其他方法.

Since the list items are not "visible" in the DOM itself you need to use a different approach.

您必须找到将在其上触发事件的自动完成和输入DOM元素.

You have to locate the autocomplete and input DOM elements on which you will trigger events.

自动完成功能通常在DOM中通过角色属性找到,例如 role =" combobox" ,但最好为其赋予一个唯一的标识符,例如 data-testid =" autocomplete"

The autocomplete is usually found in the DOM by the role attribute e.g. role="combobox" but it's best to give it a unique identifier such as data-testid="autocomplete"

以下代码显示了如何在自动完成中测试项目选择:

The following code shows how to test item selection in autocomplete:

   const autocomplete = getByTestId('autocomplete');
   const input = within(autocomplete).querySelector('input')

   autocomplete.focus()
   // assign value to input field
   fireEvent.change(input, { target: { value: value } })
   await wait()
   // navigate to the first item in the autocomplete box
   fireEvent.keyDown(autocomplete, { key: 'ArrowDown' })
   await wait()
   // select the first item
   fireEvent.keyDown(autocomplete, { key: 'Enter' })
   await wait()
   // check the new value of the input field
   expect(input.value).toEqual('some_value')

您需要在输入元素上插入一个值,然后触发更改.之后,列表框打开,允许通过触发回车键选择第一个值.所选值将替换用于搜索/打开自动完成的输入初始值.

You need to insert a value on the input element then trigger the change. After that the listbox opens which permits selecting the first value by firing the enter key. The selected value will replace the entered initial value used to search/open the autocomplete.

这篇关于如何使用React测试库测试材料UI自动完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆