英文:
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'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 '@mui/material';
<Slider
data-testid="quota-slider"
step={10}
size="medium"
min={10}
onChange={(event: Event, value: number | number[]) => {
setSliderValue(value)
}
value={sliderValue}
/>
I wrote a mock for this Slider component and tried to use it in my tests as follows.
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("test quota selection", () => {
render(<Component />)
fireEvent.change(screen.getByTestId('quota-slider'), {
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 <input />
or <textarea />
, 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 '@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);
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论