为什么使用模板驱动 return 未定义值进行测试?

Why does testing with template driven return undefined value?

我正在尝试使用 Angular 中的模板驱动表单测试一个简单的表单。我将值插入输入并单击提交按钮,该按钮将值发送到服务。代码有效,但测试失败,因为值始终未定义。

我已经创建了一个问题演示以在此处显示(我的实际代码会太复杂):

app.component.ts

@Component({
  selector: 'app-root',
  template: `
    <form #f="ngForm" (ngSubmit)="submit(f)">

      <input type="text" ngModel name="field1">
      <input type="text" [(ngModel)]="field2" name="field2">

      <input type="submit" value="submit">

      <br>field1: {{ f.value.field1 }}
      <br>submitedText: {{ submitedText }}
      <br>field2: {{ field2 }}

    </form>
  `
})
export class AppComponent {
  public submitedText: string;
  public field2: string;

  public submit(form: NgForm) {
    this.submitedText = form.value.field1;
  }
}

app.component.spec.ts

describe('AppComponent', () => {
  it('shoud to submit the text', () => {
    const fixture = TestBed.configureTestingModule({
      declarations: [ AppComponent ],
      imports: [ FormsModule ],
    }).createComponent(AppComponent)

    fixture.detectChanges();

    const field1 = fixture.elementRef.nativeElement.querySelector('input[name="field1"]');
    const field2 = fixture.elementRef.nativeElement.querySelector('input[name="field2"]');
    const button = fixture.elementRef.nativeElement.querySelector('input[type="submit"]');

    field1.value = 'test 1';
    field2.value = 'test 2';
    field1.dispatchEvent(newEvent('input'));
    field2.dispatchEvent(newEvent('input'));
    fixture.detectChanges();

    button.click();
    fixture.detectChanges();

    expect(fixture.componentInstance.submitedText).toBe('test 1');
    expect(fixture.componentInstance.field2).toBe('test 2');
  });
});
export function newEvent(eventName: string, bubbles = false, cancelable = false) {
  const evt = document.createEvent('CustomEvent');  // MUST be 'CustomEvent'
  evt.initCustomEvent(eventName, bubbles, cancelable, null);
  return evt;
}

结果是:

Failures
AppComponent > shoud to submit the text
Expected undefined to be 'test 1'.
Expected undefined to be 'test 2'.

有人可以帮助我让测试正确填写输入吗?谢谢!

我找到了解决方案,虽然我不明白为什么,因为文档没有解释它。

有不同的方法来纠正测试。

在我创建的示例中,需要将测试代码包含在 fakeAsync 中,并分别调用 fixture.detectChanges() 和 tick() 函数:

describe('AppComponent', () => {
  it('shoud to submit the text', fakeAsync(() => {
    const fixture = TestBed.configureTestingModule({
      declarations: [ AppComponent ],
      imports: [ FormsModule ],
    }).createComponent(AppComponent)

    fixture.detectChanges();
    tick();

    // rest of the code ...
}));


我需要指出的是,我的原始代码在 beforeEach 中创建了组件(没有异步),这有所不同。如果您在没有异步的 beforeEach 中创建组件,则必须在其中使用 fakeAsync,并且您不能在这个 beforeEach 中调用 fixture.detectChanges() (这破坏了我的原始代码)。但是,如果您的 beforeEach 具有异步,则不需要使用 fakeAsync,并且在您的测试(它)中使用异步或 fakeAsync 是可选的。

beforeEach(async(() => {
    const fixture = TestBed.configureTestingModule({
      declarations: [ AppComponent ],
      imports: [ FormsModule ],
    }).createComponent(AppComponent)

    fixture.detectChanges();
}));

it('shoud to submit the text', () => {
// rest of the code ...