Jos*_*rth 7 karma-jasmine angular angular-test
我有一个带标签的组件。我需要导航到一个选项卡,然后测试可查看的输入等。我可以从控制台日志中看到我正在执行的操作正在调用我正在使用以下过程进行监视的函数。我还可以看到这是以正确的顺序发生的。
不幸的是,这会产生一个没有错误的成功测试,根据 ng test 在测试中没有发现任何期望。(规格没有期望)
将期望放在 whenStable 命令之外会使期望在模糊命令之前运行。
it('should call to save changes when project name is blurred',
fakeAsync(() => {
component.ngOnInit();
tick();
const tabLabels = fixture.debugElement.queryAll(By.css('.mat-tab-label'));
console.log(tabLabels);
tabLabels[1].triggerEventHandler('click', null);
fixture.detectChanges();
fixture.whenStable().then(() => {
const projectName = fixture.debugElement.query(By.css('#projectName'));
console.log(projectName);
let mySpy = spyOn(component, 'saveProject');
projectName.triggerEventHandler('blur', null);
console.log('Lowered expectations');
expect(mySpy).toHaveBeenCalled();
});
})
);
Run Code Online (Sandbox Code Playgroud)
这是与测试相关的 HTML。
<!-- HEADER -->
<div class="header accent" fxLayout="row"></div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content">
<!-- CENTER -->
<div class="center p-24" fusePerfectScrollbar>
<!-- CONTENT -->
<div class="content p-24" style="box-shadow:0px 0px 0px rgba(0,0,0,0) !important;">
<mat-tab-group fxFlex="80%"
style="margin:0px 10%">
<mat-tab id="projectSelectionTab" label="Project Selection">
<div fxFlex="80%"
fxLayout="column"
style="margin:0px 10%"
*ngIf="versionList && projectList">
<h1 class="mt-32 mb-20">Select a Project</h1>
<mat-divider></mat-divider>
<div *ngIf="projectList.length==0">
You currently have no designs. Go to the marketplace and select a design to add to your list of projects.
</div>
<table class="displayTable">
<tr (click)="setCurrentProject( project ) "
target="_blank"
class="projectRow"
[ngClass]="{'currentItem' : project==currentProject}"
*ngFor="let project of projectList">
<td class="mat-subheading-2"
style="width:10%">
<mat-icon style="cursor:pointer"
matTooltip="Open in design studio"
[routerLink]="['/designStudio/project/'+project.uid]">
color_lens
</mat-icon>
<mat-icon style="cursor:pointer"
matTooltip="View Quotes for this project"
[routerLink]="['/invoice/'+versionList[versionList.length-1]['uid']]">
attach_money
</mat-icon>
</td>
<td class="mat-subheading-2"
style="width:25%">
{{ project.name }}
</td>
<td class="mat-subheading-2"
style="width:20%">
{{ project.dateCreated | date:'short' }}
</td>
<td class="mat-body-1" >
<span style="font-weight:bold; margin-right:10px;">Type : {{project.designType}}</span>
<span style="font-weight:bold; margin-right:10px;">Versions : {{project.versions.length}}</span>
{{ project.description }}
</td>
</tr>
</table>
</div>
</mat-tab>
<mat-tab id="projectDataTab" label="Project Data" flex="100%">
<div flex="100%"
layout="column"
style="width:100%"
*ngIf="currentProject.uid">
<h2 class="mt-32 mb-20">
Project Data -
<mat-icon style="cursor:pointer"
matTooltip="Open in design studio"
[routerLink]="['/designStudio/project/'+currentProject.uid]">
color_lens
</mat-icon>
</h2>
<!-- TOP ROW OF PROJECT DATA -->
<div fxLayout="row" fxLayoutAlign="center" flex="100%">
<div fxFlex="50%"fxLayout="column" class="text-center">
<mat-form-field appearance="outline" floatLabel="always" class="w-100-p">
<mat-label>Project Name</mat-label>
<input matInput
id="projectName"
class="form-control"
placeholder="Product Name"
name="projectName"
#projectName="ngModel"
[(ngModel)]="currentProject['name']"
(blur)="saveProject()"
minlength="5"
maxlength="150"
required>
</mat-form-field>
<div [hidden]="projectName.valid || projectName.pristine || !projectName.errors?.minlength"
class="alert alert-danger">
Project name is required with at least 5 characters
</div>
<mat-form-field style="min-height:190px" appearance="outline" floatLabel="always" class="w-100-p">
<mat-label>Project Description</mat-label>
<textarea style="min-height:190px"
matInput
id="projectDescription"
placeholder="Product Description"
name="description"
#projectDescription="ngModel"
[(ngModel)]="currentProject['description']"
(blur)="saveProject()"
rows="5"
required
minlength="25">
</textarea>
</mat-form-field>
<div [hidden]="projectDescription.valid || projectDescription.pristine || !projectDescription.errors?.minlength"
class="alert alert-danger">
Project description is required with at least 25 characters
</div>
</div>
<div fxFlex="50" fxLayout="column" fxLayoutAlign="center center">
<div fxFlex="80" style="margin:0px 10%">
<img [src]="(designImageUrl | async)">
</div>
<div fxLayout="row"
fxLayoutAlign="center"
class="w-80-p">
<button mat-raised-button
color="primary"
*ngIf="changesExist"
(click)="saveProject(); changesExist=false;"
style="margin:10px 25%; width:50%">
Save Project Changes
</button>
</div>
</div>
</div>
</div>
<!-- / TOP ROW OF PROJECT DATA -->
</mat-tab>
<mat-tab id="versionDataTab" label="Version Data">
<div layout="column"
flex="100%"
style="width:100%"
*ngIf="currentProject !== undefined">
<h2 class="mt-32 mb-20">Version Data</h2>
<!-- Row showing button to create default version -->
<div fxLayout="row"
fxLayoutAlign="center center"
flex="100%">
<div fxFlex="20" style="margin:20px 5%">
<button mat-stroked-button
color="accent"
(click)="createNewVersion('default')">
New version (default)
</button>
</div>
</div>
<!-- Row showing the version list -->
<div fxLayout="row" fxLayoutAlign="center" flex="100%">
<table class="displayTable"
fxFlex="60" style="margin:0px 5%">
<thead>
<tr>
<th>VERSION NUMBER AND NAME</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let version of versionList; index as j"
class="projectRow"
[ngClass]="{'currentItem' : version==currentVersion}"
(click)="onVersionSelected( j )">
<td>{{j+1}} - {{version.name}}</td>
<td>
<mat-icon style="cursor:pointer"
matTooltip="View Quotes for this version"
[routerLink]="['/invoice/'+version['uid']]">
attach_money
</mat-icon>
<mat-icon style="cursor:pointer"
matTooltip="Make copy as latest version"
(click)="createNewVersion( j )">
add_circle
</mat-icon>
</td>
</tr>
</tbody>
</table>
<!--
<div fxFlex="40" style="margin:0px 5%">
<mat-form-field class="w-100-p ml-10-p mt-20 form-group">
<mat-label>Select a version to see the details</mat-label>
<mat-select (selectionChange)="onVersionSelected(versionIndex)"
name="versionIndex"
#name="ngModel"
[(ngModel)]="versionIndex">
<mat-option *ngFor="let version of versionList; index as i" [value]="i">
{{i+1}} - {{version.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayoutAlign="center center" fxFlex="40" style="margin:0px 5%">
<button mat-button class="red-900 mt-8" *ngIf="currentVersion.latest">Submit for purchase</button>
<button mat-button class="primary mt-8" *ngIf="!currentVersion.latest">Recreate as latest version</button>
</div>
-->
</div>
<div fxLayout="row" fxLayoutAlign="center" flex="100%">
<!-- VERSIONS DATA -->
<div fxLayout="column"
class="mt-32"
flex="45%"
style="width:40%; margin:0px 5%">
<h3>Data</h3>
<div fxLayout="row"
class="mt-20 mb-32">
<div fxFlex="50">
Estimated price - {{currentVersion.price}}
</div>
<div fxFlex="50">
Date Created - {{currentVersion.dateCreated | date:'short'}}
</div>
</div>
<mat-form-field appearance="outline"
floatLabel="always"
class="w-100-p">
<mat-label>Version Name</mat-label>
<input matInput
class="form-control"
placeholder="Version Name"
name="vName"
#versionName="ngModel"
(blur)="versionChangesExist=true"
[(ngModel)]="currentVersion.name"
required
minlength="5"
maxlength="150">
</mat-form-field>
<div [hidden]="versionName.valid || versionName.pristine || !versionName.errors?.minlength"
class="alert alert-danger">
Version name is required with at least 5 characters
</div>
<mat-form-field appearance="outline"
floatLabel="always"
class="w-100-p">
<mat-label>Version Description</mat-label>
<textarea matInput
placeholder="Version Description"
class="form-control"
name="versionDescription"
#versionDescription="ngModel"
(blur)="versionChangesExist=true"
[(ngModel)]="currentVersion.description"
rows="5"
required>
</textarea>
</mat-form-field>
<div [hidden]="versionDescription.valid || versionDescription.pristine || !versionDescription.errors?.minlength"
class="alert alert-danger">
Version description is required with at least 25 characters
</div>
</div>
<!--/ VERSION DATA -->
<!-- MEASUREMENT LIST -->
<div fxLayout="column"
class="mt-32"
flex="45%"
style="width:40%; margin:0px 5%">
<div fxLayout="row" fxLayoutAlign="center" flex="100%">
<button mat-raised-button
color="primary"
*ngIf="versionChangesExist"
(click)="saveVersion(); versionChangesExist=false;"
那是因为它whenStable()不能很好地与fakeAsync()函数配合,因为它是async函数的东西。
为了
fakeAsync()有效地使用,必须依赖tick()或flush()。
也许像这样改变你的测试用例应该可行。
it('should call to save changes when project name is blurred',
fakeAsync(() => {
component.ngOnInit();
tick();
const tabLabels = fixture.debugElement.queryAll(By.css('.mat-tab-label'));
console.log(tabLabels);
tabLabels[1].triggerEventHandler('click', null);
fixture.detectChanges();
flushMicrotasks(); // or alternatively flush() or tick(250);
fixture.detectChanges();
const projectName = fixture.debugElement.query(By.css('#projectName'));
console.log(projectName);
let mySpy = spyOn(component, 'saveProject');
projectName.triggerEventHandler('blur', null);
console.log('Lowered expectations');
expect(mySpy).toHaveBeenCalled();
})
);
Run Code Online (Sandbox Code Playgroud)
替换
flush()为flushMicrotasks()后跟fixture.detectChanges(),它将允许在解决 Promise 后使用响应更新 DOM。再想一想,您也可以将这种方法与flush()或tick()一起使用。