使用 react-hooks-testing-library 进行测试时,自定义挂钩的当前结果会更新

The current result of a custom hook is updated when testing using react-hooks-testing-library

我正在测试如下所示的自定义 React Hook。它的作用是获取一张图片的尺寸,然后使用提供的props计算出用户想要的图片尺寸。

import { useEffect, useState } from 'react';
import { Image, LayoutAnimation, useWindowDimensions } from 'react-native';

export type SizeType =
  | {
      width: number;
      height: number;
    }
  | undefined;

export const useImageSize = (imageUri: string, fillWidth?: boolean, fillHeight?: boolean, width?: number, height?: number): SizeType => {
  const [size, setSize] = useState<SizeType>();

  const { width: screenWidth, height: screenHeight } = useWindowDimensions();

  useEffect(() => {
    Image.getSize(
      imageUri,
      (w, h) => {
        LayoutAnimation.easeInEaseOut();

        if (fillWidth) {
          setSize({
            width: screenWidth,
            height: h * (screenWidth / w),
          });

          return;
        }

        if (fillHeight) {
          setSize({
            height: screenHeight,
            width: w * (screenHeight / h),
          });

          return;
        }

        if (width && !height) {
          setSize({
            width,
            height: h * (width / w),
          });

          return;
        }

        if (!width && height) {
          setSize({
            width: w * (height / h),
            height: height,
          });
        }
      },
      () => {
        setSize({ width: 0, height: 0 });
      }
    );
  }, [imageUri, fillWidth, fillHeight, screenWidth, screenHeight, width, height]);

  console.log('size', size);

  return size;
};

这是这个钩子的测试。它模拟了 Image 组件的 getSize 方法,还模拟了 React Native 的 useWindowDimension 钩子。

import * as RN from 'react-native';
import { renderHook, act } from '@testing-library/react-hooks';
import { useImageSize } from '@app/hooks/useImageSize';

describe('useImageSize', () => {
  const getSizeSpyOn = jest.spyOn(RN.Image, 'getSize').mockImplementation(jest.fn());

  afterEach(() => {
    jest.clearAllMocks();
  });

  it('should return the correct size when we want to fill the width of the screen', () => {
    jest.spyOn(RN, 'useWindowDimensions').mockReturnValue({ width: 200, height: 200, fontScale: 1, scale: 1 });
    const { result } = renderHook(() => {
      useImageSize('test_image', true, false)
    });

    expect(getSizeSpyOn).toHaveBeenCalledTimes(1)

    const getSizeArgs = getSizeSpyOn.mock.calls[0]!;
    expect(getSizeArgs[0]).toBe('test_image');

    const success = getSizeArgs[1];

    void act(() => {
      success(100, 50);
    });

    console.log('result.current', result.current)

    expect(result.current).toEqual({
      width: 200,
      height: 100,
    });
  });
    
    console.log('result.current', result.current)

    expect(result.current).toEqual({
      width: 200,
      height: 100,
    });
  });
});

我运行测试后,hook中的console log由undefined变为{width: 200, height: 100 },这是预期值,但是,测试中的console log仍然是不明确的。我认为这种行为表明在测试期间,hook 的行为符合预期,只是由于某种原因,测试中 hook 的当前值在新值可用后没有更新。

有人知道怎么解决吗?

回调必须return钩子的结果,而不仅仅是调用它。更改此行:

    const { result } = renderHook(() => {
      useImageSize('test_image', true, false)
    });

对此:

    const { result } = renderHook(() =>
      useImageSize('test_image', true, false)
    );

请注意,我已删除回调中的 {...}