代码之家  ›  专栏  ›  技术社区  ›  stian

如何在断言之前将组件状态与HTML输入同步?

  •  1
  • stian  · 技术社区  · 6 年前

    我正在尝试测试组件内部和HTML之间的交互。

    在下面的测试代码中,我有一个带有输入字段的应用程序组件,它使用双向绑定链接到组件内的属性。

    测试1通过使用 fixture.detectChanges 等待它稳定下来。因此,在这个测试中,组件测试属性与输入字段同步。

    但是,由于compontent没有用新的test属性值更新,因此test2失败。那么,在进入断言之前,为了同步更改,我遗漏了什么或者做错了什么?

    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>

    我把下面的答案拿出来,从答案中找出最小值,让我的测试通过。关键似乎是将fixture.detectChanges()移动到beforeeach()函数。

    我相信这是我通过测试所需的最低限度,除了在beforeeach中添加fixture.detectchanges。似乎不需要完成和fixture.whinstable。

    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');
    });
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Fabian Küng    6 年前

    我认为你考试的问题是你从来没有打过电话 fixture.detectChanges() 在你设置好你的 fixture component 在你 beforeEach .

    检查 this StackBlitz是测试的有效版本。

    我加了一秒钟 在每个之前 哪里 fixture.detectChanges 被称为:

    beforeEach(() => {
      fixture = TestBed.createComponent(AppComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
    });
    

    下面是失败的(现在正在工作的)测试:

    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();
      });
    });
    
        2
  •  0
  •   HDJEMAI    6 年前

    在第二个测试中,您必须添加以下内容:

    el.dispatchEvent(new Event('input'));
    

    在做预期之前,而不是之后

    然后你还要补充

    fixture.detectChanges(); 在做预期之前

    因此,像这样编写第二个测试:

    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');
        })
    }));
    

    你必须增加 async 对你 it 功能 因为 ngModel 是异步的。

    或者你也可以使用fakeasync