2011-03-17 27 views
53

我單元測試一些JavaScript與茉莉花和希望窺探(模擬)的由jQuery選擇訪問的DOM的元件上。刺探jQuery選擇在茉莉

我的規格是:

it("should be able to mock DOM call", function() { 

    spyOn($("#Something"), 'val').andReturn("bar"); 

    result = $("#Something").val(); 

    expect(result).toEqual("bar"); 

}); 

在我specrunner.html我:

<input type="hidden" id="Something" value="foo" /> 

不幸的是,規範失敗:

應該能夠嘲笑DOM傳喚預期'foo'等於'bar'。

回答

86

此行是錯誤的:

spyOn($("#Something"), 'val').andReturn("bar"); 

茉莉花spyOn函數需要兩個參數。第一個是現有的對象。第二個是作爲字符串的函數名稱。您正確地將函數名稱作爲字符串(「val」)傳遞,但是您沒有傳入現有對象作爲第一個參數。

$("#Something") 

...不是現有的對象。它是jQuery選擇器的結果(返回值)。更具體地說,它將返回一個代表匹配節點的jQuery對象 - 有點像結果數組。

$ 

...是一個現有的對象。

$.fn 

...是現有的對象。

$("#Something") 

...是不是現有對象 - 這是jQuery選擇的結果。

這將工作:

it("should be able to mock DOM call", function() { 
    //spyOn($.fn, "val").andReturn("bar"); //pre-jasmine 2.0 syntax 
    spyOn($.fn, "val").and.returnValue("bar"); //Jasmine 2.0 Syntax 
    var result = $("#Something").val(); 
    expect(result).toEqual("bar"); 
}); 
+4

我同樣困惑。 'var $ foo = $('#foo')'。現在'$ foo'是一個現有的對象:它是一個jQuery對象。它有一個'val()'方法;它只是通過查找它的原型鏈來獲得它'jQuery.fn'。那麼爲什麼我不能'spyOn($ foo,「val」)'?爲什麼Jasmine的間諜要求我指定方法的定義?我的用例是我想檢查一下,比如說'hide()',不僅僅是一般的調用,而且還有** $ foo **。所以'spyOn(jQuery.fn,「hide」)'不會給我我想要的信息,但是'spyOn($ foo,「hide」)'會 - 如果它工作的話。 – 2011-10-27 21:15:27

+0

@NathanLong是對的 - 這是錯誤的答案。我不知道爲什麼它被upvoted如此之高.. – badunk 2012-07-06 10:11:59

+13

@NathanLong的問題是,每次你執行一個jQuery選擇的時候,你會得到一個全新的對象,所以你設置在窺探的人會比不同你在被測代碼裏面得到的那個。因此Alex告訴你要爲所有jquery對象監視原型($ .fn)。 – 2012-08-29 19:51:44

16

問題是,兩次調用$返回兩個不同的jQuery包裝節點。

這應該工作:

it("should be able to mock DOM call", function(){ 

    // var node = $("Something"); 
    // spyOn(node, 'val').andReturn('bar'); 

    // expect(node.val()).toEqual('bar'); 
    var node = $("Something"); 
    spyOn(node, 'val').and.returnValue('bar'); 

    expect(node.val()).toEqual('bar'); 
}); 

下一次,幫助茉莉花郵件列表上越來越普遍:[email protected]

+6

這是你的回答是,jQuery即使其相同的選擇返回不同的對象爲每個查詢。您需要引用相同的對象才能正確監視它。否則,你正在窺視一個,並執行另一個。 – badunk 2012-07-06 10:10:29

+1

試試這個期望:expect(node.val).toHaveBeenCalled() – 2015-11-04 20:31:08

27

好像我發現這不是基於你的代碼很好的解決

it "should open past statuses", -> 
     # We can't use $('.past') here cause each time $('.past') called it returns different objects 
     # so we need to store spy in variable 
     showSpy = spyOn($.fn, 'show') 
     # do the stuff 
     $('.show-past').click() 
     # then check if 'show' action was called 
     expect($.fn.show).toHaveBeenCalled() 
     # and if it realy our object 
     expect(showSpy.mostRecentCall.object.selector).toEqual('.past') 

但我希望這可以幫助別人。而且,是的,在CoffeScript中的例子。

+2

.selector在jQuery的1.7+棄用。 1.7+版本有什麼替代? – Venugopal 2016-07-20 17:14:42

2

我寫了一個輔助功能,它接受ID /值對的陣列。

var jasminTestHelper = { 
    spyOnValAndFake : function(obj) { 
     var i, j; 
     spyOn($.fn, 'val').andCallFake(function() { 
      for (i = 0, j = obj.length; i < j; i++) { 
       if (this.selector === '#' + obj[i][0]) { 
        return obj[i][1]; 
       } 
      } 
     }) 
    } 
} 

每對告訴爲其ID,其中,如果所述的jQuery-VAL()值應返回的騙子函數 - 函數被調用與ID-選擇器。它是這樣使用:

jasminTestHelper.spyOnValAndFake([["id1", "value1"], ["id2", "value2"]]); 

如果$('#id1').val()被稱爲被測的功能,假函數返回value1,如果$('#id2').val()被稱爲返回value2。因此,您不需要擺弄DOM,只需模擬jQuery-val()函數並模擬返回值即可。其他jQuery函數也可能以同樣的方式嘲弄。

+0

我一直在爲'$(selector)'調用這棵樹。目前,我正在嘲笑一個嘲笑多個選擇器的幫手,但現在我已經發布了https://github.com/alxndr/sundries/blob/master/spy-on- jQuery的helper.js – alxndr 2013-09-27 01:45:03

2

你可以創建自己的假的DOM元素,然後使用$( '#elementid')[0]像往常一樣

addFakeElementWithId = function (elementId) { 
     var fake = document.createElement("div"); 
     fake.setAttribute("id", elementId); 
     document.body.appendChild(fake); 
    }; 
1

我覺得這是我的茉莉花版本的變化(2.0.3),因此Alex York的解決方案沒有按原樣工作,但肯定給了我一條路。因此,這裏的工作規範 jQuery代碼將被測試

$('someSelector').data('someAttribute').enable(); 

這裏是它的茉莉規範部分

var mockJqueryObject = { enable:function(){},disable:function(){}}; 
//this mocks the .data('someAttribute') in above code. 
spyOn($.fn, "data").and.returnValue(mockSelectBoxObject); 

更細化的規範可以使用模擬的另一個水平

spyOn(mockJqueryObject,"enable") 
spyOn(mockJqueryObject,"disable")