簡體   English   中英

React 測試庫 - 未包含在 act() 錯誤中

[英]React Testing Library - not wrapped in act() error

我在使用 react-testing-library 測試切換組件時遇到問題。

單擊圖標(包裝在按鈕組件中)時,我期望 go 的文本從“已驗證”到“未驗證”。 此外,在有 state 更新的地方調用 function。

但是,單擊事件似乎不起作用,並且出現以下錯誤:

> 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)

在我的代碼中,我有一個像這樣的 function:

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();
  });

第一個期望通過,因為 function 調用被調用一次,但是我從上面遇到了 act() 錯誤,並且還有一個失敗,因為文本似乎沒有從unverified verified

我知道通常行為錯誤是異步/等待調用發生的問題,但我認為 findByText 應該等待,而且似乎還有另一個我沒有在這里遇到的問題。 有關如何調試/改進此測試的任何幫助?

當您單擊“ Remove Approval按鈕時,會在此處調用 3 個異步函數。

首先,您將加載狀態設置為 true,因此它將加載,然后調用異步函數 (myFunctionCalls),最后,加載狀態設置為 false 后,加載器將消失。

為了解決它,我們必須先等待loading出現,然后調用myFunctionCalls,然后再等待loading消失。

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(() => jest.advanceTimersByTime(500)); 將時間延長至 500 毫秒。 當時間達到 500ms 時,異步功能就會得到解決。

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();
});


嘗試這個:

     // [...]

     fireEvent.click(button);

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

     // End of test
        

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM