【问题标题】:Angular Jasmine testing Eventemitter subscriptionAngular Jasmine 测试 Eventemitter 订阅
【发布时间】:2019-12-10 11:05:27
【问题描述】:

我正在尝试在 Angular 中测试以下组件,特别是驻留在 userService 上的 eventEmitter。

import { Component, OnInit, OnDestroy } from '@angular/core';
import { RegisterUser } from 'src/app/classes/register-user';
import { ToastController } from '@ionic/angular';
import { UserService } from 'src/app/services/user.service';
import { Result } from 'src/app/classes/result';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { User } from 'src/app/classes/user';

/**
 * Register-user page, used for creating new users for the system
 */
@Component({
  selector: 'app-register-user',
  templateUrl: './register-user.page.html',
  styleUrls: ['./register-user.page.scss'],
})
export class RegisterUserPage implements OnDestroy {
  constructor(private toastController: ToastController, private userService: 
  UserService) { }

  /**
   * Unsubscribes from Observables when component gets destroyed
   */
  ngOnDestroy(): void {
    this.userService.resultEvent.unsubscribe();
    console.log('unsub');
  }

  /**
   * Function creates a new user and subscribes to resultEvent
   * @param user The new user
   */
  public registerUser(user: RegisterUser) {
    this.userService.registerUser(user);
    this.userService.resultEvent.subscribe((result: Result) => this.showToast(result));
    console.log('subscribed', this.userService.resultEvent);
  }

/**
   * Result handler, which will show result toast
   * @param result Result from the service
   */
  private async showToast(result: Result) {
    console.log('called')
    if (result.success) {
      this.toastController.create({
        message: 'Benutzer angelegt',
        duration: 2000,
      }).then((toast) => {
        toast.present();
      });
    } else {
      this.toastController.create({
        message: 'Ein Fehler ist aufgetreten Code:(' + result.httpCode + ')',
        duration: 2000,
      }).then((toast) => {
        toast.present();
      });
    }
  }
}

我的测试如下: 我正在运行 registerUser() 方法,该方法订阅 userService 中的 eventEmitter(在测试中模拟),然后调用 showToast() 方法,该方法将显示一个 toast,其结果由事件中的服务返回为价值。

import { CUSTOM_ELEMENTS_SCHEMA, EventEmitter } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { RegisterUserPage } from './register-user.page';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { UserService } from 'src/app/services/user.service';
import { RegisterUser } from 'src/app/classes/register-user';
import { ToastController } from '@ionic/angular';
import { Result } from 'src/app/classes/result';

describe('RegisterUserPage', () => {
  let component: RegisterUserPage;
  let fixture: ComponentFixture<RegisterUserPage>;

  const userServiceSpy = {
    registerUser() {},
    async getAllUsersAsync() {},
    resultEvent: new EventEmitter()
  };

  const toastControllerMock = {
    create({}) {return new Promise((resolve, reject) => {
      resolve();
    });
    }
  };

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ RegisterUserPage ],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      imports: [FormsModule, ReactiveFormsModule],
      providers: [
         { provide: UserService, useValue: userServiceSpy },
         { provide: ToastController, useValue: toastControllerMock }
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(RegisterUserPage);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should display the result', async () => {
    const userService = TestBed.get(UserService);
    const toastController = TestBed.get(ToastController);
    spyOn(toastController, 'create').and.callThrough();

    component.registerUser(new RegisterUser('', '', '', '', ''));
    userService.resultEvent.emit(new Result(400, true));

    const successMessage = {
      message: 'Benutzer angelegt',
      duration: 2000,
    };

    const failMessage = {
      message: 'Ein Fehler ist aufgetreten Code:(500)',
      duration: 2000,
    };

    component['showToast'](new Result(200, true));
    expect(toastController.create).toHaveBeenCalledWith(successMessage);
    component['showToast'](new Result(500, false));
    expect(toastController.create).toHaveBeenCalledWith(failMessage);
  });
});

不知何故,ngDestroy() 函数被调用,该函数在测试完成之前从 eventEmitter 取消订阅
因此,我遇到了 objectUnsubscribed 错误。

知道如何解决这个问题吗?

【问题讨论】:

  • 什么 ngDestroy函数?测试是如何设置的?你在测试一个组件吗?给minimal reproducible example
  • 抱歉更新晚了,但是问题已经更新了更多代码和更多解释

标签: angular jasmine angular-event-emitter


【解决方案1】:

通过以下方式修复它: 我没有从 eventEmitter 取消订阅,而是将订阅保存到 Subscription 类型的变量中并取消订阅。

export class ...{

  public resultSubsciption: Subscription;

  ngOnDestroy(): void {
    this.resultSubsciption.unsubscribe();
  }

  public registerUser(user: RegisterUser) {
    this.userService.registerUser(user);
    this.resultSubsciption = this.userService.resultEvent.subscribe((result: Result) => 
    this.showToast(result));
  }
}

订阅管理应该这样完成:
ObjectUnsubscribedError: object unsubscribed error when I am using ngx-progress in angular 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    相关资源
    最近更新 更多