【问题标题】:How to test typing to an input element?如何测试输入元素的输入?
【发布时间】:2021-02-26 18:23:45
【问题描述】:

我正在尝试对输入元素进行“打字”测试。我的目标是在 input 元素中放入一些值,并查看其绑定是否具有 input 的值,并查看我在 input 元素中输入的值。

代码:

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 等于空字符串:“”。

证明它不起作用的堆栈闪电战: https://stackblitz.com/edit/stackoverflow-input-question1q2w3e?

【问题讨论】:

  • 那么会发生什么?错误?测试失败?根据stackoverflow.com/q/39582707/3001761,设置值然后触发输入事件在例如github.com/textbook/salary-stats/blob/main/src/app/table/…
  • @jonrsharpe 测试失败,预期:“someValue”,发现:“”。现在我将您的解决方案添加到了 stackblitz(我更新了它)。可以看到测试失败了。
  • minimal reproducible example在问题中,站外链接应该是补充。
  • @jonrsharpe 但这已经是“可重复的示例”。我在我的电脑上测试了它=> 不起作用。所以我分享了一个 stackblitz 来证明它不起作用并且所有测试都失败了。还可以使用您和 uminder 解决方案更新 stackblitz,以证明这一点。
  • "描述问题。“它不起作用”的描述性不足以帮助人们理解您的问题。相反,请告诉其他读者预期的结果行为应该是。告诉其他读者错误消息的确切措辞是什么,以及产生错误消息的代码行。使用对问题的简短但描述性摘要作为问题的标题。"

标签: angular typescript unit-testing testing jasmine


【解决方案1】:

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

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() 生命周期挂钩。然后,这会将视图重新初始化为其原始状态,从而恢复之前所做的所有更改(例如设置输入值)。

亲切的问候。

【讨论】:

  • 非常感谢!有用!但我还有一个问题。它通过了测试 => 太棒了!但是为什么测试完成后我没有看到“somevalue”出现在输入元素中? (假设它是唯一运行的测试)
  • 如果您在应用程序中进行测试(而不是在 stackblittz 上),您可以将 byebugs 放入测试中。您将看到输入字段已创建,并填充了文本,然后在测试结束时重置。在实践中,我们看不到文本,因为文本运行速度太快,我们无法看到/浏览器考虑渲染。
【解决方案2】:

您应该在fakeAsync 区域内的HTMLInputElement 上发送KeyboardEvent

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

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

【讨论】:

  • 我将您的代码复制到了 stackblitz(我用您的代码更新了它),但它仍然无法正常工作。它有这个错误:“TypeError:无法读取未定义的属性'assertPresent'”
猜你喜欢
  • 2012-12-02
  • 1970-01-01
  • 2019-07-24
  • 1970-01-01
  • 2021-03-30
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多