2017-03-08 70 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财产我可以得到回调并手动执行它们以根据不同的输入测试它们。考虑到所需的努力,它不是一个理想的解决方案,但它的工作原理和可重用性。

但我觉得必须有更好的方法。