【问题标题】:React Testing Library - not wrapped in act() errorReact 测试库 - 未包含在 act() 错误中
【发布时间】:2021-09-12 12:07:53
【问题描述】:

我在使用 react-testing-library 测试切换组件时遇到问题。

单击图标(包装在按钮组件中)时,我希望文本从“已验证”变为“未验证”。此外,在有状态更新的地方调用一个函数。

但是,点击事件似乎不起作用,我收到以下错误:

> jest "MyFile.spec.tsx"

 FAIL  src/my/path/__tests__/MyFile.spec.tsx
  component MyFile
    ✓ renders when opened (94 ms)
    ✓ renders with items (33 ms)
    ✕ toggles verification status on click of icon button (100 ms)


  console.error
    Warning: An update to MyFile 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 MyFile (/path/to/myfile.tsx:44:3)
        at ThemeProvider (/users/node_modules/@material-ui/styles/ThemeProvider/ThemeProvider.js:48:24)

      123 |       );
      124 |     } finally {
    > 125 |       setIsLoading(false);
          |       ^
      126 |     }
      127 |   };
      128 |

      at printWarning (node_modules/react-dom/cjs/react-dom.development.js:67:30)
      at error (node_modules/react-dom/cjs/react-dom.development.js:43:5)
      at warnIfNotCurrentlyActingUpdatesInDEV (node_modules/react-dom/cjs/react-dom.development.js:24064:9)
      at dispatchAction (node_modules/react-dom/cjs/react-dom.development.js:16135:9)
      at handleConfirm (src/modules/myfile.tsx:125:7)

在我的代码中,我有一个这样的函数:

const handleSubmit = async() => {
  if(isLoading) {
    return;
  }

  try {
    setIsLoading(true);
    await myFunctionCalls();
  } catch (error){
    console.log(error)
  } finally {
    setIsLoading(false)
  }
};

我的测试看起来与此类似:

test('toggles verification status on click of icon button', async () => {
    renderWithTheme(
    <MyComponent/>,
   );

  const updateVerificationMock = jest.fn();
  const callFunctionWithSerializedPayloadMock =
    callFunctionWithSerializedPayload as jest.Mock;
  callFunctionWithSerializedPayloadMock.mockImplementation(
    () => updateVerificationMock,
  );

    const button = screen.getByRole('button', {name: 'Remove approval'});
    fireEvent.click(button);

    await act(async () => {
      expect(myFunctionCalls).toHaveBeenCalledTimes(1);
    });
    expect(await screen.findByText('unverified')).toBeInTheDocument();
  });

当函数调用被调用一次时,第一个期望通过,但是我从上面遇到了 act() 错误,并且还有一个失败,因为文本似乎没有从 verified 切换到 unverified

我知道通常行为错误是异步/等待调用发生的问题,但我认为 findByText 应该等待,而且似乎还有另一个我没有在这里发现的问题。有关如何调试/改进此测试的任何帮助?

【问题讨论】:

    标签: javascript reactjs async-await jestjs react-testing-library


    【解决方案1】:

    当您单击Remove Approval 按钮时,此处会调用 3 个异步函数。

    首先,您将加载状态设置为true,因此它将加载然后调用异步函数(myFunctionCalls),最后加载状态设置为false后加载器将消失。

    为了解决它,我们必须先等待加载出现,然后调用myFunctionCalls,然后再等待加载消失。

    test("toggles verification status on click of icon button", async () => {
      renderWithTheme(<MyComponent />);
    
      const updateVerificationMock = jest.fn();
      const callFunctionWithSerializedPayloadMock =
        callFunctionWithSerializedPayload as jest.Mock;
      callFunctionWithSerializedPayloadMock.mockImplementation(
        () => updateVerificationMock
      );
    
      const button = screen.getByRole("button", { name: "Remove approval" });
      fireEvent.click(button);
    
      expect(await screen.findByText(/loading/i)).toBeInTheDocument();
    
      await waitFor(() => {
        expect(myFunctionCalls).toHaveBeenCalledTimes(1);
      });
    
      await waitForTheElementToBeRemoved(() => {
        expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
      });
    
    
      expect(await screen.findByText("unverified")).toBeInTheDocument();
    });
    
    

    如果您没有加载文本,则可以使用act(() =&gt; jest.advanceTimersByTime(500)); 将时间延长至 500 毫秒。当时间达到 500ms 时,async 函数就已经解决了。

    beforeEach(() => {
      jest.useFakeTimers();
    })
    
    afterEach(() => {
      jest.runAllPendingTimers();
      jest.useRealTimers()
    })
    
    test("toggles verification status on click of icon button", async () => {
      renderWithTheme(<MyComponent />);
    
      const updateVerificationMock = jest.fn();
      const callFunctionWithSerializedPayloadMock =
        callFunctionWithSerializedPayload as jest.Mock;
      callFunctionWithSerializedPayloadMock.mockImplementation(
        () => updateVerificationMock
      );
    
      const button = screen.getByRole("button", { name: "Remove approval" });
      fireEvent.click(button);
    
      act(() => jest.advanceTimersByTime(500));
    
      await waitFor(() => {
        expect(myFunctionCalls).toHaveBeenCalledTimes(1);
      });
    
      act(() => jest.advanceTimersByTime(500));
    
      expect(await screen.findByText("unverified")).toBeInTheDocument();
    });
    
    
    

    【讨论】:

      猜你喜欢
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 1970-01-01
      • 2019-08-06
      • 2020-08-29
      • 1970-01-01
      相关资源
      最近更新 更多