如何在 Jasmine 单元测试中触发 ngModelChange 事件?
How to trigger ngModelChange event in Jasmine unit testing?
我正在使用以下代码在 Angular 应用程序中使用 Jasmine 执行单元测试。
test.component.html:
<p-treeTable [value]="employees" [columns]="cols" class="employeestreetable">
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of cols" style="width:30px">
{{col.header}}
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
<tr [ttRow]="rowNode">
<td width="30" class="text-right" ttEditableColumn>
<p-treeTableToggler [rowNode]="rowNode">
</p-treeTableToggler>
<p-treeTableCellEditor>
<ng-template pTemplate="input">
<input type="text" pInputText [(ngModel)]="rowData['name']" />
</ng-template>
<ng-template pTemplate="output">
<input type="text" pInputText [(ngModel)]="rowData['name']">
</ng-template>
</p-treeTableCellEditor>
</td>
<td width="30" class="text-right">
<p-treeTableCellEditor>
<ng-template pTemplate="input">
<input type="text" pInputText [(ngModel)]="rowData['salary']" (ngModelChange)="calculateTotalSalary(rowNode)" />
</ng-template>
<ng-template pTemplate="output">
<input type="text" pInputText [(ngModel)]="rowData['salary']">
</ng-template>
</p-treeTableCellEditor>
</td>
<td width="30" class="text-right" ttEditableColumn>
<p-treeTableCellEditor>
<ng-template pTemplate="input">
<input type="text" pInputText [(ngModel)]="rowData['incentive']" (ngModelChange)="calculateTotalSalary(rowNode)" />
</ng-template>
<ng-template pTemplate="output">
<input type="text" pInputText [(ngModel)]="rowData['incentive']">
</ng-template>
</p-treeTableCellEditor>
</td>
<td width="30" class="text-right">
<span>{{rowData['totalsalary']}}</span>
</td>
</tr>
</ng-template>
</p-treeTable>
test.component.ts:
import { Component, OnInit, ViewChild } from '@angular/core';
import { TreeNode } from 'primeng/primeng'
import { ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'test-app',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent {
cols = [
{ field: 'name', header: 'Name' },
{ field: 'salary', header: 'Salary' },
{ field: 'incentive', header: 'Incentive' },
{ field: 'totalsalary', header: 'Total Salary' }
];
employees: TreeNode[] = [
{
"data": {
"name": "Alex",
"salary": 10000,
"incentive": 5000,
"totalsalary": 15000
},
"children": [
{
"data": {
"name": "George",
"salary": 8000,
"incentive": 2000,
"totalsalary": 10000
},
}
]
},
{
"data": {
"name": "Robert",
"salary": 18000,
"incentive": 10000,
"totalsalary": 280000
},
"children": [
{
"data": {
"name": "John",
"salary": 7000,
"incentive": 5000,
"totalsalary": 12000
}
}
]
}
];
calculateTotalSalary(rownode) {
rownode.node.data.totalsalary = +rownode.node.data.salary + +rownode.node.data.incentive;
}
}
test.component.spec.ts:
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import {
TestComponent
} from "./test.component";
import { FormsModule, NgModel } from '@angular/forms';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { MessageService } from 'primeng/api';
import { TreeNode } from 'primeng/api';
import { TreeTableModule } from 'primeng/treetable';
import { By } from '@angular/platform-browser';
import { InputTextModule } from 'primeng/inputtext';
describe('TestComponent', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule,
FormsModule, TreeTableModule, InputTextModule
],
declarations: [ TestComponent ],
providers: [ ],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
beforeEach(fakeAsync(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
tick();
}));
it('should update total salary amount', fakeAsync(() => {
spyOn(component, 'calculateTotalSalary');
const editableTreeTableEl = fixture.debugElement.query(By.css(".employeestreetable"));
let editableColumns = editableTreeTableEl.queryAll(By.css(".ui-editable-column input"));
const el = editableColumns[0].nativeElement;
const ngModel = editableColumns[0].injector.get(NgModel);
tick();
ngModel.valueAccessor.writeValue(25000);
el.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(component.calculateTotalSalary).toHaveBeenCalled(); //failing here
expect(+el.value).toEqual(25000);
}));
});
演示:
https://stackblitz.com/edit/test-jasmine-karma-t7khzp?file=app%2Ftest.component.html
我正在更新上述单元测试用例中的工资金额。当我从上面的单元测试用例更新 ngModel 值时,如何触发相关的 ngModelChange 事件?
试试这个:
it('should update total salary amount', fakeAsync(() => {
spyOn(component, 'calculateTotalSalary');
const editableTreeTableEl = fixture.debugElement.query(By.css(".employeestreetable"));
let editableColumn = fixture.debugElement.query(By.css(".ui-editable-column input")).nativeElement;
editableColumn.value = 25000;
editableColumn.dispatchEvent(new Event('input'));
fixture.detectChanges();
tick(); // maybe you were missing this tick
expect(component.calculateTotalSalary).toHaveBeenCalled(); // should hopefully pass now
}));
我正在使用以下代码在 Angular 应用程序中使用 Jasmine 执行单元测试。
test.component.html:
<p-treeTable [value]="employees" [columns]="cols" class="employeestreetable">
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of cols" style="width:30px">
{{col.header}}
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
<tr [ttRow]="rowNode">
<td width="30" class="text-right" ttEditableColumn>
<p-treeTableToggler [rowNode]="rowNode">
</p-treeTableToggler>
<p-treeTableCellEditor>
<ng-template pTemplate="input">
<input type="text" pInputText [(ngModel)]="rowData['name']" />
</ng-template>
<ng-template pTemplate="output">
<input type="text" pInputText [(ngModel)]="rowData['name']">
</ng-template>
</p-treeTableCellEditor>
</td>
<td width="30" class="text-right">
<p-treeTableCellEditor>
<ng-template pTemplate="input">
<input type="text" pInputText [(ngModel)]="rowData['salary']" (ngModelChange)="calculateTotalSalary(rowNode)" />
</ng-template>
<ng-template pTemplate="output">
<input type="text" pInputText [(ngModel)]="rowData['salary']">
</ng-template>
</p-treeTableCellEditor>
</td>
<td width="30" class="text-right" ttEditableColumn>
<p-treeTableCellEditor>
<ng-template pTemplate="input">
<input type="text" pInputText [(ngModel)]="rowData['incentive']" (ngModelChange)="calculateTotalSalary(rowNode)" />
</ng-template>
<ng-template pTemplate="output">
<input type="text" pInputText [(ngModel)]="rowData['incentive']">
</ng-template>
</p-treeTableCellEditor>
</td>
<td width="30" class="text-right">
<span>{{rowData['totalsalary']}}</span>
</td>
</tr>
</ng-template>
</p-treeTable>
test.component.ts:
import { Component, OnInit, ViewChild } from '@angular/core';
import { TreeNode } from 'primeng/primeng'
import { ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'test-app',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent {
cols = [
{ field: 'name', header: 'Name' },
{ field: 'salary', header: 'Salary' },
{ field: 'incentive', header: 'Incentive' },
{ field: 'totalsalary', header: 'Total Salary' }
];
employees: TreeNode[] = [
{
"data": {
"name": "Alex",
"salary": 10000,
"incentive": 5000,
"totalsalary": 15000
},
"children": [
{
"data": {
"name": "George",
"salary": 8000,
"incentive": 2000,
"totalsalary": 10000
},
}
]
},
{
"data": {
"name": "Robert",
"salary": 18000,
"incentive": 10000,
"totalsalary": 280000
},
"children": [
{
"data": {
"name": "John",
"salary": 7000,
"incentive": 5000,
"totalsalary": 12000
}
}
]
}
];
calculateTotalSalary(rownode) {
rownode.node.data.totalsalary = +rownode.node.data.salary + +rownode.node.data.incentive;
}
}
test.component.spec.ts:
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import {
TestComponent
} from "./test.component";
import { FormsModule, NgModel } from '@angular/forms';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { MessageService } from 'primeng/api';
import { TreeNode } from 'primeng/api';
import { TreeTableModule } from 'primeng/treetable';
import { By } from '@angular/platform-browser';
import { InputTextModule } from 'primeng/inputtext';
describe('TestComponent', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule,
FormsModule, TreeTableModule, InputTextModule
],
declarations: [ TestComponent ],
providers: [ ],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
beforeEach(fakeAsync(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
tick();
}));
it('should update total salary amount', fakeAsync(() => {
spyOn(component, 'calculateTotalSalary');
const editableTreeTableEl = fixture.debugElement.query(By.css(".employeestreetable"));
let editableColumns = editableTreeTableEl.queryAll(By.css(".ui-editable-column input"));
const el = editableColumns[0].nativeElement;
const ngModel = editableColumns[0].injector.get(NgModel);
tick();
ngModel.valueAccessor.writeValue(25000);
el.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(component.calculateTotalSalary).toHaveBeenCalled(); //failing here
expect(+el.value).toEqual(25000);
}));
});
演示: https://stackblitz.com/edit/test-jasmine-karma-t7khzp?file=app%2Ftest.component.html
我正在更新上述单元测试用例中的工资金额。当我从上面的单元测试用例更新 ngModel 值时,如何触发相关的 ngModelChange 事件?
试试这个:
it('should update total salary amount', fakeAsync(() => {
spyOn(component, 'calculateTotalSalary');
const editableTreeTableEl = fixture.debugElement.query(By.css(".employeestreetable"));
let editableColumn = fixture.debugElement.query(By.css(".ui-editable-column input")).nativeElement;
editableColumn.value = 25000;
editableColumn.dispatchEvent(new Event('input'));
fixture.detectChanges();
tick(); // maybe you were missing this tick
expect(component.calculateTotalSalary).toHaveBeenCalled(); // should hopefully pass now
}));