2017-03-08 84 views
0

我有一個React組件,我從JS組件遷移過來。我正在遷移並檢查測試,並且我有很多失敗,因爲存根似乎不再工作。這裏是我的組件......使用酶淺的渲染與Sinon存根淺渲染

import DeleteButton from "./delete-button.jsx" 
import Dialogs from "../../dialogs"; 
import React from "react"; 
import UrlHelper from "../../helpers/url-helper"; 

export default class ActiveDeleteButton extends React.Component { 

    /** 
    * Creates an instance of ActiveDeleteButton. 
    * 
    * @param {object} props The react props collection. 
    * 
    * @memberOf ActiveDeleteButton 
    */ 
    constructor(props) { 
     super (props); 

     this.handleConfirmDelete = this.handleConfirmDelete.bind(this); 
    } 

    handleConfirmDelete() { 
     $.ajax({ 
      url: this.props.deleteUri, 
      type: `DELETE`, 
      contentType: `application/json; charset=utf-8`, 
      cache: false, 
      success: (xhr) => { 
       let successUri = this.props.successUri; 
       if (!successUri && xhr && xhr.uri) { successUri = xhr.uri; } 
       if (successUri) { UrlHelper.redirect(successUri); } 
      }, 
      error: (xhr, status) => { 
       this.showFailed(); 
      } 
     }); 
    } 

    /** 
    * Shows failure of deletion. 
    * 
    * @memberOf ActiveDeleteButton 
    */ 
    showFailed() { 
     Dialogs.alert(this.props.errorMessage); 
    } 

    /** 
    * Renders the component to the DOM. 
    * 
    * @returns the HTML to render. 
    * 
    * @memberOf ActiveDeleteButton 
    */ 
    render() { 
     return (
      <DeleteButton text = {this.props.text} 
          title = {this.props.title} 
          cancelText = {this.props.cancelText} 
          confirmText = {this.props.confirmText} 
          message = {this.props.message} 
          onConfirmDelete = {this.handleConfirmDelete} /> 
     ); 
    } 
} 

而這裏的測試(冷凝)...

describe("performs a DELETE AJAX request",() => { 

    it ("for specified URLs", sinon.test(function() { 
     let wrapper = shallow(<ActiveDeleteButton text = "Click Me" />); 
     let instance = wrapper.instance(); 
     let ajaxStub = this.stub($, 'ajax'); 
     instance.forceUpdate() 
     wrapper.update() 
     instance.handleConfirmDelete(); 
     console.log(ajaxStub.getCall(0)); 
     let options = ajaxStub.getCall(0).args[0]; 
     assert.equal(options.url, objUt.deleteUri); 
     assert.equal(options.type, "DELETE"); 
    })); 
})); 

我的問題是, 'ajaxStub.getCall(0)' 返回null。這應該返回Ajax調用,以便我可以檢查參數(以前它在我的舊JS組件中使用過)。雖然它(在我看來)顯然應該是這個存根從未被調用。

我在這裏錯過了什麼嗎?

回答

0

這是比其他任何方法都更好的解決方法,所以更好的答案會很棒。最後,我爲此建立了一個解決方法,如下所示:

首先,我創建了一個新的類來處理Ajax請求。

/** 
* An AJAX request wrapper. 
* Usage of this enables testing AJAX calls. 
* 
* @export AjaxRequest 
* @class AjaxRequest 
* @extends {AjaxRequest} 
*/ 
export default class AjaxRequest { 

    /** 
    * Creates an instance of AjaxRequest. 
    * @param {any} { url, type, contentType, cache, data, successCallback, errorCallback } 
    * 
    * @memberOf AjaxRequest 
    */ 
    constructor({ url, type, contentType, cache, data, successCallback, errorCallback }) { 
     Guard.throwIf(url, "url"); 
     let emptyFunc =() => {}; 

     this.url = url; 
     this.type = type.toUpperCase() || "GET"; 
     this.contentType = contentType || "application/json; charset=utf-8"; 
     this.dataType = "json"; 
     this.cache = cache || false; 
     this.data = data ? JSON.stringify(data) : undefined; 
     this.successCallback = successCallback || emptyFunc; 
     this.errorCallback = errorCallback || emptyFunc; 
    } 

    /** 
    * Executes the AJAX request. 
    * 
    * 
    * @memberOf AjaxRequest 
    */ 
    execute() { 
     $.ajax({ 
      url: this.url, 
      type: this.type, 
      contentType: this.contentType, 
      dataType: this.dataType, 
      cache: this.cache, 
      data: this.data, 
      success: this.successCallback, 
      error: this.errorCallback 
     }); 
    } 

