7

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)
bali
  • 327
  • 1
  • 5
  • 14
  • It's still not valid because you gave no values for street, city and zip? – Riscie Oct 04 '19 at 06:30
  • thanks @Riscie for having a look, but i have no need to apply validations on street and city. Can you please explain a bit more. – bali Oct 04 '19 at 06:38
  • I think `zip` is required, but you aren't providing it in the tests. – Tsvetan Ganev Oct 04 '19 at 07:55
  • @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 only – bali Oct 04 '19 at 08:06
  • 1
    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 answer – Riscie Oct 04 '19 at 08:10

3 Answers3

5

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.

Riscie
  • 3,775
  • 1
  • 24
  • 31
  • 1
    yes, I got it now. Actually i don't need to apply **required validation** for zip. Thank you very much brother. – bali Oct 04 '19 at 09:55
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]*$')])
    })
});
elcortegano
  • 2,444
  • 11
  • 40
  • 58
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.