首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >尽管已被包装,但在act错误中未被包装

尽管已被包装,但在act错误中未被包装
EN

Stack Overflow用户
提问于 2021-06-07 13:39:25
回答 1查看 165关注 0票数 1

我正在测试我的React组件,以验证setTimeout延迟的回调函数行为,但尽管我的假计时器已经在act块中触发,我还是收到了下面的错误。

错误如下:

代码语言:javascript
运行
复制
C:\dev\node\node.exe --require "C:\dev\JetBrains\IntelliJ IDEA 2021.1.1\plugins\JavaScriptLanguage\helpers\jest-intellij\lib\jest-intellij-stdin-fix.js" C:\Users\Reph0\Desktop\my-app\node_modules\react-scripts\bin\react-scripts.js test --colors --reporters "C:\dev\JetBrains\IntelliJ IDEA 2021.1.1\plugins\JavaScriptLanguage\helpers\jest-intellij\lib\jest-intellij-reporter.js" --verbose "--testNamePattern=^Timeout component should randomize value until more than 0\.9$" --runTestsByPath C:/Users/Reph0/Desktop/my-app/src/TimeoutComponent.spec.tsx
  console.error
    Warning: An update to TimeoutComponent inside a test was not wrapped in act(...).
    
    When testing, code that causes React state updates should be wrapped into act(...):
    
    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */
    
    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
        at TimeoutComponent (C:\Users\Reph0\Desktop\my-app\src\TimeoutComponent.tsx:8:35)

组件

代码语言:javascript
运行
复制
import * as React from "react";

interface Props {
  getValue: () => Promise<number>;
}

const TimeoutComponent: React.FC<Props> = (props) => {
  const [value, setValue] = React.useState<number>(0);

  React.useEffect(() => {
    if (value < 0.9) {
      const timeoutId = setTimeout(() => props.getValue().then(setValue), 300);
      return () => {
        clearTimeout(timeoutId);
      };
    }
  }, [value]);

  return (
    <>
      <p>
        Value: <span id="value">{value}</span>
      </p>
    </>
  );
};

export default TimeoutComponent;

测试

代码语言:javascript
运行
复制
import { render } from "@testing-library/react";
import React from "react";
import { act } from "react-dom/test-utils";
import TimeoutComponent from "./TimeoutComponent";

const getValue = jest.fn();

describe("Timeout component", () => {
  beforeEach(() => {
    jest.resetAllMocks();
    jest.useFakeTimers();
  });

  afterEach(() => {
    jest.useRealTimers();
  });

  it("should randomize value until more than 0.9", () => {
    getValue
      .mockResolvedValueOnce(0.1)
      .mockResolvedValueOnce(0.2)
      .mockResolvedValueOnce(0.3)
      .mockResolvedValueOnce(0.4)
      .mockResolvedValueOnce(0.7)
      .mockResolvedValueOnce(0.92)
      .mockResolvedValueOnce(0.6);

    render(<TimeoutComponent getValue={getValue} />);

    act(() => {
      jest.runAllTimers();
    });

    expect(getValue).toBeCalledTimes(6);
  });
});

这是我的package.json

代码语言:javascript
运行
复制
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "@types/jest": "^26.0.15",
    "@types/node": "^12.0.0",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    "typescript": "^4.1.2",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

这是我的codesandbox的link,但似乎jest.runAllTimers()在那里不能很好地工作。

如果有人能帮上忙,我会很感激的:)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-08 03:57:53

发生错误的原因是测试过程中状态发生了变化。我们可以等待状态改变,然后进行断言。

对于您的情况,我们可以等待不包含0.6的内容(0.92之后状态不会改变),并确定getValue之前是否调用过6 times

代码语言:javascript
运行
复制
it("should randomize value until more than 0.9", async () => {
    getValue
      .mockResolvedValueOnce(0.1)
      .mockResolvedValueOnce(0.2)
      .mockResolvedValueOnce(0.3)
      .mockResolvedValueOnce(0.4)
      .mockResolvedValueOnce(0.7)
      .mockResolvedValueOnce(0.92)
      .mockResolvedValueOnce(0.6);

    const result = render(<TimeoutComponent getValue={getValue} />);
    try {
      jest.runAllTimers();

      // wait until the content contains 0.6 
      // will timeout as 0.6 will never be displayed; and 
      // will go to catch and finally block
      await waitFor(() => {
        result.getByText(/0.6/)
      })
    } catch (e) {
      console.log("timeout for waiting for 0.6 appear: ", e.message)
    } finally {
      // get the latest value in the content before timeout error, must be 0.92
      expect(result.container.getElementsByTagName("span")[0].innerHTML).toEqual("0.92");

      // get the number of time getValue has been called before timeout error, must be 6
      expect(getValue).toBeCalledTimes(6);
    }
});

waitFor参考文献

https://testing-library.com/docs/guide-disappearance/#waiting-for-appearance

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67866411

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档