How to spyOn a value property (rather than a method) with Jasmine

JavascriptUnit TestingMockingJasmine

Javascript Problem Overview


Jasmine's spyOn is good to change a method's behavior, but is there any way to change a value property (rather than a method) for an object? the code could be like below:

spyOn(myObj, 'valueA').andReturn(1);
expect(myObj.valueA).toBe(1);

Javascript Solutions


Solution 1 - Javascript

In February 2017, they merged a PR adding this feature, they released in April 2017.

so to spy on getters/setters you use: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); where myObj is your instance, 'myGetterName' is the name of that one defined in your class as get myGetterName() {} and the third param is the type get or set.

You can use the same assertions that you already use with the spies created with spyOn.

So you can for example:

const spy = spyOnProperty(myObj, 'myGetterName', 'get'); // to stub and return nothing. Just spy and stub.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.returnValue(1); // to stub and return 1 or any value as needed.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.callThrough(); // Call the real thing.

Here's the line in the github source code where this method is available if you are interested.

https://github.com/jasmine/jasmine/blob/7f8f2b5e7a7af70d7f6b629331eb6fe0a7cb9279/src/core/requireInterface.js#L199

And the spyOnProperty method is here

Answering the original question, with jasmine 2.6.1, you would:

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

Solution 2 - Javascript

Any reason you cannot just change it on the object directly? It is not as if javascript enforces visibility of a property on an object.

Solution 3 - Javascript

Jasmine doesn't have that functionality, but you might be able to hack something together using Object.defineProperty.

You could refactor your code to use a getter function, then spy on the getter.

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);

Solution 4 - Javascript

The best way is to use spyOnProperty. It expects 3 parameters and you need to pass get or set as a third param.

Example
const div = fixture.debugElement.query(By.css('.ellipsis-overflow'));
// now mock properties
spyOnProperty(div.nativeElement, 'clientWidth', 'get').and.returnValue(1400);
spyOnProperty(div.nativeElement, 'scrollWidth', 'get').and.returnValue(2400);

Here I am setting the get of clientWidth of div.nativeElement object.

Solution 5 - Javascript

The right way to do this is with the spy on property, it will allow you to simulate a property on an object with an specific value.

const spy = spyOnProperty(myObj, 'valueA').and.returnValue(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

Solution 6 - Javascript

If you are using ES6 (Babel) or TypeScript you can stub out the property using get and set accessors

export class SomeClassStub {
  getValueA = jasmine.createSpy('getValueA');
  setValueA = jasmine.createSpy('setValueA');
  get valueA() { return this.getValueA(); }
  set valueA(value) { this.setValueA(value); }
}

Then in your test you can check that the property is set with:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');

Solution 7 - Javascript

Suppose there is a method like this that needs testing The src property of the tiny image needs checking

function reportABCEvent(cat, type, val) {
                var i1 = new Image(1, 1);
                var link = getABC('creosote');
                    link += "&category=" + String(cat);
                    link += "&event_type=" + String(type);
                    link += "&event_value=" + String(val);
                    i1.src = link;
                }

The spyOn() below causes the "new Image" to be fed the fake code from the test the spyOn code returns an object that only has a src property

As the variable "hook" is scoped to be visible in the fake code in the SpyOn and also later after the "reportABCEvent" is called

describe("Alphabetic.ads", function() {
    it("ABC events create an image request", function() {
    var hook={};
    spyOn(window, 'Image').andCallFake( function(x,y) {
          hook={ src: {} }
          return hook;
      }
      );
      reportABCEvent('testa', 'testb', 'testc');
      expect(hook.src).
      toEqual('[zubzub]&arg1=testa&arg2=testb&event_value=testc');
    });

This is for jasmine 1.3 but might work on 2.0 if the "andCallFake" is altered to the 2.0 name

Solution 8 - Javascript

I'm using a kendo grid and therefore can't change the implementation to a getter method but I want to test around this (mocking the grid) and not test the grid itself. I was using a spy object but this doesn't support property mocking so I do this:

    this.$scope.ticketsGrid = { 
        showColumn: jasmine.createSpy('showColumn'),
        hideColumn: jasmine.createSpy('hideColumn'),
        select: jasmine.createSpy('select'),
        dataItem: jasmine.createSpy('dataItem'),
        _data: []
    } 

It's a bit long winded but it works a treat

Solution 9 - Javascript

I'm a bit late to the party here i know but,

You could directly access the calls object, which can give you the variables for each call

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)

Solution 10 - Javascript

You can not mock variable but you can create getter function for it and mock that method in your spec file.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShupingView Question on Stackoverflow
Solution 1 - JavascriptJuanView Answer on Stackoverflow
Solution 2 - JavascriptPaul HarrisView Answer on Stackoverflow
Solution 3 - JavascriptEricView Answer on Stackoverflow
Solution 4 - JavascriptAniruddha DasView Answer on Stackoverflow
Solution 5 - JavascriptalexalejandroemView Answer on Stackoverflow
Solution 6 - JavascriptMartinView Answer on Stackoverflow
Solution 7 - JavascriptVorsprungView Answer on Stackoverflow
Solution 8 - JavascriptjolySoftView Answer on Stackoverflow
Solution 9 - JavascriptCosmicChildView Answer on Stackoverflow
Solution 10 - JavascriptGampeshView Answer on Stackoverflow