首页 文章

你如何使用Jest来测试img.onerror

提问于
浏览
2

我创建了一个React组件,用于加载图像并确定图像是否成功加载 .

import React from 'react';
import PropTypes from 'prop-types';
import { LOADING, SUCCESS, ERROR } from '../helpers';

class Image extends React.Component {
  static propTypes = {
    onError: PropTypes.func,
    onLoad: PropTypes.func,
    src: PropTypes.string.isRequired,
  }

  static defaultProps = {
    onError: null,
    onLoad: null,
  }

  constructor(props) {
    super(props);
    this.state = { imageStatus: LOADING };
    this.initImage();
  }

  componentDidMount() {
    this.image.onload = this.handleImageLoad;
    this.image.onerror = this.handleImageError;
    this.image.src = this.props.src;
  }

  initImage() {
    this.image = document.createElement('img');
    this.handleImageLoad = this.handleImageLoad.bind(this);
    this.handleImageError = this.handleImageError.bind(this);
  }

  handleImageLoad(ev) {
    this.setState({ imageStatus: SUCCESS });
    if (this.props.onLoad) this.props.onLoad(ev);
  }

  handleImageError(ev) {
    this.setState({ imageStatus: ERROR });
    if (this.props.onError) this.props.onError(ev);
  }

  render() {
    switch (this.state.imageStatus) {
      case LOADING:
        return this.renderLoading();
      case SUCCESS:
        return this.renderSuccess();
      case ERROR:
        return this.renderError();
      default:
        throw new Error('unknown value for this.state.imageStatus');
    }
  }
}

export default Image;

我正在尝试使用Jest Enzyme创建一个测试,以测试图像何时无法加载 .

it('should call any passed in onError after an image load error', () => {
    const onError = jest.fn();
    mount(<Image {...props} src="crap.junk"} onError={onError} />);
    expect(onError).toHaveBeenCalled();
  });

无论我做什么,Jest总能找到一种成功渲染图像的方法 . 即使将src设置为false仍会以某种方式呈现图像 . 有谁知道你怎么能强迫玩笑失败图像负载?

2 回答

  • 5

    从幕后, document.createElement('img') 相当于 new Image() ,我们可以模拟部分jsdom(由Jest使用)实现 Image 来实现你的目标 .

    (为简单起见's sake, I'已将您的组件重命名为 ImageComponent

    describe('Callbacks', () => {
      const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC';
      const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC';
    
      beforeAll(() => {
        // Mocking Image.prototype.src to call the onload or onerror
        // callbacks depending on the src passed to it
        Object.defineProperty(global.Image.prototype, 'src', {
          // Define the property setter
          set(src) {
            if (src === LOAD_FAILURE_SRC) {
              // Call with setTimeout to simulate async loading
              setTimeout(() => this.onerror(new Error('mocked error')));
            } else if (src === LOAD_SUCCESS_SRC) {
              setTimeout(() => this.onload());
            }
          },
        });
      });
    
      it('Calls onError when passed bad src', done => {
        const onError = ev => {
          expect(ev).toBeInstanceOf(Error);
    
          // Indicate to Jest that the test has finished
          done();
        };
    
        mount(<ImageComponent onError={onError} src={LOAD_FAILURE_SRC} />);
      });
    });
    

    onerror / onload 永远不会被调用,因为它将在浏览器中被解释 . 另一个会影响所有测试的修复程序在同一个issue thread中提供 .

  • 0

    你可以模拟 document.createElement

    it('should call any passed in onError after an image load error', () => {
        const img = {}
        global.document.createElement = (type) => type === 'img' ? img : null
        const onError = jest.fn();
        mount(<Image {...props} src="crap.junk"} onError={onError} />);
        img.onload()
        expect(onError).toHaveBeenCalled();
      });
    

相关问题