I have a service with a replay subject.
export class UserService {
public userChanged: ReplaySubject<User> = new ReplaySubject<User>();
...
public getUser(userId?): void {
...
this.http.get(url, httpOptions).pipe(
catchError(this.handleError('getUser', null, 'Couldn\'t get user', options))
).subscribe( (user: User) => {
this.userChanged.next(user);
});
}
My component subscribes to userChanged
.
this.userService.userChanged.subscribe((user) => {
this.user = user;
});
Now, I want to mock my UserService
in the component test:
1 option Testing Observables in Angular)
import { of } from 'rxjs';
...
const userServiceSpy = jasmine.createSpyObj('UserService', {'userChanged': of({_id: '1'}) });
or 2 option)
const userServiceSpy = jasmine.createSpyObj('UserService', {'userChanged': () => of({_id: '1'}) });
or 3 option angular test tutorial)
const userServiceSpy = jasmine.createSpyObj('UserService', ['userChanged']});
const userChangedSpy = userServiceSpy.userChanged.and.returnValue( of({_id: '1'}) );
+
TestBed.configureTestingModule({
...
providers: [
...
{provide: UserService, useValue: userServiceSpy}
],
schemas: [NO_ERRORS_SCHEMA]
})
give me this err:
this.userService.userChanged.subscribe is not a function
Shouldn't of
return an Observable to subscribe to?
Question: How to mock this?
createSpyObj
is used to to create spies on methods. You could use it for getUser
method of UserService
.
userChanged
is just a property of the class. You don't need a spy for it.
What you can do is simply create a mock object that returns subject:
const userChanged = new Subject();
providers: [
...
{provide: UserService, useValue: { userChanged }}
],
{ userChanged }
is equal to { userChanged: userChanged }
Then, in your beforeEach
block you would emit a new user instance:
//...
beforeEach(() => {
const myUser = new User(...)
userChanged.next(myUser)
})
I recommend to do this in the beforeEach
block to avoid side effects between different specs.
providers: [
...
{provide: UserService, useValue: { userChanged: of({id: 1}) }}
],
Another way of doing the same would be simply creating observable using of
method same way you're doing it in your example.
If you really want to spy on subscribe
method, you can create spy on it:
spyOn(userChanged, 'subscribe')
If you want to mix spyObject
with properties, you can use spread operator:
const spyObj = {
... jasmine.createSpyObj('MyObject', ['spyMethod']),
myProperty: true,
};
spyObj.spyMethod();
expect(spyObj.spyMethod).toHaveBeenCalled();
expect(spyObj.myProperty).toBeTrue();
This might be a bit late.. But I was able to resolve this issue by following the below approach:
1. mockUserService = TestBed.get(UserService)
2. By calling the subscribe method using :
mockUserService.userChanged.Subscribe(data => {
// do something
})
Note: Code at line 1 & 2 must sit anywhere after TestBed.configureTestingModule declaration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With