如何测试输入元素的输入?

How to test typing to an input element?

我正在尝试 'typing' 测试输入元素。我的目标是在输入元素中放入一些值,并查看其绑定是否具有输入值,以及查看我在输入元素中输入的值。

代码:

app.component:

import { Component } from "@angular/core";

@Component({
  selector: "my-app",
  template: `
    <span>My input: </span>
    <input name="name-input" placeholder="Enter name" [(ngModel)]="name" />
  `,
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  name = "";
}

测试:

import { TestBed } from "@angular/core/testing";
import { FormsModule } from "@angular/forms";
import { AppComponent } from "./app.component";

describe("AppComponent", () => {
  var fixture: any;
  var app: AppComponent;

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

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

  it("should create the app", () => {
    expect(app).toBeTruthy();
  });

  it("should type text into input element", () => {
    let inputElement = fixture.nativeElement.querySelector(
      `input[name='name-input']`
    );

    inputElement.value = "someValue";
    inputElement.dispatchEvent(new Event("input"));
    fixture.detectChanges();

    expect(app.name).toBe("someValue");
  });
});

行后:

inputElement.value = "someValue";
inputElement.dispatchEvent(new Event("input"));
fixture.detectChanges();

预期:app.name 等于“someValue”。 找到:app.name 等于空字符串:"".

证明它不起作用的 stackblitz: https://stackblitz.com/edit/Whosebug-input-question1q2w3e?

你应该调度一个 KeyboardEvent on the HTMLInputElement within a fakeAsync 区域。

您的单元测试将如下所示:

it('#keydown should update app#name', fakeAsync(() => {

  // given
  let inputElement = fixture.nativeElement.querySelector(`input[name='name-input']`);
  
  // when
  let event = new KeyboardEvent('keydown', { key: 'x' });
  inputElement.dispatchEvent(event);
  tick();

  // then
  expect(app.name).toBe("x");
}));

我相信您正在寻找的是以下代码:

it("should type text into input element after the view has been done initializing", () => {
  fixture.detectChanges(); // ngOnInit Lifecycle hook is run here

  let inputElement = fixture.nativeElement.querySelector(
    `input[name='name-input']`
  );

  inputElement.value = "someValue";
  inputElement.dispatchEvent(new Event("input"));

  fixture.detectChanges();
  expect(app.name).toBe("someValue");
});

现在,为什么这样做有效? 根据official documentation,当你运行 fixture.detectChanges()第一次时,ngOnInit()生命周期钩子被调用,这是错误的关键。

您正在 ngOnInit() 之外设置值,但是,初始化视图的生命周期挂钩尚未 运行。这意味着当您第一次调用 fixture.detectChanges() 时,它会调用 ngOnInit() 生命周期挂钩。然后将视图重新初始化为其原始状态,恢复之前所做的所有更改(如设置输入值)。

亲切的问候。