【问题标题】:Unit Testing image.onload and image.onerror Inside React.useEffect() With Jest and Enzyme使用 Jest 和 Enzyme 在 React.useEffect() 中单元测试 image.onload 和 image.onerror
【发布时间】:2020-06-26 01:24:47
【问题描述】:

我有以下组件在完全加载时显示图像:

export default function ImageDisplay(props: OwnPropsInterface): JSX.Element {
    const { src, alt, height, width } = props;

    const [image, setImage] = React.useState<string>('');
    const [showImage, setShowImage] = React.useState<boolean>(false);
    const [imageHeight, setImageHeight] = React.useState<string>('');
    const [imageWidth, setImageWidth] = React.useState<string>('');

    const setImageDimensions = () => {
        setImageHeight(
            typeof height === 'string' ? height : `${convertPixelsToRem(height)}rem`
        );
        setImageWidth(
            typeof width === 'string' ? width : `${convertPixelsToRem(width)}rem`
        );
    };

    const loadImageAsync = async () => {
        const image: HTMLImageElement = new Image();

        image.onload = () => {
            setImage(image.src);
            setShowImage(true);
        };
        image.onerror = (error) => {
            setShowImage(true);
        };

        image.src = src;
    };

    React.useEffect(() => {
        setImageDimensions();
        loadImageAsync();
    }, [src]);

    return (
        <>
            {showImage && (
                <img
                    src={image}
                    alt={alt}
                    style={{ height: imageHeight, width: imageWidth }}
                />
            )}
        </>
    );
}

我需要测试image.onloadimage.onerror 以及组件的后续行为。

目前我编写了以下测试:

    describe('ImageDisplay', () => {
        let useEffect: jest.SpyInstance;
        let wrapper: ShallowWrapper;

        const mockUseEffect = () => {
            useEffect.mockImplementationOnce((f) => f());
        };

        beforeEach(() => {
            useEffect = jest.spyOn(React, 'useEffect').mockImplementation(() => {});

            mockUseEffect();
            mockUseEffect();
            wrapper = shallow(<ImageDisplay {...imageDisplayProps} />);
        });

        describe('on load', () => {
            it('should set image props', () => {
                expect(wrapper.find('img').props()).toEqual({
                    alt: 'test_alt',
                    src: '/test/src',
                    style: {
                        height: '100%',
                        width: '100%',
                    },
                });
            });
        });
    });

expect 调用失败并出现以下错误:

Method “props” is meant to be run on 1 node. 0 found instead.

      115 |         describe('on load', () => {
      116 |             it('should set image props', () => {
    > 117 |                 expect(wrapper.find('img').props()).toEqual({
          |                                            ^
      118 |                     alt: 'test_alt',
      119 |                     src: '/test/src',
      120 |                     style: {

      at ShallowWrapper.single (node_modules/enzyme/src/ShallowWrapper.js:1652:13)
      at ShallowWrapper.props (node_modules/enzyme/src/ShallowWrapper.js:1175:17)
      at Object.<anonymous> (test/unit-tests/components/ImageDisplay.component.test.tsx:117:44)

我知道expect 失败了,因为它立即执行而不等待image.onload 完成,因此它无法找到img 元素。

有没有办法测试图像事件和组件行为?真的很感谢所有的帮助。谢谢。

【问题讨论】:

    标签: reactjs unit-testing promise jestjs enzyme


    【解决方案1】:

    您可以添加一个 waitForComponentToPaint 函数来等待整个组件完全绘制。

    const waitTimeout = (time = 0) => new Promise((resolve) => setTimeout(resolve, time));
    
    const waitForComponentToPaint = async (wrapper, time = 0) => {
      await act(async () => {
        await waitTimeout(time);
        wrapper.update();
      });
    };
    

    然后你可以这样使用:

    it('should set image props', async () => {
        await waitForComponentToPaint(wrapper)
        expect(wrapper.find('img').props()).toEqual({
            alt: 'test_alt',
            src: '/test/src',
            style: {
                height: '100%',
                width: '100%',
            },
        });
    });
    

    【讨论】:

    • 感谢您的回答。但是,我遇到了同样的错误。有没有办法在测试中模拟image.onload
    • 是否需要移除useEffect mock,因为这样,它永远不会将setShowImage设置为true。
    • 不,useEffect 模拟应该在那里,因为它会同步调用setDimension,然后在图像加载或错误时调用setShowImage
    • 有了 mock,useEffect 的默认行为将被覆盖,两个函数都不会被调用。
    猜你喜欢
    • 2020-08-27
    • 2019-05-06
    • 2018-12-16
    • 1970-01-01
    • 2019-07-28
    • 2018-09-08
    • 2017-11-26
    • 1970-01-01
    • 2021-06-24
    相关资源
    最近更新 更多