2016-09-19 15 views
16

Chciałbym zmienić wartość pola wejściowego z testu Angular 2 unit.Aktualizowanie wejściowego pola html z poziomu testu Angular 2

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

Nie mogę po prostu zmienić ngModel ponieważ abc obiekt jest prywatny:

private abc: Abc = new Abc(); 

kątowej 2 testów, mogę symulować użytkownika, wpisując w polu tekstowym, tak aby ngModel zostanie zaktualizowany z tym, co użytkownik wpisał z testu jednostki?

Mogę pobrać DebugElement i nativeElement z pola wejściowego bez problemu. (Ustawienie właściwości value w polu wejściowym nativeElement nie działa, ponieważ nie aktualizuje wartości ngModel z ustawionym dla niej wartością).

Może być wywoływana inputDebugEl.triggerEventHandler, ale nie jestem pewien, jakie argumenty podać, aby zasymulować użytkownika wpisującego określony ciąg danych wejściowych.

Odpowiedz

21

Masz rację, że nie możesz po prostu ustawić wejścia, musisz również wysłać zdarzenie 'input'. Oto funkcja pisałem wcześniej tego wieczoru do wprowadzania tekstu:

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

tutaj fixture jest ComponentFixture i inputElement jest istotne HTTPInputElement z uchwyt na nativeElement. Zwraca to obietnicę, więc prawdopodobnie będziesz musiał ją rozwiązać sendInput('whatever').then(...).

W kontekście: https://github.com/textbook/known-for-web/blob/52c8aec4c2699c2f146a33c07786e1e32891c8b6/src/app/actor/actor.component.spec.ts#L134


Aktualizacja:

Mieliśmy pewne problemy uzyskiwanie to do pracy w ruchu obrotowym 2,1, to nie podoba tworząc new Event(...), więc zamiast zrobiliśmy:

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

Dziękuję bardzo Jon.To działało wspaniale, a ngModel został zaktualizowany z żądanym tekstem. Naprawdę zaoszczędziłeś mi sporo czasu z twoją odpowiedzią. – Daniel

+1

Czy są jakieś inne błędy znalezione podczas realizacji tego? Próbuję uruchomić to rozwiązanie, ale jak dotąd nie udało się zaktualizować modelu. Jestem na Angular 2.1.2, więc nie jestem pewien, czy coś się zepsuło/zmieniło od tego posta. –

+0

@NathanG nie, że pamiętam. Może pomóc mniej lub więcej próba zmiany wykrywania i czekanie na stabilność. – jonrsharpe

9

Przyjęte rozwiązanie nie działa dla mnie w Angular 2.4. Ustawiona wartość nie pojawiła się w interfejsie (testowym), nawet po wywołaniu metody detectChanges().

Sposób mam go do pracy było skonfigurować testu w następujący sposób:

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

Moja TemplateComponent składnik ma właściwość o nazwie personName w tym przykładzie, który był własnością modelu mam wiązanie się w moim szablon:

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

+0

To był jedyny, który pracował dla mnie! – Deutro

+0

Ta odpowiedź zakończyła się 3 godzinami bólu dla mnie –

+0

Aby to zadziałało, po wywołaniu 'setInput', musiałem użyć bloku' fixture.whenStable (() => {expect (...)}); ' . – redOctober13

0

miałem też problemy z uzyskaniem odpowiedzi jonrsharpe do pracy z kątowe 2.4. Zauważyłem, że wywołania do fixture.detectChanges() i fixture.whenStable() spowodowały zresetowanie komponentu formularza. Wydaje się, że niektóre funkcje inicjalizacyjne są nadal w toku, gdy rozpoczyna się test. Rozwiązałem to przez dodanie dodatkowych wywołań do tych metod przed każdym testem. Oto fragment kodu:

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... 
    }); 
})); 
Powiązane problemy