簡體   English   中英

Angular + Jasmine - 測試加載的 BehaviorSubject 作為服務中的 Observable

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM