20

我正在转移到 react-testing-library,并且不知道如何触发此事件并获得更改的结果。

我已经尝试使用该fireEvent功能来触发更改,然后尝试了该rerender功能,但我似乎无法让它工作。

应用程序.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;

应用程序.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");

});
4

7 回答 7

18

如果你有一个像 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();
于 2020-05-20T08:36:38.450 回答
10

首先,您不必调用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')
});
于 2019-02-15T09:06:33.183 回答
5

截至 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,所以这有点做作。

于 2020-05-01T10:21:52.417 回答
0

补充@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();
  });
于 2021-10-20T18:38:04.247 回答
0

这对我有用(使用单选按钮,而不是单选组):

// some code here to make sure the screen has finished rendering, and I have all radio buttons in the DOM (I am expecting 5 containers):
await waitFor(() => expect(screen.getAllByTestId('some-slow-loading-container')).toHaveLength(5))

// get all "true" labeled radio buttons by test id (or by role + name or whatever):
const allTrueLabelRadioButtons = screen.getAllByTestId('true-label-radio-button');

// loop over the array of HTML elements found:
for (const trueLabelRadioButton of allTrueLabelRadioButtons) {
   // using fireEvent instead of userEvent because of some bugs with the components library I am stuck with. Usually I use userEvent:
   fireEvent.click(trueLabelRadioButton)
}

// check whatever you are expecting to happen after all radio buttons are set to "true".
//...
于 2022-02-09T13:23:09.430 回答
-1

请从 react-testing-library 文档中尝试这个,“渲染”应该可以正常工作。同意@Gpx

fireEvent.change(input, { target: { value: 'your_value_goes_here' } })
expect(input.value).toBe('expected_value')
于 2019-02-15T09:07:26.670 回答
-1

我也为我做了这项工作:

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-04-07T17:13:54.187 回答