[英]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.