【问题标题】:ant design v4 breaks react testing library tests for Select and Autocompleteant design v4 打破了对 Select 和 Autocomplete 的反应测试库测试
【发布时间】:2020-07-19 15:36:39
【问题描述】:

我最近将我的 React 项目升级到了 ant design v4,所有使用 Select、AutoComplete 或 Tooltip 的测试都被破坏了。基本上,当单击组件时,JSDOM 中不存在模式或选择选项。这在 v3 中可以正常工作。

有人可以告诉我如何使用 react 测试库测试 antd v4 吗?

示例:

我的组件:

import React from "react";
import "./styles.css";
import { Select } from "antd";

const { Option } = Select;

function handleChange(value) {
  console.log(`selected ${value}`);
}

export default function App() {
  return (
    <div className="App" style={{ marginTop: "40px" }}>
      <Select
        defaultValue="lucy"
        style={{ width: 120 }}
        onChange={handleChange}
      >
        <Option value="jack">Jack</Option>
        <Option value="lucy">Lucy</Option>
        <Option value="disabled" disabled>
          Disabled
        </Option>
        <Option value="Yiminghe">yiminghe</Option>
      </Select>
    </div>
  );
}

我的测试

import "@testing-library/jest-dom/extend-expect";
import React from "react";
import { render, fireEvent, prettyDOM } from "@testing-library/react";
import App from "./App";

test("App Test", () => {
  const { queryAllByText, getByText, container } = render(<App />);

  expect(queryAllByText("Lucy").length).toBe(1);
  expect(queryAllByText("Jack").length).toBe(0);
  fireEvent.click(getByText("Lucy"));
  console.log(prettyDOM(container));
  // This line fails although I would expect the dropdown to be open and all the options visible
  expect(queryAllByText("Jack").length).toBe(1);
});

这里是重现问题的代码框的链接。 (如前所述,该代码曾经在 v3 中工作)。

https://codesandbox.io/s/staging-shape-0xkrl?file=/src/App.test.js:0-494

【问题讨论】:

    标签: javascript reactjs antd react-testing-library


    【解决方案1】:

    在这失去了 2 天之后,这是问题和解决方案:

    问题

    在 antd v3 中,过去可以通过 selectHtmlElement.click() 打开 Select。您可以在 chrome 开发工具控制台中进行测试。在 v4 中,这不起作用。

    这意味着在底层使用 JSDOM 的 RTL 将具有相同的行为。当你这样做时fireEvent.click(selectElement); 什么都没有发生

    解决方案

    这让我走上了正轨:https://github.com/ant-design/ant-design/issues/22074

    您需要触发的事件不是click(),而是选择的第一个孩子上的mouseDown()

    const elt = getByTestId('your-select-test-id').firstElementChild;
    fireEvent.mouseDown(elt); // THIS WILL OPEN THE SELECT !
    

    此时,您可能想从列表中选择一个选项,但有一个动画正在进行,因此以下代码(以前在 v3 中工作)也将失败。

    expect(getByText('Option from Select')).toBeVisible(); // FAILS !
    

    您有 2 个选项,使用 toBeInTheDocument() 或使用 waitFor(...) 等待动画结束

    选项 1:更快但不完全准确,我更喜欢将其用于简单的用例,因为它使测试更快且同步

    expect(getByText('Option from Select')).toBeInTheDocument(); // WORKS !
    

    选项 2:因为您需要等待动画完成,所以速度较慢,但​​在复杂情况下更准确

    await waitFor(() => expect(getByText('Option from Select')).toBeVisible()); // WORKS !
    

    【讨论】:

    • 值得一提的是 fireEvent.change(elt.querySelector('input'), {target:{value:{'Option text'}}) 适用于可搜索的选择(只有正确的选项可见,并准备好被点击)。
    • 完美运行,但您也可以使用setInterval(() =&gt; expect(), 0),而不是await waitFor(),您也可以将open 属性设置为true,而不是执行mouseDown 事件跨度>
    • 工具提示怎么样?你知道如何测试它吗?即使我输入了 data-testid @klugjo,我似乎也无法在测试中找到工具提示
    • 感谢您的 2 天,我只损失了 20 分钟,谢谢您!
    • 其实我可以userEvent.clickimport userEvent from '@testing-library/user-event')打开下拉菜单,但是当我尝试点击选项时,出现unsable to focus的错误。
    【解决方案2】:

    现在看起来 ("antd": "4.17.3", "@testing-library/user-event": "^13.5.0") userEvent.click{ skipPointerEventsCheck: true } 工作:

    const options = [
      { label: "?", value: "cat", },
      { label: "?", value: "dog", }
    ];
    
    const onChangeMock = jest.fn();
    
    render(
      <Select
        options={options}
        onChange={onChangeMock}
      />,
    );
    
    const select = screen.getByRole("combobox");
    
    userEvent.click(select);
    
    const option = screen.getByText("?");
    
    userEvent.click(option, undefined, { skipPointerEventsCheck: true });
    
    expect(onChangeMock).toHaveBeenCalledWith("dog", {
      label: "?",
      value: "dog",
    });
    

    【讨论】:

      【解决方案3】:

      不幸的是,@klugjo 的答案对我来说不适用于 antd-mobile 的 Radio 组件。

      我通过向组件添加额外的onClick 属性解决了这个问题:

      <Radio.RadioItem
          key={key}
          checked={isSelected}
          onChange={onChange}
          onClick={onChange} // needed for rtl
          >
          {label}
      </Radio.RadioItem>
      

      不是一个干净的解决方案,因为它会修改生产代码以进行测试。它可能会错过 TouchEvent 的失败,但这应该是 antd-mobile 库的问题——不是这个测试。

      【讨论】:

        猜你喜欢
        • 2022-11-10
        • 1970-01-01
        • 2021-05-19
        • 2012-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-21
        相关资源
        最近更新 更多