我在 Angular v5 上,正在编写浅层组件测试。当 karma 运行测试时,我收到一个错误:
Failed: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.
Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.
at viewDebugError (webpack:///./node_modules/@angular/core/esm5/core.js?:9970:32)
at expressionChangedAfterItHasBeenCheckedError (webpack:///./node_modules/@angular/core/esm5/core.js?:9948:12)
at checkBindingNoChanges (webpack:///./node_modules/@angular/core/esm5/core.js?:10117:15)
at checkNoChangesNodeInline (webpack:///./node_modules/@angular/core/esm5/core.js?:14170:9)
at checkNoChangesNode (webpack:///./node_modules/@angular/core/esm5/core.js?:14142:9)
at debugCheckNoChangesNode (webpack:///./node_modules/@angular/core/esm5/core.js?:14971:45)
at debugCheckRenderNodeFn (webpack:///./node_modules/@angular/core/esm5/core.js?:14911:13)
at Object.eval [as updateRenderer] (ng:///DynamicTestModule/LocationScheduleComponent.ngfactory.js:207:5)
at Object.debugUpdateRenderer [as updateRenderer] (webpack:///./node_modules/@angular/core/esm5/core.js?:14893:21)
at checkNoChangesView (webpack:///./node_modules/@angular/core/esm5/core.js?:13982:14)
当我运行应用程序并手动执行测试场景时,不会发生此错误。我确实做了一些调试,我的 html 中的以下行导致了错误:
<i id="save-new-{{i}}" *ngIf="row.get('IsFast').value" class="save_new_icon"
IsFast
是一个布尔属性。不知道为什么只有在运行测试时才会导致错误。我只能想象我的测试中有一些东西没有正确设置,因为当我运行应用程序时我没有收到任何错误。
我是一个团队的一员,并试图让我们开始测试我们的 Angular 代码。在我的测试中我需要做些什么来完成这项工作吗?在组件中添加/修改代码只是为了让测试通过,这对我的团队来说是一个很难的卖点,但如果这是让它工作所需要的,那就这样吧。老实说,我觉得我不知道角度测试的某些方面,这就是我收到此错误的原因。
这是我的模板的相关部分:
<ng-container formArrayName="cars" *ngFor="let row of carsFormArray.controls;let i=index;">
<tr id="{{i}}">
<ng-container [formGroupName]="i">
<td>
<i id="save-new-{{i}}" *ngIf="row.get('IsFast').value" class="save_new_icon"
aria-hidden="true" [class.disabled-icon]="isDisabled"
(click)="onSaveCarClicked(row)"></i>
<i class="delete" *ngIf="ableToDelete()" (click)="onDeleteClicked(row)" aria-hidden="true" [class.disabled-icon]="isDisabled"></i>
</td>
</ng-container>
</tr>
</ng-container>
这是我的测试代码:
import {FastCarComponent} from "./fast-car.component";
import {async, ComponentFixture, TestBed, fakeAsync, tick, flush, discardPeriodicTasks} from "@angular/core/testing";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {DebugElement, NO_ERRORS_SCHEMA} from "@angular/core";
import {Observable} from "rxjs/Rx";
import {Region} from "../core/models/master/region.model";
import {MockActivatedRoute} from "../../testing/mock-activated-route";
import {By} from "@angular/platform-browser";
import {forEach} from "@angular/router/src/utils/collection";
import {click} from "../../testing";
import {DatePickerAdapter, DatePickerComponent} from "../core/components";
import {CoreModule} from "../core/core.module";
describe('FastCarComponent', () => {
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FastCarComponent, DatePickerComponent ],
imports: [
NgSelectModule,
FormsModule,
ReactiveFormsModule,
],
providers: [
...
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
fit('should clear Car Description Validation Error on Adding Fast Car when DisplayFastCar=true and car description validation is satisfied', async(() => {
fixture = TestBed.createComponent(FastCarComponent);
component = fixture.componentInstance;
component.DisplayFastCar = true;
fixture.detectChanges(); // ngOnInit()
const page: Page = new Page(fixture);
click(page.addBtn);
fixture.detectChanges();
fixture.whenStable().then(() => {
let error_span = page.getErrorSpanByTextContent(CAR_DESCRIPTION_ERROR); //get the validation error that shows on page
if (error_span) {
carControl = page.getInputByLabelName('Car Description');
if (carControl) {
carControl.value = 'Some Description';
carControl.dispatchEvent(new Event('input'));
} else {
fail(`Could not find control with label Car Description`);
}
} else {
fail(`Did Not Find following validation message: ${CAR_DESCRIPTION_ERROR}`);
}
});
fixture.detectChanges(); //run change detection
fixture.whenStable().then(() => {
//fixture.detectChanges();
let error_span = page.getErrorSpanByTextContent(CAR_DESCRIPTION_ERROR);
expect(error_span).toBeFalsy(`Found Error Span With Text: ${CAR_DESCRIPTION_ERROR}`);
});
}));
});
});