在 BsModalRef 中模拟 modal.content.onClose.subscribe

Mocking modal.content.onClose.subscribe in BsModalRef

我有一个通用的 ModalConfirm (ngx-bootstrap) 组件,如下所示:

export class ModalConfirmComponent {
  public active = false;
  public body: string | undefined | null;
  public title: string | undefined | null;
  public onClose = new Subject<boolean>();

  public constructor(private bsModalRef: BsModalRef) {}

  public showConfirmationModal(title: string, body: string): void {
    this.title = title;
    this.body = body;
    this.active = true;
  }

  public onConfirm(): void {
    this.active = false;
    this.onClose.next(true);
    this.bsModalRef.hide();
  }

  public onCancel(): void {
    this.active = false;
    this.onClose.next(false);
    this.bsModalRef.hide();
  }

  public hideConfirmationModal(): void {
    this.active = false;
    this.onClose.next(undefined);
    this.bsModalRef.hide();
  }
}

它从服务调用如下:

  addElementWithConfirmation(
    course: ICourse | undefined | null,
    courseContents: ICourseContent[] | undefined | null,
    selectedCourseContentUid: string | undefined | null,
    selectedCourseContentElementUid: string,
    selectedCourseModule: number | undefined | null,
    showAddElementMenu: boolean,
    courseContentElementMethod: CourseContentElementsMap,
    confirmElementReplacementModalBody: string
  ): void {
    if (
      course &&
      courseContents &&
      selectedCourseContentUid &&
      !UtilService.isNullOrUndefined(selectedCourseModule)
    ) {
      if (
        this.canCourseContentElementBeAdded(
          courseContentElementMethod,
          courseContents,
          selectedCourseContentUid
        )
      ) {
        const modal = this.modalService.show(ModalConfirmComponent);
        if (modal && modal.content) {
          modal.content.showConfirmationModal(
            CONFIRM_MODAL_TITLE,
            confirmElementReplacementModalBody
          );
          modal.content.onClose.subscribe((result) => {
            if (result) {
              this.hideAddElementMenu(showAddElementMenu);
              courseContents = ADD_COURSE_CONTENT_ELEMENT_MAP[courseContentElementMethod](
                (courseContents as unknown) as ICourseContent[],
                selectedCourseContentElementUid,
                selectedCourseContentUid
              );
            } else {
              this.hideAddElementMenu(showAddElementMenu);
            }
          });
      }
    }
  }

我现在面临的问题是围绕测试,modal.content.onClose.subscribe((result) => { 下的所有内容目前都是无法访问的代码。我该如何解决?我的测试如下:

  describe('addElementWithConfirmation()', () => {
    it('should add element', () => {
      spyOn(service, 'canCourseContentElementBeAdded').and.callThrough();
      let newCourseContents: ICourseContent[] = JSON.parse(JSON.stringify(courseContents));
      service.addElementWithConfirmation(
        course,
        newCourseContents,
        newCourseContents[0].uid,
        `${CourseContentElementType.AUDIO}-${UtilService.generateRandomString(10)}`,
        0,
        true,
        CourseContentElementsMap.ADD_COURSE_CONTENT_ELEMENT_AUDIO,
        'test'
      );
      expect(service.canCourseContentElementBeAdded).toHaveBeenCalled();
    });

我知道最好的做法是如下模拟 BsModalRef,但我不确定如何模拟 modal.content.onClose.subscribe 的 return?例如,这是一个 content 为空的示例:

      spyOn(mockModalService, 'show').and.returnValue({
        id: 1,
        content: null,
        hide: () => {},
        setClass: () => {},
        onHide: new EventEmitter(),
        onHidden: new EventEmitter(),
      });

解决这个问题的最佳方法是什么?

为了覆盖 modal.content.onClose.subscribe((result) => { 代码部分,我将为 onClose 函数和 return 创建一个模拟 Observable 创建一个间谍。棘手的部分是,this.modalService.show 返回一个实例,这个实例需要被模拟并且应该 return 一个包含 content.onClose.

的间谍的模拟对象

因此需要类似的东西:

  const onCloseSpy = jasmine.createSpy().and.returnValue(of({})); // Here the rxjs of operator needes to return the onClose result object istead of the empty {} object. Please change add the object based on your needs.
  const contentMock = {onClose: onCloseSpy};
  spyOn(mockModalService, 'show').and.returnValue({
    id: 1,
    content: contentMock,
    hide: () => {},
    setClass: () => {},
    onHide: new EventEmitter(),
    onHidden: new EventEmitter(),
  });

我无法测试上面的代码,但我希望它能帮助理解这个想法,并且通过一些小的调整它会起作用。