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);
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);
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.
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();
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);
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.
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');
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
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
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)
The best way is to use spyOnProperty
. It expects 3 properties and you need to pass get
or set
as third property.
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.
You can not mock variable but you can create getter function for it and mock that method in your spec file.