2017-06-09 152 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中提供。

相關問題