如何使用 react-testing-library 测试 react-select

新手上路,请多包涵

应用程序.js

 import React, { Component } from "react";
import Select from "react-select";

const SELECT_OPTIONS = ["FOO", "BAR"].map(e => {
  return { value: e, label: e };
});

class App extends Component {
  state = {
    selected: SELECT_OPTIONS[0].value
  };

  handleSelectChange = e => {
    this.setState({ selected: e.value });
  };

  render() {
    const { selected } = this.state;
    const value = { value: selected, label: selected };
    return (
      <div className="App">
        <div data-testid="select">
          <Select
            multi={false}
            value={value}
            options={SELECT_OPTIONS}
            onChange={this.handleSelectChange}
          />
        </div>
        <p data-testid="select-output">{selected}</p>
      </div>
    );
  }
}

export default App;

应用程序.test.js

 import React from "react";
import {
  render,
  fireEvent,
  cleanup,
  waitForElement,
  getByText
} from "react-testing-library";
import App from "./App";

afterEach(cleanup);

const setup = () => {
  const utils = render(<App />);
  const selectOutput = utils.getByTestId("select-output");
  const selectInput = document.getElementById("react-select-2-input");
  return { selectOutput, selectInput };
};

test("it can change selected item", async () => {
  const { selectOutput, selectInput } = setup();
  getByText(selectOutput, "FOO");
  fireEvent.change(selectInput, { target: { value: "BAR" } });
  await waitForElement(() => getByText(selectOutput, "BAR"));
});

这个最小的示例在浏览器中按预期工作,但测试失败。我认为未调用 onChange 处理程序。如何在测试中触发 onChange 回调?查找要触发事件的元素的首选方法是什么?谢谢

原文由 user2133814 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

这一定是关于 RTL 被问得最多的问题:D

最好的策略是使用 jest.mock (或测试框架中的等效项)来模拟选择并呈现 HTML 选择。

有关为什么这是最好的方法的更多信息,我也写了一些适用于这种情况的东西。 OP 询问了 Material-UI 中的选择,但想法是一样的。

原始问题 和我的答案:

因为您无法控制该 UI。它在第 3 方模块中定义。

所以,你有两个选择:

您可以找出材质库创建的 HTML,然后使用 container.querySelector 查找其元素并与之交互。这需要一段时间,但应该是可能的。完成所有这些之后,您必须希望在每个新版本中它们不会过多地更改 DOM 结构,否则您可能必须更新所有测试。

另一种选择是相信 Material-UI 将制作一个可以工作并且您的用户可以使用的组件。基于这种信任,您可以简单地将测试中的该组件替换为更简单的组件。

是的,选项一测试用户看到的内容,但选项二更容易维护。

以我的经验,第二个选项很好,但当然,您的用例可能会有所不同,您可能必须测试实际的组件。

这是如何模拟选择的示例:

 jest.mock("react-select", () => ({ options, value, onChange }) => {
  function handleChange(event) {
    const option = options.find(
      option => option.value === event.currentTarget.value
    );
    onChange(option);
  }
  return (
    <select data-testid="select" value={value} onChange={handleChange}>
      {options.map(({ label, value }) => (
        <option key={value} value={value}>
          {label}
        </option>
      ))}
    </select>
  );
});

你可以 在这里 阅读更多。

原文由 Giorgio Polvara - Gpx 发布,翻译遵循 CC BY-SA 4.0 许可协议

在我的项目中,我使用了 react-testing-library 和 jest-dom。我遇到了同样的问题 - 经过一些调查,我找到了解决方案,基于线程: https ://github.com/airbnb/enzyme/issues/400

请注意,渲染的顶级函数以及各个步骤必须是异步的。

在这种情况下不需要使用焦点事件,它将允许选择多个值。

此外,getSelectItem 中必须有异步回调。

 const DOWN_ARROW = { keyCode: 40 };

it('renders and values can be filled then submitted', async () => {
  const {
    asFragment,
    getByLabelText,
    getByText,
  } = render(<MyComponent />);

  ( ... )

  // the function
  const getSelectItem = (getByLabelText, getByText) => async (selectLabel, itemText) => {
    fireEvent.keyDown(getByLabelText(selectLabel), DOWN_ARROW);
    await waitForElement(() => getByText(itemText));
    fireEvent.click(getByText(itemText));
  }

  // usage
  const selectItem = getSelectItem(getByLabelText, getByText);

  await selectItem('Label', 'Option');

  ( ... )

}

原文由 momimomo 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进