首页 > 解决方案 > 来自另一个组件的 Angular 测试入口组件

问题描述

我是 Angular 的初学者。

我使用 Angular Bootstrap 创建了一个简单的应用程序,它打开了一个简单的模式。

在继续之前,我想实现我的测试。

我的问题:

我想为 MainComponent 测试这个工作流程:

我的问题:

第一季度

当我们执行:

expect(modalService.open).toHaveBeenCalled();

如何确定模态是真正打开的或真正调用的函数?

Q2:

当我尝试这段代码时:

const h4DebEl : DebugElement = fixtureMainComponent.debugElement.query(By.css('h4'));

为什么它是空的?

我认为这是因为 H4 标签在 ModalComponent 的元素中。

然后,我测试了:

fixtureModalComponent = TestBed.createComponent(ModalComponentComponent);

但是我有一个用于 activeModal 的错误提供程序...

请在下面找到我的实际代码:

MainComponentComponent.component.ts

import { Component, OnInit } from '@angular/core';
import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';

import { ModalComponentComponent } from '../modal-component/modal-component.component';

@Component({
  selector: 'app-main-component',
  templateUrl: './main-component.component.html',
  styleUrls: ['./main-component.component.scss']
})

export class MainComponentComponent implements OnInit {

  constructor(
    // Use modalService to open a modal
    private modalService: NgbModal
  ) { }

  ngOnInit() {

  }

  openModal() {
    const modalRef = this.modalService.open(ModalComponentComponent);

    // Define the value @Input person in ModalComponentComponent
    modalRef.componentInstance.person = {
      name: "Itachi",
      lastName: "Uchiwa"
    };

    modalRef.result.then((result) => {
      this.closeModal();
    }, (reason) => {
      this.dismissReason(reason);
    });
  }

  /**
   * Close modal
   */
  closeModal() {
    console.log('Closed modal');
  }

  /**
   * Dismiss modal
   */
  dismissReason(reason: any) {
    if (reason === ModalDismissReasons.ESC) {
      this.dismissReasonEsc();
    } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
      this.dismissReasonBackdropClick();
    } else {
      this.dismissReasonUnknownReason();
    }
  }

  dismissReasonEsc() {
    console.log('Dismiss called by pressing ESC');
  }

  dismissReasonBackdropClick() {
    console.log('Dismiss called by pressing BACKDROP_CLICK');
  }

  dismissReasonUnknownReason() {
    console.log("Dismiss called");
  }

}

MainComponentComponent.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NgbModal, NgbModalRef, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';
import { AppModule } from '../app.module';
import { MainComponentComponent } from './main-component.component';
import { ModalComponentComponent } from '../modal-component/modal-component.component';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

describe('MainComponentComponent', () => {
  let component: MainComponentComponent;
  // Wrapper MainComponentComponent
  let fixtureMainComponent : ComponentFixture<MainComponentComponent>;
  let modalService: NgbModal;
  let modalRef: NgbModalRef; 

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports : [ AppModule ]
    }).compileComponents().then(() => {
      modalService = TestBed.get(NgbModal);
      fixtureMainComponent = TestBed.createComponent(MainComponentComponent);
      component = fixtureMainComponent.componentInstance;
      modalRef = modalService.open(ModalComponentComponent);
      spyOn(modalService, "open").and.returnValue(modalRef);

      spyOn(component, "openModal").and.callThrough();
      spyOn(component, "dismissReason").and.callThrough();
      spyOn(component, "dismissReasonEsc").and.callThrough();
      spyOn(component, "dismissReasonBackdropClick").and.callThrough();
      spyOn(component, "dismissReasonUnknownReason").and.callThrough();
      spyOn(component, "closeModal").and.callThrough();
    });    
  }));

  afterAll(() => {
    modalService.dismissAll();
    fixtureMainComponent.destroy();
    component = null;
    modalRef.close();
    modalRef = null;
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('Open modal', () => {
    component.openModal();
    expect(modalService.open).toHaveBeenCalled();
  });

  it('Open modal with click on the button', () => {
    fixtureMainComponent.debugElement.query(By.css('#openModalBtn')).triggerEventHandler("click", null);
    fixtureMainComponent.detectChanges();
    expect(component.openModal).toHaveBeenCalled();
    expect(modalService.open).toHaveBeenCalled();
  });

  it('Check element in modal', () => {
    fixtureMainComponent.debugElement.query(By.css('#openModalBtn')).triggerEventHandler("click", null);
    fixtureMainComponent.detectChanges();
    // Return null
    const h4DebEl : DebugElement = fixtureMainComponent.debugElement.query(By.css('h4'));
    // const h4HtmlEl : HTMLElement = h4DebEl.nativeElement;
    // expect(h4element.textContent).toEqual("Header :");
  });

  /**
   * Check the dismiss method ESC 
   * To do same for BACKDROP_CLICK, ...
   */
  it('Dimiss with ESC', () => {
    component.openModal();
    modalRef.dismiss(ModalDismissReasons.ESC);
    expect(component.dismissReason).toHaveBeenCalled(); 
    expect(component.dismissReasonEsc).toHaveBeenCalled();
  });

});

ModalComponentComponent.component.ts

import { Component, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-modal-component',
  template: `
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Header : {{person.lastName}} {{person.name}}</h4>
    <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    Content modal
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-outline-dark" (click)="activeModal.close('Save click')">Save</button>
  </div>
  `
})

export class ModalComponentComponent {
  @Input() person;
  constructor(public activeModal: NgbActiveModal) { }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import { AppComponent } from './app.component';
import { MainComponentComponent } from './main-component/main-component.component';
import { ModalComponentComponent } from './modal-component/modal-component.component';

@NgModule({
  declarations: [
    AppComponent,
    MainComponentComponent,
    ModalComponentComponent
  ],
  imports: [
    BrowserModule,
    NgbModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [ ModalComponentComponent ],
  schemas : [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }

感谢您的帮助和时间,

此致,

标签: javascriptangularkarma-jasmine

解决方案


Q1 如何确定 modal 真的是 open 或者 function 真的被调用了?

  • 真正开放:不是你测试的关注点,应该在 ng-bootstrap 中测试
  • 或真正调用的函数:是测试说它是打开的,然后是它的打开:)

Q2 - 调试元素:不知道

模拟活动模态

 const activeModal: any = jasmine.createSpyObj('activeModal', ['close', 'dismiss']);

添加到测试平台提供程序

  { provide: NgbActiveModal, useValue: activeModal }

推荐阅读