[英]Angular + Jasmine - testing loaded BehaviorSubject as Observable in service
我有一个可注入服务,用于获取超过 HTTP 的用户角色和权限。为了确保 HTTP 调用只进行一次,我在服务中设置了一个 BehaviorSubject 并公开了一个公共 Observable,因此任何注入该服务的组件都可以订阅它检查权限是否已加载。
用户服务.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserService {
private _loaded = new BehaviorSubject<boolean>(false);
public $loaded = this._loaded.asObservable();
userDetailsUrl = "/serviceurl";
constructor(private _http: HttpClient) {
this.getUserDetails();
}
getUserDetails() {
this._http.get(this.userDetailsUrl).subscribe({
next: (data) => {
// set permissions...
this._loaded.next(true);
}
});
}
// getters for roles and permissions...
一些.component.ts
@Component({...})
export class SomeComponent implements OnInit {
loadedRoles: Subscription;
constructor(private _user: UserService) {}
ngOnInit() {
this.loadedRoles = this._user.$loaded.subscribe({
next: (data) => // get roles and permissions to restrict component functionality...
});
}
// ...
在 specfile 中,我希望能够在服务创建后再次调用 getUserDetails 来测试加载的订阅。
用户.服务.spec.ts
describe('SessionService', () => {
let service: SessionService;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
const userDetailsUrl = "/serviceurl";
const data1 = {
"roles": ["TESTER"]
};
let firstReq;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
});
service = TestBed.inject(SessionService);
httpClient = TestBed.inject(HttpClient);
httpTestingController = TestBed.inject(HttpTestingController);
firstReq = httpTestingController.expectOne({
'url': userDetailsUrl,
'method': 'get'
});
}));
afterEach(() => {
httpTestingController.verify();
});
it('should create and get user details over HTTP', () => {
expect(service).toBeTruthy();
expect(firstReq.request.method).toEqual('GET');
});
it('should be loaded', () => {
service.$loaded.subscribe({
next: (data) => {
console.log("post load", data);
expect(data).toBeTruthy(); // since it passes true to the subscription
},
error: fail
});
service.getUserDetails();
httpTestingController.expectOne({
'url': userDetailsUrl,
'method': 'get'
}).flush(data1);
});
// ...
然而,虽然它确实在调用中更新了 $loaded Observable,但“应该加载”测试失败了,显然是因为 Observable 最初有一个假值,我可以在控制台 output 中看到两次日志语句:
output
Browser application bundle generation complete.
LOG: 'post load', false
Chrome 105.0.0.0 (Windows 10): Executed 1 of 2 SUCCESS (0 secs / 0.022 secs)
LOG: 'post load', true
Chrome 105.0.0.0 (Windows 10): Executed 1 of 2 SUCCESS (0 secs / 0.022 secs)
Chrome 105.0.0.0 (Windows 10) UserService should be loaded FAILED
Error: Expected false to be truthy.
at <Jasmine>
at Object.next (src/app/services/user.service.spec.ts:50:22)
at ConsumerObserver.next (node_modules/rxjs/dist/esm/internal/Subscriber.js:91:1)
at SafeSubscriber._next (node_modules/rxjs/dist/esm/internal/Subscriber.js:60:1)
Chrome 105.0.0.0 (Windows 10): Executed 2 of 2 (1 FAILED) (0 secs / 0.032 secs)
Chrome 105.0.0.0 (Windows 10) UserService should be loaded FAILED
Error: Expected false to be truthy.
at <Jasmine>
at Object.next (src/app/services/user.service.spec.ts:50:22)
at ConsumerObserver.next (node_modules/rxjs/dist/esm/internal/Subscriber.js:91:1)
我在这里错过了什么?
在订阅发生之前,需要根据您的模拟请求调用flush()
。 next()
回调是使用 BehaviorSubject 的初始值执行的,因为 Mock 响应在订阅时还没有返回。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.