Reactjs 如何在react测试库中的单选按钮上触发更改事件?

Reactjs 如何在react测试库中的单选按钮上触发更改事件?,reactjs,jestjs,react-testing-library,Reactjs,Jestjs,React Testing Library,我正在转到react测试库,不知道如何触发此事件并获得更改的结果 我曾尝试使用fireEvent函数触发更改,然后尝试了rerender函数,但似乎无法使其正常工作 App.js import React, { useState } from "react"; import logo from "./logo.svg"; import "./App.css"; const options = { DoTheThing: 'DoTheThing', DoOtherThing: 'DoOt

我正在转到react测试库,不知道如何触发此事件并获得更改的结果

我曾尝试使用
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;
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");

});
import React,{useState}来自“React”;
从“/logo.svg”导入徽标;
导入“/App.css”;
常量选项={
DoTheThing:“DoTheThing”,
DoOtherThing:“DoOtherThing”,
};
函数App(){
const[action,setAction]=useState(options.DoTheThing);
返回(
setAction(event.target.value)}
/>
弗斯特
setAction(event.target.value)}
/>
第二
);
}
导出默认应用程序;
App.test.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;
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");

});
从“React”导入React;
从“反应测试库”导入{render,cleanup,firevent};
从“./App”导入应用程序;
每次之后(清理);
它('应该更改值',()=>{
const{getByLabelText,rerender}=render();
const second=getByLabelText(/second/);
firevent.change(第二);
重新加载();
expect(document.forms[0].elements.radio1.value).toEqual(“DoOtherThing”);
});

首先,您不必调用
rerender
。只有当您希望组件接收不同的道具时,才可以使用
rerender
。看

无论何时调用
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')
});
从“React”导入React;
从“反应测试库”导入{render,firevent};
测试(“收音机”,()=>{
常量{getByLabelText}=render(
弗斯特
第二
);
const radio=getByLabelText('First')
change(radio,{target:{value:{second}});
expect(radio.value).toBe('second')
});

请从react测试库文档中尝试此操作,“渲染”应该可以正常工作。同意@Gpx

fireEvent.change(input, { target: { value: 'your_value_goes_here' } })
expect(input.value).toBe('expected_value')

我也有这项工作要做:

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)

})

截至2020年5月,使用React 16.13和React测试库10.0,接受的答案不起作用(测试本身通过,但实际上没有做任何有意义的事情)

我在react测试库的文档中找不到任何单选按钮的参考,甚至连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”导入React;
阶级国家{
radioValue:string=“一”
}
导出默认类RadioTest扩展React.Component
{
状态:状态=新状态();
radioClick=(事件:React.MouseEvent)=>{
this.setState({radioValue:event.currentTarget.value});
}
render(){
返回(
一个
{}}
选中={this.state.radioValue===“一”}/>
两个
{}}
选中={this.state.radioValue===“two”}/>
当前值={this.state.radioValue}
this.setState({radioValue:{one})}>单击
);
}
}
测试(“无线电测试”),()=>{
常量{getByLabelText,queryByText,getByText}=render();
const one=getByLabelText('one')作为HTMLInputElement
const two=getByLabelText('two')作为HTMLInputElement
期望(一个);
期望(两个).not.toBeChecked();
expect(queryByText(“当前值=1”)).toBeTruthy();
fireEvent。单击(两个);
期望(一)个,而不是;
期望(两个);
expect(queryByText(“当前值=2”)).toBeTruthy();
fireEvent.click(getByText(“click”))
期望(一个);
期望(两个).not.toBeChecked();
expect(queryByText(“当前值=1”)).toBeTruthy();
});
React-onChange处理程序将在浏览器中工作,但不会与React测试库一起工作,因为它们在调用fireEvent.change()时不会启动

需要虚拟onChange处理程序来避免React警告:“如果字段应该是可变的,请使用
defaultChecked
”。但不能使用defaultChecked,因为它会阻止您在代码中设置状态(即,单击底部的按钮不会更新收音机)


因此,总体而言,React似乎希望您使用
onChange
,但React测试库仅适用于
onClick
,因此这有点假惺惺。

如果您有类似Material ui的Radio Component的标签,您可以使用:

const labelRadio: HTMLInputElement = getByLabelText('Label of Radio');
expect(labelRadio.checked).toEqual(false);
fireEvent.click(labelRadio);
expect(androidRadio.checked).toEqual(true);
或者,您可以添加匹配器并通过以下方式进行检查:

expect(getByLabelText('Label of Radio')).not.toBeChecked();
fireEvent.click(labelRadio);
expect(getByLabelText('Label of Radio')).toBeChecked();

我最初发送了一个模拟事件,但后来看到一些(可能)旧信息显示这是不必要的。我只是添加了重新渲染器,因为我看不到更改本身。我记得我为什么要重新渲染。最终,我要测试的是值更改后一组特定输入的外观。我的第一步是能够断言收音机发生了变化。我使用的是
waitForElement
,但它只是超时并抛出。我应该为此创建一个新问题吗?
waitForElement
在发生异步事件时非常有用,例如,您正在等待
fetch
响应。在这种情况下,您不需要等待任何东西,因为更新会立即发生。当
waitForElement
失败时,我尝试使用
wait
。即使这样也不行,问题通常在其他地方。通常,我的组件根本不会更新。但单选按钮不是这样工作的。它们的价值是固定的。只有它们的选中状态改变。这些代码所做的只是将第一个单选按钮的值更改为“second”。现在你只有两台收音机