如何在 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
  }));