it-swarm.com.de

Aktualisieren des HTML-Eingabefelds aus einem Angular 2-Test

Ich möchte den Wert eines Eingabefeldes in einem Angular 2 Unit Test ändern.

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

Ich kann das ngModel nicht einfach ändern, da das abc -Objekt privat ist:

 private abc: Abc = new Abc();

Kann ich beim Testen von Angular 2) den Benutzer simulieren, der in das Eingabefeld eingibt, sodass das ngModel mit dem aktualisiert wird, was der Benutzer in einem Komponententest eingegeben hat?

Ich kann das DebugElement und das nativeElement des Eingabefeldes problemlos abrufen. (Das einfache Setzen der Eigenschaft value auf nativeElement des Eingabefelds scheint nicht zu funktionieren, da es das ngModel nicht mit den von mir festgelegten Einstellungen aktualisiert der Wert).

Vielleicht inputDebugEl.triggerEventHandler kann aufgerufen werden, aber ich bin mir nicht sicher, welche Argumente ich verwenden soll, damit der Benutzer simuliert, dass er eine bestimmte Zeichenfolge eingegeben hat.

30
Daniel

Sie haben Recht, dass Sie nicht nur die Eingabe festlegen können, sondern auch das Ereignis 'input' Auslösen müssen. Hier ist eine Funktion, die ich heute Abend geschrieben habe, um Text einzugeben:

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

Hier ist fixture das ComponentFixture und inputElement das relevante HTTPInputElement aus dem nativeElement des Scheinwerfers. Dies gibt ein Versprechen zurück, sodass Sie es wahrscheinlich auflösen müssen sendInput('whatever').then(...).

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


Update :

Wir hatten einige Probleme damit das funktioniert in Angular= 2.1, es hat nicht gefallen ein new Event(...) zu erstellen, also haben wir stattdessen folgendes gemacht:

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

Die akzeptierte Lösung hat in Angular 2.4 nicht ganz funktioniert. Der von mir festgelegte Wert wurde in der (Test-) Benutzeroberfläche nicht angezeigt, selbst nachdem detectChanges () aufgerufen wurde.

Ich habe meinen Test folgendermaßen eingerichtet:

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

Meine TemplateComponent -Komponente hat in diesem Beispiel eine Eigenschaft mit dem Namen personName, an die ich in meiner Vorlage gebunden bin:

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

13
Paul

Ich hatte auch Probleme, Jonrsharpes Antwort für die Arbeit mit Angular 2.4. Ich stellte fest, dass die Aufrufe von fixture.detectChanges() und fixture.whenStable() das Zurücksetzen der Formularkomponente verursachten. Es sieht so aus, als ob zu Beginn des Tests noch einige Initialisierungsfunktionen ausstehen. Dies wurde behoben, indem ich diesen Methoden vor jedem Test zusätzliche Aufrufe hinzufügte. Hier ist ein Ausschnitt aus meinem Code:

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...
    });
}));
3
Philip Beber