'jasmine.createSpyObj with properties
When mocking dependencies in my Angular tests, I usually create a spy object using jasmine.createSpyObj
:
const serviceSpy= jasmine.createSpyObj('MyService', ['method']);
then provide it to the TestBed:
providers: [
{provide: MyService, useValue: serviceSpy}
]
When I use it in my test, I can then specify the desired return value:
serviceSpy.method.and.returnValue(of([...]));
Now I also need to mock properties and I cannot find out how it should be done. createSpyObj
does allow the definition of property names:
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], ['property']);
but I've tried varies solutions based on the numerous articles and answers out there without any success, e.g.:
// Cannot read property 'and' of undefined
serviceSpy.property.and.returnValue(true);
// not declared configurable
spyOnProperty(serviceSpy, 'property').and.returnValue(true);
// no build errors, but value stays 'undefined'
serviceSpy.property = true;
The only way I could make it 'half' work is:
let fakeValue = true;
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], {'property': fakeValue});
The problem here is that it's a one-time set at creation. If I want to change the expected value in the test, it does not work.
fakeValue = false;
serviceSpy.property ==> stays to the initial value 'true';
Does there exist a solution to both mock methods and properties by creating a spy object, or should I create my own fake class on which I can then use spyOn
and spyOnProperty
?
I would also like to know what the usage is of the properties array in the createSpyObj
definition. So far I have not seen any example on the web that explains it.
Solution 1:[1]
Thank you so much @jonrsharpe! I just added a function so I could do:
spyPropertyGetter(spy, 'propName').and.returnValue(...)
Which is defined as:
function spyPropertyGetter<T, K extends keyof T>(
spyObj: jasmine.SpyObj<T>,
propName: K
): jasmine.Spy<() => T[K]> {
return Object.getOwnPropertyDescriptor(spyObj, propName)?.get as jasmine.Spy<() => T[K]>;
}
Solution 2:[2]
This one will also do the job :)
const serviceSpy= jasmine.createSpyObj('MyService', ['method']);
Object.getOwnPropertyDescriptor(serviceSpy, "method").value.and.returnValue("test");
Solution 3:[3]
Thanks for the post, was super helpfull.
I added a Stackblitz Demo (Angular v12) to
jonrsharpe's & s.alems solution
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | s.alem |
Solution 2 | Peter Csala |
Solution 3 | Florian Uhlmann |