2016-09-19 38 views
16

我想在Angular 2單元測試中更改輸入字段的值。從Angular 2測試中更新輸入html字段

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

我不能只是改變ngModel因爲abc對象是私有的:

private abc: Abc = new Abc(); 

在角2的測試,我可以模擬用戶輸入到輸入字段,以便ngModel將被更新用戶在單元測試中鍵入的內容?

我可以抓住輸入欄的DebugElementnativeElement沒有問題。 (只需在輸入字段的nativeElement上設置value屬性似乎不起作用,因爲它不更新我爲該值設置的ngModel)。

也許inputDebugEl.triggerEventHandler可以調用,但我不知道給它什麼參數,所以它會模擬用戶鍵入一個特定的輸入字符串。

回答

21

你是對的,你不能只是設置輸入,你還需要調度'input'事件。這是一個功能我今晚早些時候寫信給輸入文本:

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

這裏fixtureComponentFixtureinputElement從燈具的nativeElement相關HTTPInputElement。這返回一個承諾,所以你可能不得不解決它sendInput('whatever').then(...)

在背景:https://github.com/textbook/known-for-web/blob/52c8aec4c2699c2f146a33c07786e1e32891c8b6/src/app/actor/actor.component.spec.ts#L134


更新

我們有一些問題得到這個在角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(); 
} 
+0

非常感謝Jon。這工作很好,ngModel獲取所需的文本更新。你真的爲我的答案省下了一大堆時間。 – Daniel

+1

執行此操作時是否還有其他任何陷阱?我試圖讓這個解決方案起作用,但到目前爲止還沒有能夠讓模型更新。我在Angular 2.1.2上,所以不確定自從這篇文章以來是否有任何內容被破壞/改變。 –

+0

@NathanG不是我記得的。嘗試更多或更少的更改檢測並等待穩定性可能會有所幫助。 – jonrsharpe

9

在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" />

+0

那是我唯一的工作! – Deutro

+0

這個答案對我來說結束了3個小時的痛苦 –

+0

對於我來說,調用'setInput'後,我不得不使用'fixture.whenStable(()=> {expect(...)});'block 。 – redOctober13

0

我也有麻煩jonrsharpe的答案與角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... 
    }); 
}));