Rob*_*ers 23 reactjs material-ui react-testing-library
我正在尝试使用react-testing-library 测试Select 组件的onChange
事件。
我使用getByTestId
效果很好的元素获取元素,然后设置元素的值,然后调用fireEvent.change(select);
但onChange
从未调用过并且状态从未更新过。
我已经尝试使用 select 组件本身以及获取对底层input
元素的引用,但都不起作用。
任何解决方案?或者这是一个已知问题?
haa*_*dev 80
material-ui 的 select 组件使用 mouseDown 事件触发弹出菜单出现。如果您使用fireEvent.mouseDown
它应该触发弹出窗口,然后您可以在出现的列表框中单击您的选择。见下面的例子。
import React from "react";
import { render, fireEvent, within } from "react-testing-library";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
it('selects the correct option', () => {
const {getByRole} = render(
<>
<Select fullWidth value={selectedTab} onChange={onTabChange}>
<MenuItem value="privacy">Privacy</MenuItem>
<MenuItem value="my-account">My Account</MenuItem>
</Select>
<Typography variant="h1">{/* value set in state */}</Typography>
</>
);
fireEvent.mouseDown(getByRole('button'));
const listbox = within(getByRole('listbox'));
fireEvent.click(listbox.getByText(/my account/i));
expect(getByRole('heading').toHaveTextContent(/my account/i);
});
Run Code Online (Sandbox Code Playgroud)
Alv*_*Lee 16
这证明当您使用材料的UI的是超级复杂Select
与native={false}
(这是默认值)。这是因为渲染的输入甚至没有<select>
HTML 元素,而是混合了 div、隐藏输入和一些 svg。然后,当您单击选择时,会显示一个表示层(有点像模态)以及您的所有选项(<option>
顺便说一下,这些选项不是HTML 元素),我相信单击这些选项之一触发您作为onChange
回调传递给原始 Material-UI 的任何内容<Select>
所有这一切说,如果你愿意用<Select native={true}>
,那么你就必须实际<select>
和<option>
HTML元素一起工作,你可以在火灾发生变化的事件<select>
,你会预期。
这是来自代码沙箱的测试代码,它可以工作:
import React from "react";
import { render, cleanup, fireEvent } from "react-testing-library";
import Select from "@material-ui/core/Select";
beforeEach(() => {
jest.resetAllMocks();
});
afterEach(() => {
cleanup();
});
it("calls onChange if change event fired", () => {
const mockCallback = jest.fn();
const { getByTestId } = render(
<div>
<Select
native={true}
onChange={mockCallback}
data-testid="my-wrapper"
defaultValue="1"
>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</Select>
</div>
);
const wrapperNode = getByTestId("my-wrapper")
console.log(wrapperNode)
// Dig deep to find the actual <select>
const selectNode = wrapperNode.childNodes[0].childNodes[0];
fireEvent.change(selectNode, { target: { value: "3" } });
expect(mockCallback.mock.calls).toHaveLength(1);
});
Run Code Online (Sandbox Code Playgroud)
您会注意到,<select>
一旦 Material-UI 呈现其<Select>
. 但是一旦你找到它,你就可以fireEvent.change
对其进行处理。
CodeSandbox 可以在这里找到:
ken*_*ntr 11
*ByLabelText()
// demo.js
import * as React from "react";
import Box from "@mui/material/Box";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import Typography from "@mui/material/Typography";
export default function BasicSelect() {
const [theThing, setTheThing] = React.useState("None");
const handleChange = (event) => {
setTheThing(event.target.value);
};
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Choose a thing</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={theThing}
label="Choose a thing"
onChange={handleChange}
>
<MenuItem value={"None"}>None</MenuItem>
<MenuItem value={"Meerkat"}>Meerkat</MenuItem>
<MenuItem value={"Marshmallow"}>Marshmallow</MenuItem>
</Select>
</FormControl>
<Box sx={{ padding: 2 }}>
<Typography>The thing is: {theThing}</Typography>
</Box>
</Box>
);
}
Run Code Online (Sandbox Code Playgroud)
// demo.test.js
import "@testing-library/jest-dom";
import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Demo from "./demo";
test("When I choose a thing, then the thing changes", async () => {
render(<Demo />);
// Confirm default state.
expect(await screen.findByText(/the thing is: none/i)).toBeInTheDocument();
// Click on the MUI "select" (as found by the label).
const selectLabel = /choose a thing/i;
const selectEl = await screen.findByLabelText(selectLabel);
expect(selectEl).toBeInTheDocument();
userEvent.click(selectEl);
// Locate the corresponding popup (`listbox`) of options.
const optionsPopupEl = await screen.findByRole("listbox", {
name: selectLabel
});
// Click an option in the popup.
userEvent.click(within(optionsPopupEl).getByText(/marshmallow/i));
// Confirm the outcome.
expect(
await screen.findByText(/the thing is: marshmallow/i)
).toBeInTheDocument();
});
Run Code Online (Sandbox Code Playgroud)
codesandbox 注意:测试不在codesandbox上运行,但在本地运行并通过。
Gab*_*iel 10
使用 Material UI 5.10.3,以下是如何模拟组件上的单击Select
,然后抓取/验证项目值,并单击其中之一来触发底层更改事件:
import { fireEvent, render, screen, within } from '@testing-library/react';
import { MenuItem, Select } from '@mui/material';
describe('MUI Select Component', () => {
it('should have correct options an handle change', () => {
const spyOnSelectChange = jest.fn();
const { getByTestId } = render(
<div>
<Select
data-testid={'component-under-test'}
value={''}
onChange={(evt) => spyOnSelectChange(evt.target.value)}
>
<MenuItem value="menu-a">OptionA</MenuItem>
<MenuItem value="menu-b">OptionB</MenuItem>
</Select>
</div>
);
const selectCompoEl = getByTestId('component-under-test');
const button = within(selectCompoEl).getByRole('button');
fireEvent.mouseDown(button);
const listbox = within(screen.getByRole('presentation')).getByRole(
'listbox'
);
const options = within(listbox).getAllByRole('option');
const optionValues = options.map((li) => li.getAttribute('data-value'));
expect(optionValues).toEqual(['menu-a', 'menu-b']);
fireEvent.click(options[1]);
expect(spyOnSelectChange).toHaveBeenCalledWith('menu-b');
});
});
Run Code Online (Sandbox Code Playgroud)
也发布在这里。
以下是带有“选择”选项的 MUI TextField 的工作示例。
文本域:
import { TextField, MenuItem, InputAdornment } from "@material-ui/core";
import { useState } from "react";
export const sampleData = [
{
name: "Vat-19",
value: 1900
},
{
name: "Vat-0",
value: 0
},
{
name: "Vat-7",
value: 700
}
];
export default function TextSelect() {
const [selected, setSelected] = useState(sampleData[0].name);
return (
<TextField
id="vatSelectTextField"
select
label="#ExampleLabel"
value={selected}
onChange={(evt) => {
setSelected(evt.target.value);
}}
variant="outlined"
color="secondary"
inputProps={{
id: "vatSelectInput"
}}
InputProps={{
startAdornment: <InputAdornment position="start">%</InputAdornment>
}}
fullWidth
>
{sampleData.map((vatOption) => (
<MenuItem key={vatOption.name} value={vatOption.name}>
{vatOption.name} - {vatOption.value / 100} %
</MenuItem>
))}
</TextField>
);
}
Run Code Online (Sandbox Code Playgroud)
测试:
import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import { act } from "react-dom/test-utils";
import TextSelect, { sampleData } from "../MuiTextSelect/TextSelect";
import "@testing-library/jest-dom";
describe("Tests TextField Select change", () => {
test("Changes the selected value", () => {
const { getAllByRole, getByRole, container } = render(<TextSelect />);
//CHECK DIV CONTAINER
let vatSelectTextField = container.querySelector(
"#vatSelectTextField"
) as HTMLDivElement;
expect(vatSelectTextField).toBeInTheDocument();
//CHECK DIV CONTAINER
let vatSelectInput = container.querySelector(
"#vatSelectInput"
) as HTMLInputElement;
expect(vatSelectInput).toBeInTheDocument();
expect(vatSelectInput.value).toEqual(sampleData[0].name);
// OPEN
fireEvent.mouseDown(vatSelectTextField);
//CHECKO OPTIONS
expect(getByRole("listbox")).not.toEqual(null);
// screen.debug(getByRole("listbox"));
//CHANGE
act(() => {
const options = getAllByRole("option");
// screen.debug(getAllByRole("option"));
fireEvent.mouseDown(options[1]);
options[1].click();
});
//CHECK CHANGED
vatSelectInput = container.querySelector(
"#vatSelectInput"
) as HTMLInputElement;
expect(vatSelectInput.value).toEqual(sampleData[1].name);
});
});
/**
* HAVE A LOOK AT
*
*
* https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Select/Select.test.js
* (ll. 117-121)
*
* https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/TextField/TextField.test.js
*
*
*/
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
22016 次 |
最近记录: |