Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
87 views
in Technique[技术] by (71.8m points)

Testing angular component form for pristine is not working

I have a form that has an input and I have a button that needs to be enabled only when the form data was changed. I am using a pristine check and it all works functionally in the browser but I am having trouble to test it. No matter what I do the pristine check is always true no matter how many times I set the values. Any idea what I am doing wrong?

The HTML has 2 inputs with labels and a button

<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>

My typescript file

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

And the 2 tests. I have tried with asych testing and without. I also tried setting the value of the native element and on the form. But in both cases the pristine check is always true. Any idea what I am doing wrong?

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
    });
  }));
});
question from:https://stackoverflow.com/questions/65645144/testing-angular-component-form-for-pristine-is-not-working

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is not working because

A control is pristine if the user has not yet changed the value in the UI.

Only if you change value using UI, the pristine property will become false. Setting/changing form values programmatically doesn't change it.

One way to fix this is, in your tests you can use component.form.markAsDirty() to make pristine false and make the tests work properly.

Read more here.

Other way is to simulate the behaviour as if value was changed from UI, you can use

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

Or

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...