从Angular 2测试中更新输入html字段

时间:2016-09-19 21:52:55

标签: unit-testing testing angular jasmine

我想在Angular 2单元测试中更改输入字段的值。

<input type="text" class="form-control" [(ngModel)]="abc.value" />

我不能只更改ngModel,因为abc对象是私有的:

 private abc: Abc = new Abc();

在Angular 2测试中,我是否可以模拟用户在输入字段中输入内容,以便使用用户在单元测试中输入的内容更新ngModel

我可以毫无问题地抓住输入字段的DebugElementnativeElement。 (仅在输入字段的value上设置nativeElement属性似乎不起作用,因为它没有使用我为该值设置的内容更新ngModel

也许可以调用inputDebugEl.triggerEventHandler,但是我不确定给它的参数是什么,所以它会模拟输入特定输入字符串的用户。

3 个答案:

答案 0 :(得分:43)

你是对的,你不能只设置输入,你还需要发送'input'事件。这是我今天早些时候写的一个函数来输入文本:

function sendInput(text: string) {
  inputElement.value = text;
  inputElement.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  return fixture.whenStable();
}

此处fixtureComponentFixtureinputElement是来自灯具HTTPInputElement的相关nativeElement。这会返回一个承诺,因此您可能需要解决它sendInput('whatever').then(...)

在上下文中:https://github.com/textbook/known-for-web/blob/52c8aec4c2699c2f146a33c07786e1e32891c8b6/src/app/actor/actor.component.spec.ts#L134

<强>更新

我们在Angular 2.1中遇到了一些问题,它并不像创建new Event(...)那样,所以我们做了:

import { dispatchEvent } from '@angular/platform-browser/testing/browser-util';

...

function sendInput(text: string) {
  inputElement.value = text;
  dispatchEvent(fixture.nativeElement, 'input');
  fixture.detectChanges();
  return fixture.whenStable();
}

答案 1 :(得分:12)

在Angular 2.4中,我接受的解决方案并不适用于我。即使在调用了detectChanges()之后,我设置的值也没有出现在(测试)UI中。

我开始工作的方式是按如下方式设置我的测试:

describe('TemplateComponent', function () {
  let comp: TemplateComponent;
  let fixture: ComponentFixture<TemplateComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ FormsModule ],
      declarations: [ TemplateComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TemplateComponent);
    comp = fixture.componentInstance;
  });

  it('should allow us to set a bound input field', fakeAsync(() => {
    setInputValue('#test2', 'Tommy');

    expect(comp.personName).toEqual('Tommy');
  }));

  // must be called from within fakeAsync due to use of tick()
  function setInputValue(selector: string, value: string) {
    fixture.detectChanges();
    tick();

    let input = fixture.debugElement.query(By.css(selector)).nativeElement;
    input.value = value;
    input.dispatchEvent(new Event('input'));
    tick();
  }
});

我的TemplateComponent组件在此示例中有一个名为personName的属性,它是我在模板中绑定的模型属性:

<input id="test2" type="text" [(ngModel)]="personName" />

答案 2 :(得分:3)

我也很难让jonrsharpe回答使用Angular 2.4。我发现对fixture.detectChanges()fixture.whenStable()的调用导致表单组件重置。在测试开始时,似乎某些初始化函数仍处于未决状态。我通过在每次测试之前添加额外的调用来解决这个问题。以下是我的代码片段:

beforeEach(() => {
    TestBed.configureTestingModule({
        // ...etc...
    });
    fixture = TestBed.createComponent(LoginComponent);
    comp = fixture.componentInstance;
    usernameBox = fixture.debugElement.query(By.css('input[name="username"]'));
    passwordBox = fixture.debugElement.query(By.css('input[type="password"]'));
    loginButton = fixture.debugElement.query(By.css('.btn-primary'));
    formElement = fixture.debugElement.query(By.css('form'));
});

beforeEach(async(() => {
    // The magic sauce!!
    // Because this is in an async wrapper it will automatically wait
    // for the call to whenStable() to complete
    fixture.detectChanges();
    fixture.whenStable();
}));

function sendInput(inputElement: any, text: string) {
    inputElement.value = text;
    inputElement.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    return fixture.whenStable();
}

it('should log in correctly', async(() => {

    sendInput(usernameBox.nativeElement, 'User1')
    .then(() => {
        return sendInput(passwordBox.nativeElement, 'Password1')
    }).then(() => {
        formElement.triggerEventHandler('submit', null);
        fixture.detectChanges();

        let spinner = fixture.debugElement.query(By.css('img'));
        expect(Helper.isHidden(spinner)).toBeFalsy('Spinner should be visible');

        // ...etc...
    });
}));