Spying on JQuery Selectors in Jasmine

前端 未结 6 1438
执念已碎
执念已碎 2020-12-02 15:29

I am unit testing some JavaScript with Jasmine and wish to spy on (mock) an element of the DOM that is accessed by a jQuery selector.

My spec is:

it(         


        
相关标签:
6条回答
  • 2020-12-02 15:42

    You could create your own fake DOM element and then use $('#elementid')[0] as usual

    addFakeElementWithId = function (elementId) {
          var fake = document.createElement("div");
          fake.setAttribute("id", elementId);
          document.body.appendChild(fake);
       };
    
    0 讨论(0)
  • 2020-12-02 15:55

    The problem is that the two calls to $ return two different jQuery-wrapped nodes.

    This should work:

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

    Next time, help is more prevalent on the Jasmine mailing list: jasmine-js@googlegroups.com.

    0 讨论(0)
  • 2020-12-02 15:55

    I wrote a helper-function, which accepts an array of 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];
                    }
                }
            })
        }
    }
    

    Each pair tells the faker-function for which id, which value should be returned if the jQuery-val()-function is called with the id-selector. It is used like this:

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

    If $('#id1').val() is called in your function under test, the fake-function returns value1, if $('#id2').val() is called it returns value2. So you don't need to fiddle with the DOM, you just mock the jQuery-val()-function and simulate return-values. Other jQuery-functions could probably mocked the same way.

    0 讨论(0)
  • 2020-12-02 15:57

    This line is wrong:

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

    Jasmine's spyOn function expects two parameters. The first is an existing object. The second is a function name as a string. You are correctly passing in the function name as a string ("val") but you are not passing in an existing object as the first parameter.

    $("#Something")
    

    ...is not an existing object. It is the result (the return value) of a jQuery selector. More specifically, it will return a jQuery object representing the matched nodes - kind of like an array of results.

    $
    

    ...is an existing object.

    $.fn
    

    ...is an existing object.

    $("#Something")
    

    ...is not an existing object - it is the result of a jQuery selector.

    This will work:

    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");
    });
    
    0 讨论(0)
  • 2020-12-02 16:00

    Seems like I found good solution

        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')
    

    This is not based on your code but i hope this can help someone. And, yes, example in CoffeScript.

    0 讨论(0)
  • 2020-12-02 16:00

    I think there is a change in my jasmine version (2.0.3), hence the solution by Alex York didn't work as is, but definitely gave me a path. So here is the working spec jquery code which is to be tested

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

    here is the jasmine spec part of it

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

    A more granular spec could use another level of mock as

    spyOn(mockJqueryObject,"enable")
    spyOn(mockJqueryObject,"disable")
    
    0 讨论(0)
提交回复
热议问题