sourcetip

테스트 시 리액트 상태 갱신의 원인이 되는 코드를 행동으로 정리해야 합니다.

fileupload 2023. 2. 13. 20:39
반응형

테스트 시 리액트 상태 갱신의 원인이 되는 코드를 행동으로 정리해야 합니다.

다음 테스트가 있습니다.

import {
  render,
  cleanup,
  waitForElement
} from '@testing-library/react'

const TestApp = () => {
  const { loading, data, error } = useFetch<Person>('https://example.com', { onMount: true });

  return (
    <>
      {loading && <div data-testid="loading">loading...</div>}
      {error && <div data-testid="error">{error.message}</div>}
      {data && 
        <div>
          <div data-testid="person-name">{data.name}</div>
          <div data-testid="person-age">{data.age}</div>
        </div>
      }
    </>
  );
};

  describe("useFetch", () => {
    const renderComponent = () => render(<TestApp/>);

    it('should be initially loading', () => {
      const { getByTestId } = renderComponent();

      expect(getByTestId('loading')).toBeDefined();
    })
  });

테스트는 성공했지만 다음 경고가 표시됩니다.

경고:테스트 내의 TestApp 업데이트는 액트(...)로 포장되지 않았습니다.

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
    in TestApp

console.error node_modules/react-dom/cjs/react-dom.development.js:506 경고:테스트 내의 TestApp 업데이트는 액트(...)로 포장되지 않았습니다.

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
    in TestApp

열쇠는 하는 것이다await act그런 다음 사용async화살표 기능

await act( async () => render(<TestApp/>));

출처:

https://stackoverflow.com/a/59839513/3850405

'wait wait For()' 내에서 어설션을 시도합니다.이것에 대해서는, it() 함수가 비동기일 필요가 있습니다.

it('should be initially loading', async () => {
  const { getByTestId } = renderComponent();

  await waitFor(() => {
    expect(getByTestId('loading')).toBeDefined();
  });
});

침착하고 행복한 코딩

getBy* 또는 queryBy*가 아닌 비동기 쿼리(findBy*)를 사용하여 해결된 동일한 문제가 발생하고 있습니다.

expect(await screen.findByText(/textonscreen/i)).toBeInTheDocument(); 

비동기 쿼리는 요소 대신 Promise를 반환합니다.이 경우 지정된 쿼리와 일치하는 요소가 발견되면 해결됩니다.요소를 찾을 수 없거나 기본 타임아웃 1000ms 후에 여러 요소가 발견되면 약속은 거부됩니다.여러 요소를 찾아야 할 경우 findAllBy를 사용합니다.

https://testing-library.com/docs/dom-testing-library/api-async/

하지만 아시다시피 화면에 표시되지 않으면 제대로 작동하지 않습니다.그러니까queryBy*그에 따라 테스트 케이스를 업데이트해야 할 수도 있습니다.

[주의: 사용자 이벤트는 없습니다.단순한 렌더링만 하면 find By가 동작합니다.그렇지 않으면 사용자 이벤트를 활성화해야 합니다]

wait inside act를 사용해 보세요.

import { act } from 'react-dom/test-utils';
await act(async () => {
            wrapper = mount(Commponent);
            wrapper.find('button').simulate('click');
        });
    test('handles server ok', async () => {
    render(
      <MemoryRouter>
        <Login />
      </MemoryRouter>
    )

    await waitFor(() => fireEvent.click(screen.getByRole('register')))

    let domInfo
    await waitFor(() => (domInfo = screen.getByRole('infoOk')))

    // expect(domInfo).toHaveTextContent('登陆成功')
  })

난 이런 식으로 문제를 풀었으니 너도 한번 해봐

액트 에러의 스택은 보이지 않지만, 로딩이 종료되었을 때 TestApp 상태가 변경되어 테스트 종료 후에 다시 렌더링되는 것이 원인이라고 생각합니다.따라서 테스트가 끝날 때까지 로딩이 사라지기를 기다리는 것이 이 문제를 해결할 수 있을 것입니다.

describe("useFetch", () => {
  const renderComponent = () => render(<TestApp/>);

  it('should be initially loading', async () => {
    const { getByTestId } = renderComponent();

    expect(getByTestId('loading')).toBeDefined();
    await waitForElementToBeRemoved(() => queryByTestId('loading'));
  });
});

리액트 테스트 라이브러리로 리액트 앱:

여러 가지 시도를 해봤는데, 제게 효과가 있었던 것은 시험이 끝난 후 아무 일도 일어나지 않도록 화재 발생 후 무언가를 기다리는 것이었습니다.

제 경우 입력 필드가 집중되면 열리는 달력입니다.포커스 이벤트를 실행하고 결과 포커스 이벤트가 발생했는지 확인하고 테스트를 마쳤습니다.아마도 제 테스트가 끝난 후 시스템이 끝나기 전에 캘린더가 열려서 경고가 발생한 것 같습니다.끝나기 전에 달력이 나타나기를 기다린 것이 효과가 있었다.

fireEvent.focus(inputElement);

await waitFor(async () => {
  expect(await screen.findByText('December 2022')).not.toBeNull();
});
expect(onFocusJestFunction).toHaveBeenCalledTimes(1);
// End

이게 도움이 됐으면 좋겠는데, 반나절이나 이 일에 소비했어.

은 단지 에 있는 이다.react-testing-library (RTL) 됩니다.actRTL은 이미 백그라운드에서 사용되고 있기 때문에 RTL에서 사용할 수 있습니다.「 」를하고 있지 않은 경우RTL , 을.act

import {act} from "react-dom/test-utils"
test('',{
    act(()=>{
        render(<TestApp/>)
    })
})

구성 요소가 데이터 가져오기를 수행할 때 이 경고가 표시됩니다.에 내부 act() 및 가 먼저 , 다시 업데이트해야 합니다.act(),그러면요소를최신상태.

이 함수 RTL을 실행하는 입니다.findBy*

test("test", async () => {
  render(
    <MemoryRouter>
      <TestApp />
    </MemoryRouter>
  );

  await screen.findByRole("button");
});

언급URL : https://stackoverflow.com/questions/56722139/when-testing-code-that-causes-react-state-updates-should-be-wrapped-into-act

반응형