reactjs 如何让测试等待useEffect的更新被首先调用

egdjgwm8  于 2023-08-04  发布在  React
关注(0)|答案(2)|浏览(95)
function App() {
  let [ctr, setCtr] = useState(0);
  useEffect(() => {
    setCtr(1);
  }, []);
              //<-------------------------put a debugger here, only hit once
  return ctr;
}

个字符
目前这个测试失败,因为测试的expect(...)useEffect触发另一个更新之前完成。所以我想在测试中加入一些东西,让它等待另一个更新完成,这样我就可以看到调试器命中两次。我试过:

it("should render 1", () => {
   const el = document.createElement("div");
   ReactDOM.render(<App />, el);

   for (let i = 0; i < 2000; i++) {   // add a long loop so it could have a chance for the `useEffect` trigged update finishes
      // ...
   }
   expect(el.innerHTML).toBe("1"); // this fails!
});


但是我仍然不能控制js运行时,下一个要执行的作业看起来像expect(el.innerHTML).toBe("1")在循环结束后立即执行。那么,我是否可以添加一些类似技巧的东西,以便可以看到调试器命中两次,即让useEffect的更新在expect(...)语句之前执行

3zwtqj6y

3zwtqj6y1#

您的测试不会工作,因为您没有等待重新渲染的发生--在useEffect调用setCtr之后,您的测试中没有任何东西可以触发重新渲染。TBH,我甚至不知道这段代码是否真的会渲染DOM来Assert测试。
我认为一个更好的方法是使用react-testing-library,它为您提供了测试React组件的工具,而无需尝试重新发明轮子。
下面是一个Code Sandbox设置的react-testing-library和一个简单Assert值1在DOM中。您可以在代码沙盒的Tests选项卡中运行测试。下面是相关的代码片段。

// App.tsx
export default function App() {
  const [ctr, setCtr] = useState(0);

  useEffect(() => {
    setCtr(1);
  }, []);

  return (
    <div className="App">
      <Typography variant="h4" component="h1" gutterBottom>
        SO Help: React Testing Library
      </Typography>
      <Typography>{ctr}</Typography>
    </div>
  );
}

个字符
希望这对你有帮助!
更新:解决OP的原始问题
您需要做的就是将您的render Package 在act中,从react-dom/test-utils
要为Assert准备组件,请在act()调用中 Package 呈现组件并执行更新的代码。这使您的测试运行更接近React在浏览器中的工作方式。
行动文件

import { render } from "react-dom";
import { act } from "react-dom/test-utils"
import App from "./App"

it("should render 1", async () => {
  const el = document.createElement("div");
  await act(async () => {
    render(<App />, el);
  })
  
  expect(el.innerHTML).toBe("1"); 
});


也更新了Code Sandbox。结账__tests__/SO.test.tsx

8ulbf1ek

8ulbf1ek2#

您可能需要useLayoutEffect钩子。

function App() {
  let [ctr, setCtr] = useState(0);
  useEffect(() => {
    setCtr(1);
    console.log("Executed.")
  }, []);

  useLayoutEffect(() => {
    console.log("Executed before useEffect called.")
  })

  return ctr;
}

字符串

相关问题