我正在使用角度4 app中的jasmine编写单元测试用例。我每次都得到'无法读取属性'nativeElement'的'null',我不知道为什么。我在下面尝试做的是检查按钮是否被点击。以下是我的代码文件。
import { Http, Response, RequestOptions, Request, ConnectionBackend } from '@angular/http';
import { DataShareService } from '../core/services/data-share.service';
import { scooterRepairService } from './services/scooterRepair.service';
import { Router } from '@angular/router';
import { scooterRepairUnitComponent } from './scooter-repair-Unit.component';
import { TestBed, ComponentFixture, async, inject } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { SelectItem, CheckboxModule, CalendarModule, MultiSelectModule } from 'primeng/primeng';
import { CoreUIModule } from 'core-ui';
import { RouterTestingModule } from '@angular/router/testing';
describe('scooterRepairUnitComponent', () => {
let fixture: ComponentFixture<scooterRepairUnitComponent>;
let component: any;
let http: Http;
let dataShare: DataShareService;
let scooterRepairService: scooterRepairService;
let router: Router
let comp = new scooterRepairUnitComponent(http, dataShare, scooterRepairService, router);
// service stubs to mock services
let MockResponse = {
navigate: jasmine.createSpy('Response')
}
let MockRequestOptions = {
navigate: jasmine.createSpy('RequestOptions')
}
let MockRequest = {
navigate: jasmine.createSpy('Request')
}
let MockConnectionBackend = {
navigate: jasmine.createSpy('ConnectionBackend')
}
// async beforeEach
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [scooterRepairUnitComponent], // declare the test component
imports: [FormsModule, CheckboxModule, CalendarModule, MultiSelectModule, CoreUIModule, RouterTestingModule],
schemas: [NO_ERRORS_SCHEMA],
providers: [Http,
{ provide: Response, useValue: MockResponse },
{ provide: RequestOptions, useValue: MockRequestOptions },
{ provide: Request, useValue: MockRequest },
{ provide: ConnectionBackend, useValue: MockConnectionBackend },
DataShareService,
scooterRepairService]
})
.compileComponents(); // compile template and css
fixture = TestBed.createComponent(scooterRepairUnitComponent);
component = fixture.componentInstance;
}));
// synchronous beforeEach -- used if component is having external templates
beforeEach(() => {
comp = new scooterRepairUnitComponent(http, dataShare, scooterRepairService, router);
});
it('should', async(() => {
spyOn(component, 'onClearClick');
let de: DebugElement = fixture.debugElement.query(By.css('#clearSearch'));
let el: HTMLElement = de.nativeElement;
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(component.onClearClick).toHaveBeenCalled();
})
}));
import { Component, OnInit, ViewEncapsulation, ElementRef, Output, Input } from '@angular/core';
import { Pipe, PipeTransform, Inject } from '@angular/core';
import { Http, Response, RequestOptions, Request, ConnectionBackend } from '@angular/http';
import { IScooter } from './models/Scooter';
import { IShop } from './models/shop';
import { ISelectedTab } from './models/selectedTab';
import { RestClientService, EnvironmentService } from 'core-shared/core.service';
import { Observable } from 'rxjs/Observable';
import { DataShareService } from '../core/services/data-share.service';
//mport { CommonService } from '../shared/services/common.service';
import { NgForm, FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { SelectItem } from 'primeng/primeng';
import { ScooterRepairService } from './services/ScooterRepair.service';
@Component({
selector: 'Scooter-repair-Unit',
templateUrl: './Scooter-repair-Unit.component.html',
styleUrls: ['./Scooter-repair-Unit.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class ScooterRepairUnitComponent {
selectedTab: string = 'ScooterRepair';
showRepairUnitSelection: boolean=true;
showScooterRepairUnit:boolean=true;
showShopRepairUnit:boolean=false ;
showMissingRepairUnit:boolean=false;
showAddScooterRepairUnit:boolean=false;
showAddShopRepairUnit: boolean = false;
showScooterRepairUnitResultGrid = false;
ScooterRepairUnitSearchTitle= 'Search Scooter Repair Unit Threshold';
ScooterRepairUnitSearchResult= 'Scooter Repair Unit Results';
shopRepairUnitSearchTitle= 'Search Shop Repair Unit Threshold';
shopRepairUnitSearchResult= 'Shop Repair Unit Results';
missingRepairUnitSearchResult= 'Missing Repair Unit Results';
updateRepairUnitTitle= 'Update Results';
gridPageSize: number;
Scooters: IScooter[];
errorMessage: string;
ScooterRepairs: IScooter[] = [];
canSubmitAuditRequest = false;
totalScooterRepairRecords: number;
isValidated: boolean;
isSubmittedSuccessfully: boolean;
clearScooterRepairSearch: boolean;
constructor(private http: Http,
private dataShare: DataShareService,
// private commonService: CommonService,
private ScooterRepairService: ScooterRepairService,
// private loggerService: LoggerService,
// private storageService: StorageService,
private router: Router) {
this.gridPageSize = 10;
}
onSelectionChange(tabname) {
this.SetTab(tabname);
}
private SetTab(tabname: string){
this.showScooterRepairUnit = false;
this.showShopRepairUnit = false ;
this.showMissingRepairUnit = false;
if (tabname === 'ScooterRepair') {
this.showScooterRepairUnit = true;
}
if (tabname === 'shopRepair') {
this.showShopRepairUnit = true ;
}
if (tabname === 'missingRepair') {
this.showMissingRepairUnit = true;
}
}
ngOnInit(): void {
this.setBreadCrumb();
this.setLastSearch();
this.selectedTab = 'ScooterRepair';
}
private setBreadCrumb() {
// Setting Page title
this.dataShare.setData('appTitle', 'Repair Unit Maintenance');
// Setting Breadcrumb
this.dataShare.setData('breadcrumbItems', [
{ label: 'Business Rule Engine' },
{ label: 'Repair Unit Maintenance', url: '/cra' }
]);
}
onClearClick()
{
this.clearScooterRepairSearch = true;
}
}
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" *ngIf="showRepairUnitSelection">
<div class="panel ">
<form class="form-horizontal scooterUnitSearchForm" #requestauditsearchform="ngForm" action="#" >
<div class="form-group ">
<div class="col-lg-12 col-xs-12 clearfix">
<label for="" class=" col-lg-2 col-xs-6 control-label">
Search By:
</label>
<label class="control-label radio-inline">
<input type="radio" id="showscooter" name="mainTab" [(ngModel)]="selectedTab" value="scooterRepair" (change)="onSelectionChange(selectedTab)"
[checked]="selectedTab === scooterRepair">
scooter Repair Unit
</label>
<label class=" control-label radio-inline">
<input type="radio" name="mainTab" id="showShop" [(ngModel)]="selectedTab" value="shopRepair" (change)="onSelectionChange(selectedTab)"
[checked]="selectedTab === shopRepair">
Shop Repair Unit
</label>
<label class=" control-label radio-inline">
<input type="radio" name="mainTab" id="showMissingscooter" [(ngModel)]="selectedTab" value="missingRepair"(change)="onSelectionChange(selectedTab)"
[checked]="selectedTab === missingRepair">
Missing scooter Repair Unit
</label>
</div>
</div>
</form>
</div>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="scooterRepairUnitSearchTitle" *ngIf="showscooterRepairUnit">
<scooter-repair-Unit-search
(requestscooterRepairSearch)="searchscooterRepairRequest($event)"
[clearscooterRepairSearch]="clearscooterRepairSearch"
>
</scooter-repair-Unit-search>
</collapse-expand-frame>
</div>
<div class="row" style="Margin-bottom:20px" *ngIf="showscooterRepairUnit">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 ">
<div class="form-group">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 text-sm-right text-md-right text-right">
<button pButton type="button" label="Add Repair Unit" (click)="onAddscooterRepair()" class="btn btn-default"></button>
<button pButton type="button" label="Search" class="btn btn-default"></button>
<button pButton type="button" label="Clear" (click)="onClearClick()" class="btn btn-default"></button>
</div>
</div>
</div>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12 clearfix" *ngIf="showAddscooterRepairUnit">
<collapse-expand-frame >
<add-scooter-repair-Unit
(requestscooterRepairSearch)="searchscooterRepairRequest($event)"
>
</add-scooter-repair-Unit>
</collapse-expand-frame >
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="scooterRepairUnitSearchResult" *ngIf="showscooterRepairUnit">
<scooter-repair-Unit-search-grid
>
</scooter-repair-Unit-search-grid >
</collapse-expand-frame>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="updateRepairUnitTitle" *ngIf="showscooterRepairUnit">
<update-scooter-repair-Unit
>
</update-scooter-repair-Unit>
</collapse-expand-frame>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="shopRepairUnitSearchTitle" *ngIf="showShopRepairUnit">
<shop-repair-Unit-search
>
</shop-repair-Unit-search>
</collapse-expand-frame>
</div>
<div class="row" style="Margin-bottom:20px" *ngIf="showShopRepairUnit">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 ">
<div class="form-group">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 text-sm-right text-md-right text-right">
<button pButton type="button" label="Add Repair Unit" (click)="onAddShopRepair()" class="btn btn-default"></button>
<button pButton type="button" label="Search" class="btn btn-default"></button>
<button pButton type="button" label="Clear" id="clearSearch" (click)="onClearClick()" class="btn btn-default"></button>
</div>
</div>
</div>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
*ngIf="showAddShopRepairUnit">
<add-shop-repair-Unit
>
</add-shop-repair-Unit>
</collapse-expand-frame>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="shopRepairUnitSearchResult" *ngIf="showShopRepairUnit">
<shop-repair-Unit-search-grid
>
</shop-repair-Unit-search-grid >
</collapse-expand-frame>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="updateRepairUnitTitle" *ngIf="showShopRepairUnit">
<update-shop-repair-Unit
>
</update-shop-repair-Unit>
</collapse-expand-frame>
</div>
<div class="col-lg-12 col-mg-12 col-sm-12 col-xs-12">
<collapse-expand-frame
[frametitle]="missingRepairUnitSearchResult" *ngIf="showMissingRepairUnit">
<missing-repair-Unit-search-grid
>
</missing-repair-Unit-search-grid>
</collapse-expand-frame>
</div>
我遇到了同样的问题,我将问题追溯到div上的* ngIf语句
你必须在测试中为'showscooterRepairUnit'设置一个值,否则它将假定为false并将css元素设置为null,导致debugElement为null
解决方法
如果您在元素中使用*ngIf
,请改用hidden
。
<h2 [hidden]="hideItem"> My Message</h2>
当jasmine在DOM中找不到该元素时,会导致此错误。最常见的情况是在模板中使用*ngIf
。根据docs,* ngIf会破坏DOM中的元素,如果表达式的计算结果为false。
我有一个类似的问题,能够通过使用页面对象和querySelectorAll来解决它
fixture.nativeElement.querySelectorAll('button');
HTML:
<div *ngIf="isAbbreviationsAvailable(element.description); then caseA else caseB"></div>
<ng-template #caseA>
<div>
<ng-template #popContent class="popover">
<span id="glossary" > {{element.description| glossary:glossaryDescription}}</span>
<button class="close" (click)="p.close()"><img src="assets/icons/close.svg"></button>
</ng-template>
<button class="popoverLink" [ngbPopover]="popContent" [autoClose]="false"
triggers="manual" #p="ngbPopover" (click)="p.open()" placement="top-right bottom-right" container="body"
html="true" >
{{split(element.description)[0]}}
</button>
/{{split(element.description)[1]}}
</div>
</ng-template>
<ng-template #caseB>{{element.description}}</ng-template>
测试用例:
const template: HTMLElement[] = fixture.nativeElement.querySelectorAll('button');
let link: HTMLElement = template[8]
expect(link.textContent.trim()).toEqual('ACC');