Angular Jasmine - 从组件中的模拟服务中侦测主题

Angular Jasmine - spy a subject from a mocked service in a component

您好,我正在测试一个组件,在该组件中我有两个主题的 CartService。我正在为该服务创建一个 spyObject。现在,当 angular 尝试订阅这些主题时,它们完全没有定义。试图 returnValue 的 Subject 或其他东西,但现在没有任何效果。仍未定义。

这是服务和主题。

export class CartService {

  totalQuantity: Subject<number> = new Subject<number>();
  totalPrice: Subject<number> = new Subject<number>();
}

然后在 ngOnInit() 的组件中我只是订阅了它们。这是 Angular 尝试订阅的地方,但它们未定义,我不知道如何模拟它们

this.subscribePrice = this.cartService.totalPrice.subscribe(data => this.totalPrice = data);
this.subscribeQuantity = this.cartService.totalQuantity.subscribe(data => this.totalQuantity = data);

这里是测试class:

fdescribe('CheckoutComponent', () => {
  let component: CheckoutComponent;
  let fixture: ComponentFixture<CheckoutComponent>;
  let el: DebugElement;
  let messageToastrService: any;
  let cartService: any;
  let priceSubject: Subject<number>;
  let quantitySubject: Subject<number>;

  beforeEach(async(() => {
    priceSubject = new Subject<number>();
    quantitySubject = new Subject<number>();
    const messageToastrSpy = jasmine.createSpyObj('MessageToastrService', ['success']);
    const cartServiceSpy = jasmine.createSpyObj('CartService',
      ['getCartFromStorage', 'computeTotals'], ['totalQuantity', 'totalPrice']);

    TestBed.configureTestingModule({
      declarations: [ CheckoutComponent ],
      imports: [
        ProductsModule,
        RouterTestingModule.withRoutes([]),
        HttpClientTestingModule,
      ],
      providers: [
        {provide: MessageToastrService, useValue: messageToastrSpy},
        {provide: CartService, useValue: cartServiceSpy},
      ]
    })
    .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(CheckoutComponent);
        component = fixture.componentInstance;
        el = fixture.debugElement;
        messageToastrService = TestBed.inject(MessageToastrService);
        cartService = TestBed.inject(CartService);
        fixture.detectChanges();
      });
  }));

现在只是专注于手头的事情。这些是我试图解决问题的方法。但是,仍然没有任何效果。

it('should properly initialize component', function() {
    component.ngOnInit();

    // cartService.totalPrice.and.returnValue(priceSubject.asObservable());
    // cartService.totalQuantity.and.returnValue(quantitySubject.asObservable());

    cartService.totalPrice.and.returnValue(of());
    cartService.totalQuantity.and.returnValue(of());

    // (cartService.totalPrice as jasmine.Spy).and.returnValue(priceSubject.asObservable());
    // (cartService.totalQuantity as jasmine.Spy).and.returnValue(quantitySubject.asObservable());
  });

踪迹:

Failed: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
    at CheckoutComponent.uploadCartInfo (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:62:55)
    at CheckoutComponent.ngOnInit 
error properties: Object({ rejection: TypeError: Cannot read property 'subscribe' of undefined, promise: [object Promise], zone: Zone({ _parent: Zone({ _parent: null, _name: '<root>', _properties: Object({  }), _zoneDelegate: ZoneDelegate({ _taskCounts: Object({ microTask: 0, macroTask: 0, eventTask: 0 }), zone: <circular reference: Object>, _parentDelegate: null, _forkZS: null, _forkDlgt: null, _forkCurrZone: null, _interceptZS: null, _interceptDlgt: null, _interceptCurrZone: null, _invokeZS: null, _invokeDlgt: null, _invokeCurrZone: null, _handleErrorZS: null, _handleErrorDlgt: null, _handleErrorCurrZone: null, _scheduleTaskZS: null, _scheduleTaskDlgt: null, _scheduleTaskCurrZone: null, _invokeTaskZS: null, _invokeTaskDlgt: null, _invokeTaskCurrZone: null, _cancelTaskZS: null, _cancelTaskDlgt: null, _cancelTaskCurrZone: null, _hasTaskZS: null, _hasTaskDlgt: null, _hasTaskDlgtOwner: null, _hasTaskCurrZone: null }) }), _name: 'ProxyZone', _properties: Object({ ProxyZoneSpec: ProxyZoneSpec({ defaultS ...
Error: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
    at CheckoutComponent.uploadCartInfo (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:62:55)
    at CheckoutComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:40:10)
    at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2922:1)
    at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2892:1)
    at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2844:1)
    at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:7213:1)
    at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:7312:1)
    at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8507:1)
    at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8532:1)
    at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9918:1)
    at resolvePromise (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:798:1)
    at http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:864:1
    at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:399:1)
    at AsyncTestZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:1016:1)
    at ProxyZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:320:1)
    at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:398:1)
    at Zone.runTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:167:1)
    at drainMicroTaskQueue (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:569:1)

我该如何解决这个问题?谢谢。

在您的 CartService 中,totalQuantity 和 totalPrice 是主题。所以像这样嘲笑那些科目

cartService.totalQuantity.and.returnValue(new Subject<number>()); 

由于您在 ngOnInit 中访问这些主题,因此您必须在 CreateComponent 之前保留此间谍。所以把它放在 beforeEach 上面 create.

在 Szymon 的帮助下找到了答案。

首先我必须更改 cartServiceSpy 的 spyObject 并在下面添加这两个字段以监视它们。

 const cartServiceSpy = jasmine.createSpyObj('CartService', ['getCartFromStorage', 'computeTotals']);
 cartServiceSpy.totalQuantity = quantitySubject;
 cartServiceSpy.totalPrice = priceSubject;