【问题标题】:Testing angular component form for pristine is not working测试原始角度组件形式不起作用
【发布时间】:2021-02-10 17:12:11
【问题描述】:

我有一个带有输入的表单,并且我有一个按钮,只有在表单数据更改时才需要启用该按钮。我正在使用原始检查,它在浏览器中都能正常工作,但我无法测试它。无论我做什么,无论我设置多少次,原始检查总是正确的。知道我做错了什么吗?

HTML 有 2 个输入,带有标签和一个按钮

<form (ngSubmit)="login()"
      [formGroup]="form">
  <label>Email</label>
  <input type="email" formControlName="email" name="email">
  <label>Password</label>
  <input type="password" formControlName="password">
  <button type="submit">Login</button>
</form>

我的打字稿文件

import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from "@angular/forms";

export class User {
  constructor(public email: string,
              public password: string) {
  }
}

@Component({
  selector: 'app-login-component',
  templateUrl: './login-component.component.html',
  styleUrls: ['./login-component.component.scss']
})
export class LoginComponentComponent implements OnInit {
  @Output() loggedIn = new EventEmitter<User>();
  form: FormGroup;

  constructor(private fb: FormBuilder) {
  }

  ngOnInit() {
    this.form = this.fb.group({
      email: ['', [Validators.required, Validators.pattern("[^ @]*@[^ @]*")]],
      password: ['', [Validators.required, Validators.minLength(8)]],
    });
  }

  login() {
    console.log(`Login ${this.form.value}`);
    if (this.form.valid) {
      this.loggedIn.emit(
        new User(
          this.form.value.email,
          this.form.value.password
        )
      );
    }
  }
}

还有 2 个测试。我已经尝试过异步测试和没有。我还尝试在表单上设置原生元素的值。但在这两种情况下,原始检查总是正确的。知道我做错了什么吗?

import {async, ComponentFixture, TestBed} from '@angular/core/testing';

import {LoginComponentComponent} from './login-component.component';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {By} from "@angular/platform-browser";

describe('Component: Login', () => {

  let component: LoginComponentComponent;
  let fixture: ComponentFixture<LoginComponentComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ReactiveFormsModule, FormsModule],
      declarations: [LoginComponentComponent]
    });
    fixture = TestBed.createComponent(LoginComponentComponent);
    component = fixture.componentInstance;
    component.ngOnInit();
  });

  it('Tried WIHTOUT async function', () => {
    expect(component.form.pristine).toBeTrue();         //Should not be in a modified state when it starts
    fixture.detectChanges();

    const inputElement = fixture.debugElement.query(By.css('input[name="email"]')).nativeElement;
    //Try to set the control itself and the form
    component.form.controls.email.setValue("2")
    inputElement.value = '2';

    //Detect changes and wait to be stable
    fixture.detectChanges();
    expect(inputElement.value).toEqual("2");  //Test that the value has infact change
    expect(component.form.pristine).toBeFalse();   //This fails
  });

  it('Tried using async function', async(() => {
    expect(component.form.pristine).toBeTrue();         //Should not be in a modified state when it starts
    fixture.detectChanges();

    const inputElement = fixture.debugElement.query(By.css('input[name="email"]')).nativeElement;
    //Try to set the control itself and the form
    component.form.controls.email.setValue("2")
    inputElement.value = '2';

    //Detect changes and wait to be stable
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      expect(inputElement.value).toEqual("2");  //Test that the value has infact change
      expect(component.form.pristine).toBeFalse(); //This fails
    });
  }));
});

【问题讨论】:

    标签: angular jasmine angular-test


    【解决方案1】:

    这不起作用,因为

    如果用户尚未更改 UI 中的值,则控件是原始控件。

    仅当您使用 UI 更改值时,原始属性才会变为 false。 以编程方式设置/更改表单值不会改变它。

    解决此问题的一种方法是,在您的测试中,您可以使用 component.form.markAsDirty() 使原始错误并让测试正常工作。

    Read more here.

    另一种方法是模拟行为就像从 UI 更改值一样,您可以使用

    component.form.controls.email.setValue("2");
    inputElement.dispatchEvent(new Event('input'));
    

    或者

    inputElement.dispatchEvent(new Event('input'));
    inputElement.value = '2';
    

    【讨论】:

    • 嗨 Ashish,谢谢,到目前为止,这是让我的测试通过的最佳方式。但是有没有办法使用“UI”来更改测试中的值?
    • 你可以用这个来模拟inputElement.dispatchEvent(new Event('input'));
    • 为什么要在设置值之前调度事件?我以为你会设置价值然后进行调度
    猜你喜欢
    • 1970-01-01
    • 2018-05-01
    • 2015-07-05
    • 2021-11-25
    • 2018-07-18
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多