Angular Form is not valid even after all form fields are valid
Asked Answered
P

3

8

I m trying to solve one Angular form validation Hands on, for that i made the below form, this form is passing all the test cases except one, looks like the problem is with testing file(app.component.spec.ts) that is readable only working Demo of the handson shows form status as VALID. but it fails testing

I am stuck with this handson form last two days.Your help is cordially appreciated.

-------------------[read only]app.component.spec.ts----------

import { AppComponent } from './app.component';
import { ReactiveFormsModule, FormControl, AbstractControl, FormGroup } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { asNativeElements, DebugElement } from '@angular/core';

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

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

    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  }));

  // it('should create the component', () => {
  //   expect(component).toBeTruthy();
  // });

  it('form should be invalid when empty', () => {
    expect(component.contactForm.invalid).toBeTruthy();
  });

  it('form should be valid on entering required fields', () => {
    fixture.detectChanges(); // ngOninit()
    component.name.setValue('david');
    component.phone.setValue('9999999999');

    expect(component.contactForm.valid).toBeTruthy();
  });

  describe('#name', () => {
    let name: AbstractControl;

    beforeEach(() => {
      name = component.contactForm.controls['name'];
    });

    it('should be invalid if empty', () => {
      expect(name.invalid).toBeTruthy();
    });

    it('should be a "required" field', () => {
      expect(name.errors['required']).toBeTruthy();
    });

    it('should be valid if some value is present', fakeAsync(() => {
      name.setValue('david');
      expect(name.valid).toBeTruthy();
    }));
  });

  describe('#phone', () => {
    let phone: AbstractControl;
    beforeEach(() => {
      phone = component.contactForm.controls['phone'];
    });

    it('should be invalid if empty', () => {
      expect(phone.invalid).toBeTruthy();
    });

    it('should have "required" validation', () => {
      expect(phone.errors['required']).toBeTruthy();
    });

    it('should accept only numbers(pattern validation)', () => {
      phone.setValue('abc');
      expect(phone.errors['pattern']).toBeTruthy();
    });

    it('should have 10 digits(minlength & maxlength validation)', () => {
      phone.setValue('123');
      expect(phone.errors['minlength']).toBeTruthy();
      phone.setValue('12333333333');
      expect(phone.errors['maxlength']).toBeTruthy();
    });
  });

  describe('#address - zip', () => {
    let address;
    let zip;
    beforeEach(() => {
      address = component.contactForm.controls['address'] as FormGroup ;
      zip = address.controls['zip'] ;
      fixture.detectChanges(); // ngOnInit()
    });
    it('should be a number', fakeAsync(() => {
      zip.setValue('abc');
      expect(zip.errors['pattern']).toBeTruthy();
      zip.setValue('123456');
      fixture.detectChanges();
      expect(zip.valid).toBeTruthy();
    }));
    it('should have 6 digits exactly', () => {
      // enter 3 digits and check for minlength validation
      zip.setValue('123');
      expect(zip.errors['minlength']).toBeTruthy();

      // enter 7 digits and check for maxlength validation
      zip.setValue('1234567');
      fixture.detectChanges(); // update changes, angular will not do for you automatically
      expect(zip.errors['maxlength']).toBeTruthy();
    });
  });
});

Here is the test error

AppComponent
 ✖ form should be valid on entering required fields
   HeadlessChrome 75.0.3770 (Linux 0.0.0)
  Expected false to be truthy.
    at UserContext. (src/app/app.component.spec.ts:35:41)
    at ZoneDelegate.invoke (node_modules/zone.js/dist/zone-evergreen.js:359:1)
    at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke 
 (node_modules/zone.js/dist/zone-testing.js:308:1)
       at ZoneDelegate.invoke (node_modules/zone.js/dist/zone-evergreen.js:358:1)
Preschool answered 4/10, 2019 at 5:34 Comment(5)
It's still not valid because you gave no values for street, city and zip?Ivatts
thanks @Ivatts for having a look, but i have no need to apply validations on street and city. Can you please explain a bit more.Preschool
I think zip is required, but you aren't providing it in the tests.Saenz
@TsvetanGanev that's not an issue brother by the way all other things are provided by hackerrank,I had deal with app.component.html and app.component.ts files onlyPreschool
Your test ist failing because zip has no value, but a value is required. Either remove the validation for the zip property or provide a value for it within your tests. See my answerIvatts
I
6

Your test ist failing because zip has no value, but a value is required. Either remove the validation for the zip property or provide a value within your tests.

Removing the validation for zip within AppComponent would look like this

contactForm = new FormGroup({
        name: new FormControl(null, [ Validators.required,
                                    Validators.minLength(4),
                                    Validators.maxLength(10)]),
        phone: new FormControl(null,  [ Validators.required,
                                        Validators.pattern("^[0-9]*$"),        Validators.minLength(10),
                                        Validators.maxLength(10) ]),
        address: new FormGroup({
        street: new FormControl(null),
        city: new FormControl(null),
        zip: new FormControl(null)
        })
    });

Passing in a value for zip within your tests would look like this

    it('form should be valid on entering required fields', () => {
        fixture.detectChanges(); // ngOninit()
        component.name.setValue('david');
        component.phone.setValue('9999999999');
        component.zip.setValue('123456');

        expect(component.contactForm.valid).toBeTruthy();
      });

The second option only works if you have setters for these properties in your component. In your stackblitz there are only getters.

Ivatts answered 4/10, 2019 at 8:13 Comment(1)
yes, I got it now. Actually i don't need to apply required validation for zip. Thank you very much brother.Preschool
W
0

Add this piece of code to app.component.ts:

contactForm = new FormGroup({

  name: new FormControl(null,[ 
  Validators.required,
  Validators.minLength(4),
  Validators.maxLength(10)]),                        
  phone: new FormControl(null,[
  Validators.required,
  Validators.pattern("^[0-9]*$"),
  Validators.minLength(10),
  Validators.maxLength(10) ]),
                                        
  address: new FormGroup({
    street: new FormControl(null),
    city: new FormControl(null),
    zip: new FormControl(null,[ 
    Validators.minLength(6),
    Validators.maxLength(6),
    Validators.pattern('^[0-6]*$')])
    })
});
Weather answered 27/7, 2020 at 12:25 Comment(1)
Just add this piece of code in your app.component.ts file. And the program will compile all your test cases.Weather
P
0

If you want to check Your form is Valid or not, which means Empty or not, then you should use the. this.formData.valid(); In this method u get a response if your form is invalid then you get an error, otherwise, you will get true.

Popliteal answered 25/7, 2021 at 17:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.