bali
bali

Reputation: 337

Angular Form is not valid even after all form fields are valid

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)

Upvotes: 8

Views: 15708

Answers (3)

Kalka Prasad
Kalka Prasad

Reputation: 1

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.

Upvotes: 0

Bhavna Singh
Bhavna Singh

Reputation: 1

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]*$')])
    })
});

Upvotes: 0

Riscie
Riscie

Reputation: 4629

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.

Upvotes: 6

Related Questions