    /** 
    * Gets a GET request. 
    * 
    * @static 
    * @param {string} url 
    * @param {function} successCallback 
    * @param {function} errorCallback 
    * @returns an AjaxRequest 
    * 
    * @memberOf AjaxRequest 
    */ 
    static get(url, successCallback, errorCallback) { 
     return new AjaxRequest({ 
      url: url, 
      type: 'GET', 
      successCallback: successCallback, 
      errorCallback: errorCallback 
     }); 
    } 

    /** 
    * Gets a POST request. 
    * 
    * @static 
    * @param {string} url 
    * @param {object} data 
    * @param {function} successCallback 
    * @param {function} errorCallback 
    * @returns an AjaxRequest 
    * 
    * @memberOf AjaxRequest 
    */ 
    static post(url, data, successCallback, errorCallback) { 
     return new AjaxRequest({ 
      url: url, 
      data: data, 
      type: 'POST', 
      successCallback: successCallback, 
      errorCallback: errorCallback 
     }); 
    } 

    /** 
    * Gets a PUT request. 
    * 
    * @static 
    * @param {string} url 
    * @param {object} data 
    * @param {function} successCallback 
    * @param {function} errorCallback 
    * @returns an AjaxRequest 
    * 
    * @memberOf AjaxRequest 
    */ 
    static put(url, data, successCallback, errorCallback) { 
     return new AjaxRequest({ 
      url: url, 
      data: data, 
      type: 'PUT', 
      successCallback: successCallback, 
      errorCallback: errorCallback 
     }); 
    } 

    /** 
    * Gets a DELETE request. 
    * 
    * @static 
    * @param {string} url 
    * @param {function} successCallback 
    * @param {function} errorCallback 
    * @returns an AjaxRequest 
    * 
    * @memberOf AjaxRequest 
    */ 
    static delete(url, successCallback, errorCallback) { 
     return new AjaxRequest({ 
      url: url, 
      type: 'DELETE', 
      successCallback: successCallback, 
      errorCallback: errorCallback 
     }); 
    } 
} 

(我覺得這裏有一定數量的車輪重新發明)。然後,我更新了我的方法調用在我的組件如下...

handleConfirmDelete() { 
    AjaxRequest.delete(this.props.deleteUri, 
     (xhr) => { 
      let successUri = this.props.successUri; 
      if (!successUri && xhr && xhr.uri) { successUri = xhr.uri; } 
      if (successUri) { UrlHelper.redirect(successUri); } 
     }, 
     (xhr, status) => { 
      this.showFailed(); 
     } 
    ).execute(); 
} 

我現在可以測試如下...

describe("performs a DELETE AJAX request",() => { 
    let wrapper = null; 
    let instance = null; 
    let ajaxStub = null; 
    let urlHelperRedirectStub = null; 

    beforeEach(() => { 
     ajaxStub = sinon.stub(AjaxRequest.prototype, 'execute'); 
     urlHelperRedirectStub = sinon.stub(UrlHelper, 'redirect'); 
     wrapper = shallow(<ActiveDeleteButton text = "Click Me" />); 
     instance = wrapper.instance(); 
    }); 

    afterEach(() => { 
     ajaxStub.restore(); 
     urlHelperRedirectStub.restore(); 
    }); 

    it ("for default URLs", sinon.test(function() { 
     instance.handleConfirmDelete(); 
     sinon.assert.called(ajaxStub); 
     let requestInfo = ajaxStub.getCall(0).thisValue;   

     assert.equal(UrlHelper.current.url().split('?')[0], requestInfo.url); 
    })); 

    it ("for specified URLs", sinon.test(function() { 
     wrapper = shallow(<ActiveDeleteButton text = "Click Me" deleteUri="http://localhost/items/12" />); 
     instance = wrapper.instance(); 

     instance.handleConfirmDelete(); 
     sinon.assert.called(ajaxStub); 
     let requestInfo = ajaxStub.getCall(0).thisValue;   

     assert.equal("http://localhost/items/12", requestInfo.url); 
    })); 
})); 

使用存根調用的thisValue財產我可以得到回調並手動執行它們以根據不同的輸入測試它們。考慮到所需的努力,它不是一個理想的解決方案,但它的工作原理和可重用性。

但我覺得必須有更好的方法。