63

我正在使用 Jasmine 对一些 JavaScript 进行单元测试,并希望监视(模拟)由 jQuery 选择器访问的 DOM 元素。

我的规格是:

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 调用 Expected 'foo' to equal 'bar'。

4

6 回答 6

97

这一行是错误的:

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

Jasmine 的 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");
});
于 2011-06-01T08:11:01.773 回答
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 中的示例。

于 2011-11-20T20:45:02.070 回答
17

问题是对 $ 的两次调用返回两个不同的 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');
});

下一次,Jasmine 邮件列表中的帮助会更加普遍:jasmine-js@googlegroups.com。

于 2011-03-23T05:34:02.093 回答
3

您可以创建自己的假 DOM 元素,然后像往常一样使用 $('#elementid')[0]

addFakeElementWithId = function (elementId) {
      var fake = document.createElement("div");
      fake.setAttribute("id", elementId);
      document.body.appendChild(fake);
   };
于 2013-02-19T20:22:21.540 回答
2

我写了一个辅助函数,它接受一个 id/value-pairs 数组。

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];
                }
            }
        })
    }
}

每对都告诉 faker-function 哪个 id,如果使用 id-selector 调用 jQuery-val()-function 应该返回哪个值。它是这样使用的:

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

如果$('#id1').val()在您的被测函数中调用,则假函数返回value1,如果$('#id2').val()被调用,则返回value2。所以你不需要摆弄 DOM,你只需模拟 jQuery-val() 函数并模拟返回值。其他 jQuery 函数可能会以同样的方式进行模拟。

于 2013-01-25T20:07:30.827 回答
0

我认为我的 jasmine 版本(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")
于 2015-08-06T07:16:51.163 回答