How to mock/replace getter function of object with Jest?

60,385

Solution 1

You could use Object.defineProperty

Object.defineProperty(myObj, 'prop', {
  get: jest.fn(() => 'bar'),
  set: jest.fn()
});

Solution 2

For anyone else stumbling across this answer, Jest 22.1.0 introduced the ability to spy on getter and setter methods.

Edit: like in scieslak's answer below, because you can spy on getter and setter methods, you can use Jest mocks with them, just like with any other function:

class MyClass {
  get something() {
    return 'foo'
  }
}

jest.spyOn(MyClass, 'something', 'get').mockReturnValue('bar')
const something = new MyClass().something

expect(something).toEqual('bar')

Solution 3

If you care about spying only, go for @Franey 's answer. However if you actually need to stub a value for the getter, this is how you can do it:

class Awesomeness {
  get isAwesome() {
    return true
  }
}

describe('Awesomeness', () => {
  it('is not always awesome', () => {
    const awesomeness = new Awesomeness
    jest.spyOn(awesomeness, 'isAwesome', 'get').mockReturnValue(false)

    expect(awesomeness.isAwesome).toEqual(false)
  })
})
Share:
60,385
I_like_foxes
Author by

I_like_foxes

Student... Being curious and learning, learning, learning...

Updated on July 05, 2022

Comments

  • I_like_foxes
    I_like_foxes almost 2 years

    In Sinon I can do the following:

    var myObj = {
        prop: 'foo'
    };
    
    sinon.stub(myObj, 'prop').get(function getterFn() {
        return 'bar';
    });
    
    myObj.prop; // 'bar'
    

    But how can I do the same with Jest? I can't just overwrite the function with something like jest.fn(), because it won't replace the getter

    "can't set the value of get"

  • I_like_foxes
    I_like_foxes about 7 years
    Thank you a lot, that works. Sometimes I notice I don't need more knowledge about some library/framework but the fundamental workings of JavaScript. May I ask one follow up question: How would I mock this function if I wanted my mock to replace the original function just one time but the next call should handled by the original function again?
  • shoke
    shoke over 6 years
    This works, but when I try to do it in my beforeEach() call it fails with Cannot redefine property. Why is this?
  • cgat
    cgat over 6 years
    @clu add configurable: true to your the defineProperty function. That should do the trick
  • Misu
    Misu almost 6 years
    Notice that - in contrast with mocks - it won't "unmock" your getter at the end of each test case, so - if other tests rely on the original return value of the getter - you may get different results running one test and the whole suite.
  • Sandeep vashisth
    Sandeep vashisth over 5 years
    getting cannot redefine property.
  • Franey
    Franey about 5 years
    @taystack Being able to spy on the getters/setters was a necessary step toward being able to mock them like a regular function. I updated my answer to be more explicit about that and added a mock to the example code.
  • Tomasz Kula
    Tomasz Kula almost 5 years
    Scroll down to Franey answer. It is more recent.
  • Fabrizio Bertoglio
    Fabrizio Bertoglio over 4 years
    something property does not exist with [email protected]with ["module:metro-react-native-babel-preset", while it works fine with scieslak solution which sets the spy exactly on the awesomeness instance. In rspec I would use a method called any_instance and I would mock/stub any_instance of that class. There is a clear difference in syntax between the jest official spyOn documentation and your example. In that example jest spys on an object literal
  • Fabrizio Bertoglio
    Fabrizio Bertoglio over 4 years
    const video = { get play() { return true; },};
  • Ran Lottem
    Ran Lottem about 4 years
    I got an error that the property does not exist. It also looks like the other answer calls spyOn on the class whereas you call it on an instance.
  • Mike P.
    Mike P. about 4 years
    @fabrizo jest.spyOn(MyClass, 'something', 'get').mockReturnValue('bar') should be jest.spyOn(MyClass.prototype, 'something', 'get').mockReturnValue('bar')
  • mdhvn
    mdhvn almost 4 years
    I'm seeing the same thing - 'property does not exist' - when calling on an instance.
  • Valentine Shi
    Valentine Shi over 2 years
    This is really good as this allows working with the complex object's fixture - its POJO representation. This especially useful when you have to supply that object as dependency and would not like to bother creating the actual object - actually keeping yourself away from integration tesing when it is not yet desirable.