如何测试具有更新背景的组件取决于状态变化

How to test a component with updates background depend on state changes

我有一个组件可以根据状态更改背景图像。我在下面添加了简化代码。

由于我在状态更改时从服务器获取图像,背景图像一直在闪烁。这就是我使用 preloadImage() 函数将它们加载到 DOM 的原因。这个函数解决了这个问题。

问题从测试开始。查看测试文件!

const BackgroundImage = styled`
  ...
  background-image: ${(props) => props.bg && `url(${props.bg})`};
`

const preloadImage = (src, wrapperRef, callback) => {
  const img = new Image();
  img.src = src;
  img.style.display = 'none';
  img.dataset.testid = 'preloaded-image';

  const el = wrapperRef.current;
  el.innerHTML = '';
  el.appendChild(img);

  img.onload = () => typeof callback === 'function' && callback(src);
};    

const Panel = (defaultBG) => {
  const imageCacheRef = useRef();
  const [bg, setBG] = useState(defaultBG);

  useEffect(() => {
    const fetchImage = async () => {
      const imageSrc = await import(`https://fakeimageapi.com/${bg}.png`);
      return preloadImage(imageSrc.default, imageCacheRef, setImage);
    }

    try {
      await fetchImage()
    } catch (error) {
      console.log(error)
    }
  }, [])

  return (
    <div ref={imageCacheRef}>
      <BackgroundImage bg={bg} data-testid="bg" />

      <button onClick={ () => setBG('cat') }>Cat</button>
      <button onClick={ () => setBG('dog') }>Cat</button>
      <button onClick={ () => setBG('rabbit') }>Cat</button>
      <button onClick={ () => setBG('parrot') }>Cat</button>
    </div>
  )
}

这是用测试库编写的测试套件。

import { render, waitFor, screen, act } from '@testing-library/react';

describe('Panel', () => {
  test('Sets background-image correctly', async () => {
    render(<Panel defaultBG="panda" />)
    expect(screen.getByTestId('bg')).toHaveStyle(
      'background-image: url(panda.png);',
    );
  })
})

不幸的是,这个测试失败了。图像加载到 useEffect 后我使用回调的问题(我猜)。我怎样才能以成功的结果结束这个测试?

问题已解决。我在 preloadImage() 中向图像添加了一个测试 ID,并使用 fireEvent 方法加载图像。就是这样!

import { render, waitFor, screen, fireEvent } from '@testing-library/react';

describe('Panel', () => {
  test('Sets background-image correctly', async () => {
    render(<Panel defaultBG="panda" />)

    const image = await waitFor(() => screen.getByTestId('preloaded-image'));
    fireEvent.load(image);

    expect(screen.getByTestId('bg')).toHaveStyle(
      'background-image: url(panda.png);',
    );
  })
})

此外,对 preloadImage() 函数进行了一些重构。

const preloadImage = (src, wrapperRef, callback) => {
  const img = new Image();
  img.src = src;
  img.style.display = 'none';
  img.dataset.testid = 'preloaded-image';

  const el = wrapperRef.current;
  el.innerHTML = '';
  el.appendChild(img);

  if (typeof callback === 'function') {
    img.onload = () => callback(src);
  }
};