1

我正在测试如下所示的自定义 React Hook。它的功能是获取图像的大小,然后使用提供的道具来计算用户想要的图像大小。

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

运行测试后,钩子中的控制台日志从 undefined 变为 { width: 200, height: 100 } 这是预期值,但是,测试中的控制台日志仍然未定义。我认为这种行为表明在测试期间,钩子的行为符合预期,只是由于某种原因,测试中钩子的当前值在新值可用后没有更新。

有谁知道如何解决这个问题?

在此处输入图像描述

4

1 回答 1

2

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

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

对此:

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

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

于 2021-09-05T23:20:59.690 回答