Angular - проверка отображаемой ошибки при проверке формы - PullRequest
2 голосов
/ 04 апреля 2020

У меня есть тест, который выглядит следующим образом:

...
component.registerForm.controls['username'].setValue('VALID USERNAME');

fixture.detectChanges();

expect(component.registerForm.valid).toEqual(true);  // FIRST ASSERTION
const errors = fixture.debugElement.queryAll(By.css('.error.username'));
expect(errors.length).toBe(0);  // <-- SECOND ASSERTION: IT VAILS HERE!!!

Проблема в том, что даже если форма верна и первое утверждение проходит, второе утверждение терпит неудачу, потому что отображается сообщение об ошибке "required". Для меня это выглядит так, как будто форма была обновлена, а fixture.debugElement не так, что она отображает первоначальную ошибку. Т.е. игнорируется установка значения username.

ОБНОВЛЕНО: У меня очень похожая проблема, и я считаю, что источник может быть таким же: у меня есть несколько тестовых случаев, которые я хотел бы убедиться, что моя форма проверки правильности настроена правильно (т. е. действительные случаи приводят к правильной форме, недопустимые случаи в недействительной форме) (я упростил форму только до username):

getUsernameCases().forEach((testCase) => {
  it(`should be valid: ${testCase.valid}`, () => {
    component.myForm.get('username').setValue(testCase.username);

    component.registerForm.updateValueAndValidity();
    fixture.detectChanges();
    component.registerForm.updateValueAndValidity(); // Second time to make sure order does not matter

    expect(component.myForm.valid).toBe(testCase.valid); // ALWAYS INVALID HERE
  });
});

Проблема в том, что форма всегда недействительна независимо от значения. Имеет ошибку required - это означает, что показывает начальное состояние формы. До setValue.

Ответы [ 3 ]

1 голос
/ 20 апреля 2020

Это будет во многом зависеть от того, как вы создаете свою форму, но я могу написать тест, который подтверждает правильность формы так, как я думаю, вы пытаетесь. Мне нужно увидеть тестируемый компонент, чтобы знать наверняка.

Вот фрагмент стека, показывающий эти тесты .

app.component.ts:

export class AppComponent implements OnInit {

  myForm: FormGroup;

  //Helper to get the username control to check error state
  get username() {
    return this.myForm.get('username');
  }

  constructor(private fb: FormBuilder) {
  }

  ngOnInit() {
    //"Username" has two validations to test: required and minLength
    this.myForm = this.fb.group({
      'username': new FormControl(null, [Validators.required, Validators.minLength(10)])
    });
  }
}

app.component. html:

<form [formGroup]="myForm">
  <!-- "username" input with conditional styles based on error state -->
  <input type="text" 
         formControlName="username"
         [class.username-valid]="!username.errors"
         [class.error-username-required]="username.errors?.required"
         [class.error-username-minlength]="username.errors?.minlength">
</form>

app.component.spe c .ts:

describe('AppComponent', () => {
  let fixture: ComponentFixture<AppComponent>;
  let component: AppComponent;

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

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

  describe('The form validity', () => {
    const testCases = [
      {
        expected: true,
        username: 'VALID_USERNAME',
        expectedCss: 'username-valid'
      },
      {
        expected: false,
        username: null,
        expectedCss: 'error-username-required'
      },
      {
        expected: false,
        username: 'too_short',
        expectedCss: 'error-username-minlength'
      }
    ];

    testCases.forEach(testCase => {
      it(`should update the form validity: ${testCase.expected}`, () => {
        component.myForm.get('username').setValue(testCase.username);
        component.myForm.updateValueAndValidity();
        fixture.detectChanges();
        expect(component.myForm.valid).toBe(testCase.expected); //assert the form is valid/invalid
        expect(fixture.debugElement.query(By.css(`.${testCase.expectedCss}`))).toBeTruthy(); //assert the conditional style is applied
      });
    });
  });
});
0 голосов
/ 24 апреля 2020

Несколько дней назад я столкнулся с подобной проблемой go. Я решил эту проблему, вызвав

component.myForm.get('username').updateValueAndValidity({ emitEvent: true })

По сути, вам нужно запустить пересчет значения и проверку на уровне FormControl, а не на уровне FormGroup.

Возможно вам не понадобится параметр emitEvent, в моем случае у меня есть подписка на FormGroup, чтобы узнать, был ли статус формы действительным или нет, предоставив {emitEvent: true} Angular, который выдаст statusChanges & valueChanges и подписка сделает свое дело.

0 голосов
/ 21 апреля 2020

Я попросил вас предоставить код HTML для вашей проблемы. Программное изменение значения не помечает грязное свойство как true или false (я предполагаю, что это является причиной вашей проблемы). Вы можете разрешить его несколькими способами:

  1. Я бы посоветовал вам изменить значение элементов DOM, а не изменять его программно.

    let inputEl = fixture.debugElement.queryAll(By.css('.inputElClass'));
    let inputElement = inputEl.nativeElement;
    
        //set input value
    inputElement.value = 'test value';
    inputElement.dispatchEvent(new Event('input'));
    
    fixture.detectChanges();
    
    expect(component.registerForm.valid).toEqual(true);  // FIRST ASSERTION
    const errors = fixture.debugElement.queryAll(By.css('.error.username'));
    expect(errors.length).toBe(0);  
    
  2. Вам необходимо использовать методы API FormControl (markAsDirty, markAsDirty), как показано ниже.

    const formcontrol = component.registerForm.controls['username']
    formcontrol.setValue('VALID USERNAME');
    this.formName.markAsDirty()
    this.formName.markAsTouched()
    
...