我应该在react-testing-library中手动调用unmount renderHook吗?

问题描述 投票:0回答:1

React 测试库文档说不需要在每次测试后进行清理,但是对于

renderHook
文档,如果在测试结束后调用 unmount 则不会说什么。

那么在使用

unmount
的测试中是否有必要调用
renderHook
呢?

reactjs jestjs react-testing-library
1个回答
0
投票

使用

cleanup
时不需要调用 RTL
renderHook()
函数,从源码中我们知道它底层是通过 render
 来调用 
<TestComponent/>
 函数的。所以

如果您使用的测试框架支持

cleanup

 全局(如 mocha、Jest 和 Jasmine),则默认情况下会在每次测试后自动调用 
afterEach

function renderHook(renderCallback, options = {}) {
  const {initialProps, ...renderOptions} = options

  if (renderOptions.legacyRoot && typeof ReactDOM.render !== 'function') {
    const error = new Error(
      '`legacyRoot: true` is not supported in this version of React. ' +
        'If your app runs React 19 or later, you should remove this flag. ' +
        'If your app runs React 18 or earlier, visit https://react.dev/blog/2022/03/08/react-18-upgrade-guide for upgrade instructions.',
    )
    Error.captureStackTrace(error, renderHook)
    throw error
  }

  const result = React.createRef()

  function TestComponent({renderCallbackProps}) {
    const pendingResult = renderCallback(renderCallbackProps)

    React.useEffect(() => {
      result.current = pendingResult
    })

    return null
  }

  const {rerender: baseRerender, unmount} = render(
    <TestComponent renderCallbackProps={initialProps} />,
    renderOptions,
  )

  function rerender(rerenderCallbackProps) {
    return baseRerender(
      <TestComponent renderCallbackProps={rerenderCallbackProps} />,
    )
  }

  return {result, rerender, unmount}
}

如果你想测试

cleanup
钩子的
useEffect()
函数中的代码逻辑,你应该调用
ummount()
函数。请看下面的例子:

import { renderHook, screen } from '@testing-library/react';
import React, { useEffect } from 'react';

describe('78435539', () => {
  test('should pass', () => {
    const Context = React.createContext('default');
    function Wrapper({ children }) {
      return (
        <Context.Provider value="provided">
          <h1>Provider 1</h1>
          {children}
        </Context.Provider>
      );
    }
    const { result } = renderHook(() => React.useContext(Context), { wrapper: Wrapper });
    expect(result.current).toEqual('provided');
    screen.debug();
  });

  test('should pass 2', () => {
    const Context = React.createContext('default');
    function Wrapper({ children }) {
      return (
        <Context.Provider value="provided">
          <h1>Provider 2</h1>
          {children}
        </Context.Provider>
      );
    }
    const { result } = renderHook(() => React.useContext(Context), { wrapper: Wrapper });
    expect(result.current).toEqual('provided');
    screen.debug();
  });

  test('should pass 3', () => {
    let count = 0;
    const { unmount } = renderHook(() => {
      useEffect(() => {
        const onClick = () => {
          count++;
        };
        document.body.addEventListener('click', onClick);
        return () => {
          document.body.removeEventListener('click', onClick);
        };
      }, []);
    });

    document.body.click();
    expect(count).toBe(1);
    unmount();
    document.body.click();
    expect(count).toBe(1);
  });
});

测试结果:

> jest -o

  console.log
    <body>
      <div>
        <h1>
          Provider 1
        </h1>
      </div>
    </body>

      at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:87:13)

  console.log
    <body>
      <div>
        <h1>
          Provider 2
        </h1>
      </div>
    </body>

      at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:87:13)

 PASS  stackoverflow/78435539/index.test.tsx
  78435539
    √ should pass (32 ms)
    √ should pass 2 (5 ms)
    √ should pass 3 (2 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        1.044 s
Ran all test suites related to changed files.
© www.soinside.com 2019 - 2024. All rights reserved.