如何在 react-testing-library 中的单选按钮上触发更改事件?
Posted
技术标签:
【中文标题】如何在 react-testing-library 中的单选按钮上触发更改事件?【英文标题】:How do I trigger a change event on radio buttons in react-testing-library? 【发布时间】:2019-07-09 02:50:50 【问题描述】:我正在迁移到 react-testing-library,但不知道如何触发此事件并获得更改的结果。
我尝试使用fireEvent
函数来触发更改,然后尝试了rerender
函数,但我似乎无法让它工作。
App.js
import React, useState from "react";
import logo from "./logo.svg";
import "./App.css";
const options =
DoTheThing: 'DoTheThing',
DoOtherThing: 'DoOtherThing',
;
function App()
const [action, setAction] = useState(options.DoTheThing);
return (
<div className="App">
<header className="App-header">
<form>
<fieldset>
<label>
<input
type="radio"
name="radio1"
value=options.DoTheThing
checked=action === options.DoTheThing
onChange=event => setAction(event.target.value)
/>
First
</label>
<label>
<input
type="radio"
name="radio1"
value=options.DoOtherThing
checked=action === options.DoOtherThing
onChange=event => setAction(event.target.value)
/>
Second
</label>
</fieldset>
</form>
</header>
</div>
);
export default App;
App.test.js
import React from 'react';
import render, cleanup, fireEvent from 'react-testing-library';
import App from './App';
afterEach(cleanup);
it('should change the value ', () =>
const getByLabelText, rerender = render(<App/>);
const second = getByLabelText(/Second/);
fireEvent.change(second);
rerender(<App/>);
expect(document.forms[0].elements.radio1.value).toEqual("DoOtherThing");
);
【问题讨论】:
【参考方案1】:如果你有一个像 Material-ui 的 Radio Component 这样的标签,你可以使用:
const labelRadio: htmlInputElement = getByLabelText('Label of Radio');
expect(labelRadio.checked).toEqual(false);
fireEvent.click(labelRadio);
expect(androidRadio.checked).toEqual(true);
或者你可以添加https://github.com/testing-library/jest-dom匹配器,这样检查:
expect(getByLabelText('Label of Radio')).not.toBeChecked();
fireEvent.click(labelRadio);
expect(getByLabelText('Label of Radio')).toBeChecked();
【讨论】:
【参考方案2】:首先,您不必致电rerender
。仅当您希望组件接收不同的道具时才使用rerender
。见link。
每当您调用 fireEvent
时,组件都会像在您的普通应用中一样呈现。
触发change
事件是正确的,但您必须传递带有事件数据的第二个参数。
这个例子有效:
import React from "react";
import render, fireEvent from "react-testing-library";
test("radio", () =>
const getByLabelText = render(
<form>
<label>
First <input type="radio" name="radio1" value="first" />
</label>
<label>
Second <input type="radio" name="radio1" value="second" />
</label>
</form>
);
const radio = getByLabelText('First')
fireEvent.change(radio, target: value: "second" );
expect(radio.value).toBe('second')
);
【讨论】:
我最初发送了一个模拟事件,但后来看到一些 [大概] 较旧的信息表明这是不必要的。我只添加了重新渲染,因为我看不到更改本身。 我记得我为什么要重新渲染。最终,我要测试的是值更改后一组特定输入的外观。我的第一步是能够断言收音机发生了变化。我正在使用waitForElement
,但它只是超时并抛出。我应该为此创建一个新问题吗?
waitForElement
在发生异步事件时很有用,例如您正在等待fetch
回复。在这种情况下,您不需要等待任何事情,因为更新会立即发生。当waitForElement
失败时,我尝试改用wait
。如果即使这样也不起作用,问题通常出在其他地方。通常,我的组件根本不会更新。
这不是单选按钮的工作方式。它们的价值是固定的。只有他们的选中状态会改变。
这段代码所做的只是将第一个单选按钮的值更改为“第二个”。现在您只有 2 个值为“second”的单选按钮,但它们都没有被选中。此外,它不会导致响应 onChange 处理程序被调用,所以它不是真的有用【参考方案3】:
截至 2020 年 5 月,使用 React 16.13 和 react-testing-library 10.0,接受的答案不起作用(测试本身通过但实际上并没有做任何有意义的事情)。
我在 react-testing-library 甚至 React 本身的文档中找不到任何对单选按钮的引用。但是,据我所知,这是一个可以正常工作的示例(使用 Typescript)。
import React from "react";
class State
radioValue: string = "one"
export default class RadioTest extends React.Component<, State>
state: State = new State();
radioClick = (event: React.MouseEvent<HTMLInputElement, MouseEvent>) =>
this.setState( radioValue: event.currentTarget.value );
render()
return (<>
<label>
One
<input type="radio" name="radio" onClick=this.radioClick
value="one" onChange=() =>
checked=this.state.radioValue === "one" />
</label>
<label>
Two
<input type="radio" name="radio" onClick=this.radioClick
value="two" onChange=() =>
checked=this.state.radioValue === "two" />
</label>
<div>current value=this.state.radioValue</div>
<button onClick=() => this.setState(radioValue:"one")>Click</button>
</>);
test("radiotest", () =>
const getByLabelText, queryByText, getByText = render(<RadioTest />);
const one = getByLabelText('One') as HTMLInputElement
const two = getByLabelText('Two') as HTMLInputElement
expect(one).toBeChecked();
expect(two).not.toBeChecked();
expect(queryByText("current value=one")).toBeTruthy();
fireEvent.click(two);
expect(one).not.toBeChecked();
expect(two).toBeChecked();
expect(queryByText("current value=two")).toBeTruthy();
fireEvent.click(getByText("Click"))
expect(one).toBeChecked();
expect(two).not.toBeChecked();
expect(queryByText("current value=one")).toBeTruthy();
);
React onChange 处理程序将在浏览器中工作,但不适用于 react-testing-library,因为当您调用 fireEvent.change() 时它们不会触发
需要虚拟 onChange 处理程序来避免 React 警告:“如果字段应该是可变的,请使用 defaultChecked
”。但是你不能使用 defaultChecked,因为它会阻止你在代码中设置状态(即点击底部的按钮不会更新收音机)
所以总的来说,看起来 React 希望你使用 onChange
,但 react-testing-library 只适用于 onClick
,所以这有点做作。
【讨论】:
这是我们问题的解决方案。 .change 不会触发行为【参考方案4】:补充@andy 的回答,这应该有效地测试两个收音机:
it('should render successfully', async () =>
render(
<YourRadioGroup />
);
expect(screen.getByText('option 1')).toBeInTheDocument();
expect(screen.getByText('option 2')).toBeInTheDocument();
);
it('should change checked option', () =>
render(
<YourRadioGroup />
);
const secondRadio = screen.getByLabelText('option 2');
fireEvent.click(secondRadio);
expect(secondRadio).toBeChecked();
const firstRadio = screen.getByLabelText('option 1');
fireEvent.click(firstRadio);
expect(firstRadio).toBeChecked();
expect(secondRadio).not.toBeChecked();
);
【讨论】:
【参考方案5】:请从 react-testing-library 文档中尝试这个,“渲染”应该可以正常工作。同意@Gpx
fireEvent.change(input, target: value: 'your_value_goes_here' )
expect(input.value).toBe('expected_value')
【讨论】:
【参考方案6】:我也有这项工作:
test('Does stuff', async () =>
// ... test prep ...
const formEl = screen.getByTestId('form_test_id')
// You can use screen.getByLabelText here instead of DOM queries
// if you've got a nicely laid out form
const defaultInput = formEl.querySelector('input[value="default_value"]')
const newValueInput = formEl.querySelector('input[value="new_value"]')
// Confirm your baseline
expect(defaultInput.checked).toEqual(true)
expect(newValueInput.checked).toEqual(false)
// Fire the change event
await act(async () =>
fireEvent.change(newValueInput, target: checked: true )
// To trigger any onChange listeners
fireEvent.blur(newValueInput)
)
// Confirm expected form state(s)
expect(defaultInput.checked).toEqual(false)
expect(newValueInput.checked).toEqual(true)
)
【讨论】:
以上是关于如何在 react-testing-library 中的单选按钮上触发更改事件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 react-testing-library 在 react-select 组件上触发更改事件?
如何使用 react-testing-library 测试由其他组件组成的组件?
如何使用 react-testing-library 测试包装在 withStyles 中的样式化 Material-UI 组件?
如何在使用 react-testing-library 和 jest 完成的单元测试中启用 react-i18n 翻译文件?