[英]how to synchronise component state with html-input before assertion?
I am trying to test interactions between a components internals and its HTML.我正在尝试测试组件内部与其 HTML 之间的交互。
In the following test code, I have an app-component with an input-field, which is linked to an attribute within the component using two-way binding.在下面的测试代码中,我有一个带有输入字段的应用程序组件,它使用双向绑定链接到组件内的一个属性。
Test1 passes with the use of fixture.detectChanges
and waiting it to be stable. Test1 通过使用
fixture.detectChanges
并等待它稳定。 So, in this test the components test-attribute is synchronised with the input-field.因此,在此测试中,组件测试属性与输入字段同步。
However, test2 fails due to the fact that the compontent has not been updated with the new test-attribute value.但是,由于组件尚未使用新的 test-attribute 值更新,test2 失败。 So, what am I missing or doing wrong to synchronise the changes before entering into the assertion?
那么,在进入断言之前,我错过了什么或做错了什么来同步更改?
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { test = 'hello'; } import { TestBed, async } from '@angular/core/testing'; import { AppComponent } from './app.component'; import {BrowserModule, By} from '@angular/platform-browser'; import {FormsModule} from '@angular/forms'; import {ComponentFixture} from '../../node_modules/@angular/core/testing'; import {detectChanges} from '../../node_modules/@angular/core/src/render3'; describe('AppComponent', () => { let component: AppComponent; let fixture: ComponentFixture<AppComponent>; beforeEach(() => { TestBed.configureTestingModule({ imports: [ FormsModule ], declarations: [ AppComponent, ], }).compileComponents(); fixture = TestBed.createComponent(AppComponent); component = fixture.componentInstance; }); it('test1', () => { const inputElement = fixture.debugElement.query(By.css('input')); const el = inputElement.nativeElement; fixture.detectChanges(); fixture.whenStable().then(() => { expect(el.value).toBe('hello'); }) }); it('test2', () => { const inputElement = fixture.debugElement.query(By.css('input')); const el = inputElement.nativeElement; el.value = 'test'; expect(el.value).toBe('test'); el.dispatchEvent(new Event('input')); fixture.detectChanges(); fixture.whenStable().then(() => { expect(component.test).toBe('test'); }) }); });
<div> <input [(ngModel)]="test" type="text"> <p>{{test}}</p> </div>
I took the answer below and looked at the minimal from the answer to get my test to pass.我接受了下面的答案,并从答案中查看了最少的内容,以使我的测试通过。 The key seems to have been to move the fixture.detectChanges() to the beforeEach() function.
关键似乎是将 fixture.detectChanges() 移动到 beforeEach() 函数。
I believe this was the minimum I needed to include for a passing test, in addition to adding the fixture.detectChanges in the beforeEach.除了在 beforeEach 中添加 fixture.detectChanges 之外,我相信这是通过测试所需的最低要求。 It seems that the done and the fixture.whenStable is not necessary.
似乎不需要 done 和 fixture.whenStable 。
it('test2', () => {
const inputElement = fixture.debugElement.query(By.css('input'));
const el = inputElement.nativeElement;
el.value = 'test';
el.dispatchEvent(new Event('input'));
expect(component.test).toBe('test');
});
I think the issue with your test is that you never initially call fixture.detectChanges()
after you set up your fixture
and component
in your beforeEach
.我认为您的测试的问题在于,在您在
beforeEach
设置fixture
和component
后,您最初从未调用过fixture.detectChanges()
。
Check this stackblitz for a working version of your test.
检查此stackblitz 以获取测试的工作版本。
I added a second beforeEach
where fixture.detectChanges
is called:我添加了第二个
beforeEach
其中fixture.detectChanges
被称为:
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
And here is the failing (now working) test:这是失败的(现在工作)测试:
it('test2', (done) => {
const inputElement = fixture.nativeElement.querySelector('input');
inputElement.value = 'test';
const inputEvent = document.createEvent('Event');
inputEvent.initEvent('input', true, true);
inputElement.dispatchEvent(inputEvent);
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.test).toBe('test');
done();
});
});
In the second test, you have to add this:在第二个测试中,您必须添加以下内容:
el.dispatchEvent(new Event('input'));
before doing the expect, and not after在做期望之前,而不是之后
and then you have also to add然后你还必须添加
fixture.detectChanges();
before doing the expect as well在做期望之前
so write your second test like this:所以写你的第二个测试是这样的:
it('test2', async(() => {
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement;
inputElement.value = 'test';
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.test).toBe('test');
})
}));
You have to add async
to your it
function because ngModel
is async.您必须将
async
添加到您的it
函数中,因为ngModel
是异步的。
Alternatively you can use fakeAsync as well或者,您也可以使用 fakeAsync
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.