Ben Aston Ben Aston - 6 months ago 209
Javascript Question

How can I spy on a getter property using jasmine?

How can I spy on a getter property using jasmine?

var o = { get foo() {}, };

spyOn(o, 'foo').and.returnValue('bar'); // Doesn't work.

This also does not work AFAICT:

spyOn(Object.getOwnPropertyDescriptor(o, 'foo'), 'get').and.returnValue('bar');


This feature doesn't appear to implemented, but there's no reason why it couldn't be.

Jasmine's spyOn operates by rewriting an object's method with a new function that calls the old function. spyOn(obj, prop) does something like this:

var oldFunc = obj[prop];
obj[prop] = function() {
    return oldFunc.apply(this, arguments);

This approach doesn't work for getters and setters, since bracket notation will run the setter/getter, but it will not access it. Your attempt to use getOwnPropertyDescriptor is on the right track, but getOwnPropertyDescriptor simply returns a new object that describes the property's getters/setters. Changing a property on that returned description object with obj[prop] = function() { ... } does not cause a change to the property itself.

Instead, you'd need to take a fundamentally different approach to re-writing the function. Rather than rewriting the property with a function, you'd need to redefine the property to use a new getter:

var oldDescriptor = Object.getOwnPropertyDescriptor(o, 'foo');

// test if this is an accessor property
if(oldDescriptor.get) {
    Object.defineProperty(o, 'foo', {
        set: oldDescriptor.set,
        get: function() {
            return oldDescriptor.get.apply(this);

The Jasmine code for spyOn is in /src/core/SpyRegistry.js, and in particular, the code that replaces a method with a spy function is currently:

  var spy = j$.createSpy(methodName, obj[methodName]);

    spy: spy,
    baseObj: obj,
    methodName: methodName,
    originalValue: obj[methodName]

  obj[methodName] = spy;

As described above, this totally rewrites properties with spy functions; it currently has no support for rewriting only the set or get of an accessor property with definePrpoerty.