如何在 MUI v5 中对 Slider 组件进行单元测试

huangapple go评论57阅读模式
英文:

How to unit test the Slider component in mui v5

问题

我正在尝试为一个使用 Mui 滑块来选择配额的 React 组件编写单元测试在该组件中滑块的使用如下所示

```js
import { Slider } from '@mui/material';

<Slider
   data-testid="quota-slider"
   step={10}
   size="medium"
   min={10}
   onChange={(event: Event, value: number | number[]) => {
      setSliderValue(value)
   }}
   value={sliderValue}
/>

我为这个 Slider 组件编写了一个模拟,并尝试在我的测试中使用它,如下所示。

import { render, screen, fireEvent } from '@testing-library/react';

jest.mock('@mui/material/Slider', () => (props: any) => {
  const { id, name, min, max, onChange, testid } = props;
  return (
    <input
      data-testid={testid}
      type="range"
      id={id}
      name={name}
      min={min}
      max={max}
      onChange={(event) => onChange(event.target.value)}
    />
  );
});


test("测试配额选择", () => {
  render(<Component />)
  fireEvent.change(screen.getByTestId('quota-slider'), {
      target: { value: 20 },
  });
})

但是当我运行时,我收到以下错误。

给定的元素没有值设置器

有人能帮我解决这个错误吗?TIA.


<details>
<summary>英文:</summary>

I&#39;m trying to write a unit test for a React component in which a Mui slider is used to select the quota. The slider is used as follows in that component.

```js
import { Slider } from &#39;@mui/material&#39;;

&lt;Slider
   data-testid=&quot;quota-slider&quot;
   step={10}
   size=&quot;medium&quot;
   min={10}
   onChange={(event: Event, value: number | number[]) =&gt; {
      setSliderValue(value)
   }
   value={sliderValue}
/&gt;

I wrote a mock for this Slider component and tried to use it in my tests as follows.

import { render, screen, fireEvent } from &#39;@testing-library/react&#39;;

jest.mock(&#39;@mui/material/Slider&#39;, () =&gt; (props: any) =&gt; {
  const { id, name, min, max, onChange, testid } = props;
  return (
    &lt;input
      data-testid={testid}
      type=&quot;range&quot;
      id={id}
      name={name}
      min={min}
      max={max}
      onChange={(event) =&gt; onChange(event.target.value)}
    /&gt;
  );
});


test(&quot;test quota selection&quot;, () =&gt; {
  render(&lt;Component /&gt;)
  fireEvent.change(screen.getByTestId(&#39;quota-slider&#39;), {
      target: { value: 20 },
  });
})

But when I'm running this, I'm getting the following error.

> The given element does not have a value setter

Does anyone can help me to get this error sorted out? TIA.

答案1

得分: 1

fireEvent.change API 适用于标准的 HTML 元素,其中值可以直接更改,比如 <input /><textarea />,你尝试在自定义组件中使用它,但自定义组件没有一个可以直接修改的 value 属性。

在你的模拟中,onChange 属性只是传递了来自 event.target.value 的值,这将是滑块值的字符串表示。Material UI 中的真实 Slider 组件不仅接收新值,还接收一个事件和新值。这就是为什么你的测试失败的原因。

fireEvent.change 正试图在你的模拟滑块上设置一个值,但它并不存在,因为它是一个自定义组件。你可以通过创建一个自定义的触发事件来解决这个问题,以匹配 Slider 的 API。

另外,你应该在你的模拟中正确传递 data-testid 属性。在你之前的模拟中,它被错误地接收为 testid

这里我使用 ...rest 作为剩余属性的 rest 语法,从中提取剩余的属性到新对象中。这创建了一个合成事件,触发了一个具有 null 事件和从范围输入的字符串值解析出的新值的更改。

尝试这个代码示例:

import { render, screen } from '@testing-library/react';

jest.mock('@mui/material/Slider', () => (props: any) => {
  const { onChange, 'data-testid': testId, ...rest } = props;

  return (
    <input
      data-testid={testId}
      type="range"
      onChange={event => {
        onChange(null, parseInt(event.target.value, 10));
      }}
      {...rest}
    />
  );
});

test('test quota selection', () => {
  render(<Component />);
  const slider = screen.getByTestId('quota-slider');
  slider.value = "30";
  fireEvent.change(slider);
});
英文:

fireEvent.change API works with standard HTML elements where the value can be changed directly, like &lt;input /&gt; or &lt;textarea /&gt;, you're trying to use it with a custom component, which doesn't have a value property that can be directly modified.

In your mock, the onChange prop is just passing the value from the event.target.value, which would be the string representation of the slider's value. The real Slider component from Material UI doesn't just receive the new value, but an event and the new value. That's why your test is failing.

The fireEvent.change is trying to set a value on your mock slider that doesn't directly exist, because it's a custom component. You can fix it by creating a custom firing event that matches the Slider's API.

Also you should pass data-testid prop in your mock correctly. It was wrongly received as testid in your previous mock.

Here I have used ...rest as the rest syntax to extract the remaining properties to the new object. This creates a synthetic event that triggers the change with a null event and a new value parsed from the string value of the range input.

Try this out -->

import { render, screen } from &#39;@testing-library/react&#39;;

jest.mock(&#39;@mui/material/Slider&#39;, () =&gt; (props: any) =&gt; {
  const { onChange, `data-testid`: testId, ...rest } = props;

  return (
    &lt;input
      data-testid={testId}
      type=&quot;range&quot;
      onChange={event =&gt; {
        onChange(null, parseInt(event.target.value, 10));
      }}
      {...rest}
    /&gt;
  );
});

test(&#39;test quota selection&#39;, () =&gt; {
  render(&lt;Component /&gt;);
  const slider = screen.getByTestId(&#39;quota-slider&#39;);
  slider.value = &quot;30&quot;;
  fireEvent.change(slider);
});

huangapple
  • 本文由 发表于 2023年6月16日 13:19:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76487141.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定