2017-06-09 108 views
1

我已经创建了一个React组件来加载图像并确定图像是否成功加载。如何使用Jest来测试img.onerror

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 +酶来测试图像加载失败。

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仍会以某种方式呈现图像。有谁知道如何在你可以强迫笑话失败的图像加载?

回答

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(); 
    }); 
+0

我认为你有一些东西,但有嘲笑document.createElement的问题。我的图像函数还根据参数创建了跨度和div,所以返回null会导致测试崩溃。现在我正在测试以查看是否可以添加任何属性。它不工作。这是我得到的:https://gist.github.com/mrbinky3000/567b532928f456ee74e55ebe959c66ec – mrbinky3000

+1

我放弃了。我只是决定使用wrapper.instance(),然后直接调用instance.image.onerror()。我想到我过度测试了。我必须相信,HTMLImageElement会在发生图像错误时触发错误。如果没有,那么Web浏览器的源代码有一个巨大的错误。可能性:无。所以我只是手动启动了错误来模拟错误。案件结案。谢谢,不过。 – mrbinky3000

0

由于幕后,document.createElement('img')相当于new Image(),我们可以嘲笑jsdom(由玩笑使用)执行Image的一部分来实现你要什么。

(为简单起见,我已经改名为您的组件ImageComponent

describe('Callbacks',() => { 
    const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC'; 
    const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC'; 

    let originalImageSrcProto; 
    beforeAll(() => { 
    // Keep a copy of the original Image.prototype.src 
    // in order to restore it after these tests are done 
    originalImageSrcProto = Object.getOwnPropertyDescriptor(
     global.Image.prototype, 
     'src' 
    ); 

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

    afterAll(() => { 
    // Restore the original Image.prototype.src 
    Object.defineProperty(global.Image.prototype, 'src', originalImageSrcProto); 
    }); 

    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不会被调用,因为它是在浏览器中在这个jsdom issue解释。另一个会影响您所有测试的修复程序将在同一issue thread中提供。

相关问题