简体   繁体   English

Angular + Jasmine - 测试加载的 BehaviorSubject 作为服务中的 Observable

[英]Angular + Jasmine - testing loaded BehaviorSubject as Observable in service

I have an injectable service for getting a user's roles and permissions over HTTP. To ensure the HTTP call is made only once, I set up a BehaviorSubject inside the service and expose a public Observable, so any component injecting the service can subscribe to it to check whether permissions have loaded.我有一个可注入服务,用于获取超过 HTTP 的用户角色和权限。为了确保 HTTP 调用只进行一次,我在服务中设置了一个 BehaviorSubject 并公开了一个公共 Observable,因此任何注入该服务的组件都可以订阅它检查权限是否已加载。

user.service.ts用户服务.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...

some.component.ts一些.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...
    });
  }
  // ...

In the specfile, I was expecting to be able to test the loaded subscription by calling getUserDetails again after service creation.在 specfile 中,我希望能够在服务创建后再次调用 getUserDetails 来测试加载的订阅。

user.service.spec.ts用户.服务.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);
  });
  // ...

However, while it does update the $loaded Observable in the call, the 'should be loaded' test fails, apparently since the Observable initially has a false value, and I can see the log statement twice in the console output:然而,虽然它确实在调用中更新了 $loaded Observable,但“应该加载”测试失败了,显然是因为 Observable 最初有一个假值,我可以在控制台 output 中看到两次日志语句:

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)

What am I missing here?我在这里错过了什么?

flush() needs to be called on your mock request before the subscription happens.在订阅发生之前,需要根据您的模拟请求调用flush() The next() callback is executed with the initial value of your BehaviorSubject because the Mock response hasn't come back at the point of subscription. next()回调是使用 BehaviorSubject 的初始值执行的,因为 Mock 响应在订阅时还没有返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM