我正在编写一个非常基本的单元测试。我不知道该怎么办。我尝试了很多事情,但无法解决此错误。除第一次测试外,其他测试均失败。
规范文件
fdescribe("New TestOrder ICD10 Code Selection Modal Component", () => {
let component: NewTestOrderICD10CodeSelectionModalComponent;
let fixture: ComponentFixture<NewTestOrderICD10CodeSelectionModalComponent>;
let de: DebugElement;
let element: HTMLElement;
beforeEach(async (() => {
TestBed.configureTestingModule({
declarations: [
NewTestOrderICD10CodeSelectionModalComponent
],
imports: [
ReactiveFormsModule,
NgbModule.forRoot(),
FormsModule,
RouterTestingModule,
StoreModule.forRoot({}),
HttpModule
],
providers: [
AuthService,
UtilService,
SessionService,
TestOrderService,
{provide: APP_BASE_HREF, useValue : '/'}
],
schemas: [
NO_ERRORS_SCHEMA
]
}).compileComponents();
}));
beforeEach(async() => {
fixture = TestBed.createComponent(NewTestOrderICD10CodeSelectionModalComponent);
component = fixture.debugElement.componentInstance;
de = fixture.debugElement.query(By.css('.new-test-order-icd10-code-selection-modal.component'));
element = de.nativeElement;
fixture.detectChanges();
});
it("New Test Order ICD10 Coed Selection Modal Should be created", () => {
expect(component).toBeTruthy();
});
it('Should have a title', () => {
expect(element.textContent).toContain(component.title);
});
});
这是mew-test-order-icd10-code-selection-modal.component.ts文件
// Angular DOM
import {Component, ViewChild, TemplateRef, OnDestroy} from "@angular/core";
// Angular Hooks
import {OnInit, AfterViewInit} from "@angular/core";
// Redux Store
import {Store} from "@ngrx/store";
import {SetTestOrderCodeSelectionSession} from "../../../../shared";
// Models
import {
TestOrder,
TestOrderCodeSelectionSession
} from "../../../../shared/models";
// Third Party Services
import {NgbModal, NgbModalOptions} from "@ng-bootstrap/ng-bootstrap";
import {ActivatedRoute, Router} from "@angular/router";
import * as lodash from "lodash";
// Services
import {TestOrderService} from "../../../../shared";
import {SetTestOrderICDCodes} from "../../../../shared/actions/test-order.actions";
import {Subscription} from "rxjs/Subscription";
@Component({
selector: "app-new-test-order-icd10-code-selection-modal",
templateUrl: "./new-test-order-icd10-code-selection-modal.component.html",
styleUrls: ["./new-test-order-icd10-code-selection-modal.component.scss"]
})
export class NewTestOrderICD10CodeSelectionModalComponent
implements OnInit, AfterViewInit, OnDestroy {
@ViewChild("icd10codes") template: TemplateRef<any>;
public codeSelectionSession: TestOrderCodeSelectionSession;
public icdCodes: Array<ICDCode>;
public newIcdCodesArray = [];
public modalRef: any;
title: string = "Please Select ICD-10 Codes";
public serviceSubscription: Subscription;
private selectedCodes: Array<ICDCode> = [];
private options: NgbModalOptions = {
backdrop: "static",
windowClass: "icd10-codes",
container: "app-new-test-order-icd10-code-selection-modal",
keyboard: false,
size: "lg"
};
constructor(
private modalService: NgbModal,
private testOrderService: TestOrderService,
public router: Router,
private route: ActivatedRoute,
private store: Store<any>
) {
}
ngOnInit() {
this.serviceSubscription = this.testOrderService.getICDCodes().subscribe((codes: Array<ICDCode>) => {
this.icdCodes = codes;
});
this.store
.select("codeSelectionSession")
.subscribe((session: TestOrderCodeSelectionSession) => {
// checks for null and undefined
if (session == null) {
this.store.select("testOrder").subscribe((testOrder: TestOrder) => {
this.codeSelectionSession = new TestOrderCodeSelectionSession();
this.store.dispatch(
new SetTestOrderCodeSelectionSession(this.codeSelectionSession)
);
});
} else {
this.codeSelectionSession = session;
}
});
}
ngAfterViewInit() {
setTimeout(() => {
this.modalRef = this.modalService.open(this.template, this.options);
});
this.serviceSubscription = this.route.queryParams.subscribe(params => {
//for selected icd
if(params.selectedIcdCodes) {
this.selectedCodes = JSON.parse(params.selectedIcdCodes);
}
this.codeSelectionSession.SelectedCodes = lodash.concat(this.codeSelectionSession.SelectedCodes, this.selectedCodes);
//for icd id
this.codeSelectionSession.ICDCodeIds = lodash.concat(this.codeSelectionSession.ICDCodeIds, params.icd10Codes);
this.newIcdCodesArray = lodash.concat(this.newIcdCodesArray, params.icd10Codes);
this.codeSelectionSession.ICDCodeIds = lodash.uniq(this.codeSelectionSession.ICDCodeIds);
let difference = lodash.difference(this.codeSelectionSession.ICDCodeIds, this.newIcdCodesArray);
this.codeSelectionSession.ICDCodeIds = lodash.differenceBy(this.codeSelectionSession.ICDCodeIds, difference); //remove the difference
});
}
onCheckboxUpdate(selected: boolean, icdCode: ICDCode) {
this.codeSelectionSession.ICDCodeIds = this.codeSelectionSession.ICDCodeIds.filter(
codeId => codeId !== icdCode.Id
);
this.codeSelectionSession.SelectedCodes = this.codeSelectionSession.SelectedCodes.filter(
code => code.Id !== icdCode.Id
);
if (selected) {
this.codeSelectionSession.ICDCodeIds.push(icdCode.Id);
this.codeSelectionSession.SelectedCodes.push(icdCode);
}
}
ngOnDestroy() {
setTimeout(() => {
this.modalRef.close();
});
this.serviceSubscription.unsubscribe();
}
}
第二项测试也应该通过。我不知道我在做什么错。
我尝试过的另一种方法。 这是我的specfile,它向我显示了无法读取null的属性'nativeElement'
beforeEach(async() => {
fixture = TestBed.createComponent(NewTestOrderICD10CodeSelectionModalComponent);
component = fixture.debugElement.componentInstance;
// de = fixture.debugElement.query(By.css('.h5')).nativeElement.innerText;
// element = de.nativeElement;
fixture.detectChanges();
});
it("New Test Order ICD10 Coed Selection Modal Should be created", () => {
expect(component).toBeTruthy();
});
it('Should have a title', () => {
//expect(element.textContent).toContain(component.title);
fixture.detectChanges();
const de = fixture.debugElement.query(By.css('.modal-title')).nativeElement.innerText;
expect(de).toContain(component.title);
});
这是我的html文件
<ng-template #icd10codes let-c="close" let-d="dismiss">
<form role="form" #icdCodeSelectionForm="ngForm" novalidate>
<div class="modal-header">
<span class="material-icons clickable text-dimmed" (click)="onBackButtonClick()" [routerLink]="['/test-order/create/details']">arrow_back</span>
<h5 class="modal-title">{{title}}</h5>
<button type="button" class="btn square-btn" (click)="update()">ADD CODES</button>
<div class="icd-search">
<app-search-list (onSearchInputUpdate)="onSearchUpdate($event)"></app-search-list>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-3 text-dimmed pad-left-45">ICD-10 Codes</div>
<div class="col-8 text-dimmed">Description</div>
<div class="col-1"></div>
</div>
<div class="list-border"></div>
<div class="code-list">
<div class="row" *ngFor="let icdCode of icdCodes; let odd = odd" [ngClass]="{'isOdd': odd}">
<div class="col-3 pad-left-45">{{ icdCode.Code }}</div>
<div class="col-8 text-dimmed">{{ icdCode.ShortDescription }}</div>
<div class="col-1">
<label class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[ngModel]="codeSelectionSession.ICDCodeIds.indexOf(icdCode.Id) !== -1"
(ngModelChange)="onCheckboxUpdate($event, icdCode)"
[name]="icdCode.Id">
<span class="custom-control-indicator"></span>
</label>
</div>
</div>
</div>
</div>
</form>
</ng-template>
答案 0 :(得分:0)
在element = de.nativeElement;
中执行beforeEach()
时,element
包含该值。
而且可以通过
it('Should have a title', () => {
expect(element).toContain(component.title);
});
在de = fixture.debugElement.query(By......
中,de
将是HTMLNode
,对此使用nativeElement
将为您提供内容。或者,您可以直接使用de.textContent
来获取元素de
的内容。
答案 1 :(得分:0)
我的建议是删除
de = fixture.debugElement.query(By.css('.new-test-order-icd10-code-selection-modal.component'));
从beforeEach
块开始。请注意,您正在尝试在fixture.detectChanges();
之前获得此值,所以我认为这不是一个好方法。您必须确保在完成所有角度更改后获得HTML值。试试:
it('Should have a title', () => {
fixture.detectChanges(); // No need to add this line if you have it in "beforeEach" block
const de = fixture.debugElement.query(By.css('.new-test-order-icd10-code-selection-modal.component'));
const element = de.nativeElement;
expect(element.textContent).toContain(component.title);
});
要测试ng-template
,您必须采取其他措施:
app.component.html
<div id="title">
{{title}}
</div>
<ng-template #content
let-modal
id="ng-modal">
<div class="modal-header dark-modal">
Header
</div>
<div class="justify-content-center flex-column flex-md-row list-inline">
Body
</div>
</ng-template>
app.component.ts
import { Component, ViewChild, TemplateRef } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'AngularProj';
@ViewChild('content') modalRef: TemplateRef<any>;
}
您需要以略有不同的方式写入spec
文件:
app.component.spec.ts
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { ViewChild, Component, OnInit, AfterContentInit, TemplateRef } from '@angular/core';
import { By } from '@angular/platform-browser';
@Component({
template: `
<ng-container *ngTemplateOutlet="modal"> </ng-container>
<app-root></app-root>
`,
})
class WrapperComponent implements AfterContentInit {
@ViewChild(AppComponent) appComponentRef: AppComponent;
modal: TemplateRef<any>;
ngAfterContentInit() {
this.modal = this.appComponentRef.modalRef;
}
}
describe('AppComponent', () => {
let app: AppComponent;
let fixture: ComponentFixture<WrapperComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [WrapperComponent, AppComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(WrapperComponent);
const wrapperComponent = fixture.debugElement.componentInstance;
app = wrapperComponent.appComponentRef;
fixture.detectChanges();
});
it('should create the app', async(() => {
expect(app).toBeDefined();
}));
it('should have title in HtmL ', async(() => {
const titleText = (fixture.debugElement.nativeElement.querySelector('#title').innerText);
expect(titleText).toBe('AngularProj');
}));
it('should have Header in HtmL ', async(() => {
const headerText = (fixture.debugElement.queryAll(By.css('.modal-header.dark-modal'))[0].nativeElement.innerText);
expect(headerText).toBe('Header');
}));
});
app-root
)包装了WrapperComponent
。app-root
具有ng-template
,因此它不会自己呈现。由于我们需要呈现app.component
的这一部分,因此这会造成棘手的情况。ng-template
暴露@ViewChild('content') modalRef: TemplateRef<any>;
,然后使用它在WrapperComponent
内部进行渲染。 我知道这似乎是一种hack,但是在我浏览的所有文章中,这都是我们可以实现的方式。