简体   繁体   中英

How to wrap a function's result in jasmine

I've got a function whose output I want to mess with. It's a little like a combination of andCallThrough and andCallFake. For example, suppose I've got this constructor function:

function Widget() {
  this.frobble = function() {return 1;};
}

function frotz() {
  return new Widget().frobble();
}

What I want to be able to do is something like this:

describe("Widget", function() {
  it("is created and frobbled when frotz() is called", function() {
    var widget;
    spyOn(window, 'Widget').andMessWithOutput(function(newWidget) {
      widget = newWidget;
      spyOn(widget, 'frobble').andCallThrough();
      frotz();
      expect(widget.frobble.calls.length).toBe(1);
    });
  });
});

The best way I've found for doing this is the following:

it("is clumsily created and frobbled when frotz() is called", function() {
  var widget;
  spyOn(window, 'Widget').andCallFake(function() {
    // originalValue is the original spied-upon value. note that if it's a constructor
    // you've got to call it with new (though that shouldn't seem unusual).
    widget = new Widget.originalValue(); 
    spyOn(widget, 'frobble').andCallThrough();
    frotz();
    expect(widget.frobble.calls.length).toBe(1);
  });
});

I have a helper I use for this, maybe it could be useful to others.

// testUtils.js

module.exports = {
    spyOn: customSpyOn
};

function customSpyOn(obj, name) {
    const fn = obj[name];
    return {
        and: {
            wrapWith: wrapWith
        }
    };

    function wrapWith(wrapper) {
        obj[name] = jasmine.createSpy(`wrapped: ${name}`)
            .and.callFake(spyWrapper);
        return obj[name];

        function spyWrapper() {
            const args = [].slice.call(arguments);
            return wrapper.apply(obj, [fn].concat(args));
        }
    }
}

Usage

If you were wanting to add spies to the return value of;

const connection = socket.createConnection('ws://whatever.com/live', {
    format: 'json'
});

connection.open();
// etc...

The top of your spec and setup might look something like this

// some.spec.js

const testUtils = require('./testUtils');

testUtils.spyOn(socket, 'createConnection')
    .and
    .wrapWith(function(original, url, options) {
        var api = original(url, options);
        spyOn(api, 'open').and.callThrough();
        spyOn(api, 'close').and.callThrough();
        spyOn(api, 'send').and.callThrough();
        return api;
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM