【问题标题】:React/Jest Select element onChange values not updatingReact/Jest Select 元素 onChange 值未更新
【发布时间】:2022-02-14 09:24:23
【问题描述】:

我有如下代码测试Select元素改变后的值:

it("changes value after selecting another field", () => {
  doSetupWork();
  let field = screen.getByLabelText("MySelectField");
  expect(field).toHaveValue("");

  fireEvent.change(field, { target: { value: "1" } });

  // Insert one of two options from below
});

但是,当我在底部插入以下内容时,它不起作用:

field = screen.getByLabelText("MySelectField");
expect(field).toHaveValue("1");

并给出以下错误信息:

Expected the element to have value: 1
Received:

但是,当我将它包装在 setTimeout 中,延迟只有 1 毫秒时,它确实有效:

setTimeout(() => {
  field = screen.getByLabelText("MySelectField");
  expect(field).toHaveValue("1");
}, 1);

感觉在没有setTimeout 的情况下应该有一种更优雅的写法。有什么建议吗?

【问题讨论】:

    标签: javascript reactjs typescript jestjs


    【解决方案1】:

    您可以尝试使用waitFor 而不是setTimeout

    import {waitFor} from '@testing-library/react'
    
    ...
    
    await waitFor(() => screen.getByLabelText("MySelectField").toHaveValue("1"))
    

    【讨论】:

      【解决方案2】:

      您看到的是,您的应用需要有限的时间才能对发生的更改做出反应(请原谅双关语) - 具体来说,它需要重新渲染。

      是的,有一个更好的方法 - 来自testing-library/reactthe waitFor function

      import { screen, waitFor } from '@testing-library/react';
      
      ...
      
        it("changes value after selecting another field", async () => {
      
          ...
      
          fireEvent.change(field, { target: { value: "1" } });
      
          await waitFor(async () => {
            field = screen.getByLabelText("MySelectField");
            expect(field).toHaveValue("1");
          });
        }
      

      请注意,整个测试主体(即在测试名称之后)必须声明为 async,以便能够 await 新的 waitFor 块。

      【讨论】:

      • 感谢您的回复。不幸的是,这会导致同样的错误:/
      【解决方案3】:

      当我使用 react-testing-library 时,当我有要与之交互的事件时,我倾向于使用渲染。 例如:

      在我的 App.js 中,我在返回方法上有这段代码

        const handleChoice = () => {};
      
        const attributes = [
          { label: "One", value: "1" },
          { label: "Two", value: "2" },
          { label: "Three", value: "3" }
        ];
      
        return (
          <div className="App">
            <h1>Hello CodeSandbox</h1>
      
            <select onChange={handleChoice} data-testid="MySelectField">
              <option value="0">Zero</option>
              {attributes.map((item) => {
                return (
                  <option key={item.value} value={item.value}>
                    {item.label}
                  </option>
                );
              })}
            </select>
          </div>
        );
      

      那么我的测试将是这样的:

      import { fireEvent, render } from "@testing-library/react";
      import "@testing-library/jest-dom";
          
      import App from "./App";
          
      it("changes value after selecting another field", () => {
        const { getByTestId } = render(<App />);
        let field = getByTestId("MySelectField");
        expect(field).toHaveValue("0");
      
        fireEvent.change(field, { target: { value: "1" } });
        expect(field.value).toBe("1");
      
        fireEvent.change(field, { target: { value: "3" } });
        expect(field.value).toBe("3");
        // Insert one of two options from below
      });
      

      看看这个沙盒,看看它的工作情况。 https://codesandbox.io/s/ecstatic-https-hzi5n?file=/src/App.spec.js

      【讨论】:

      • 感谢您的回复,但您的回答是关于输入字段,而不是选择字段。另外,当我对渲染方法使用对象解构时,eslint 会向我抛出错误以避免这样做。
      • 不客气。我不确定你有什么错误。但是针对选择字段进行了更新。请检查 eslint 的破坏规则。它在 Javascript 上非常标准。让我知道是否可以提供帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-16
      • 2020-04-30
      • 2018-02-18
      • 2019-04-06
      相关资源
      最近更新 更多