Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Unit Testing Form Submit

I've a simple component which contains two input fields inside a form element. On clicking the submit button, it calls the addUser function on the component.

Component template is given below:

<div>
  <form [formGroup]="signupForm" (submit)="addUser($event)" role="form" class="form-horizontal">
      <label>Firstname:</label>
      <input type="text" formControlName="firstName"> 
      <label>Lastname:</label>
      <input type="text" formControlName="lastName">
      <input type="submit" id="btnSubmit" class="btn btn-primary btn-lg" value="Register" />
  </form>
</div>

Component definition is given below:

@Component({
  moduleId: module.id,  
  templateUrl: 'user.component.html'  
})
export class UserComponent {

  registered = false;

  constructor(
    private router: Router,
    private fb: FormBuilder,
    public authService: AuthService) {

      this.signupForm = this.fb.group({
            'firstName': ['', Validators.required],
            'lastName': ['', Validators.required]
        });        
  }

  addUser(event: any) {
      event.preventDefault();
      this.addUserInvoked = true;
      ......
      ......
      this.authService.register(this.signupForm.value)
        .subscribe(
        (res: Response) => {
            if (res.ok) {
                this.registered = true;
            }
        },
        (error: any) => {
            this.registered = false;                                
        });
  }
}

It works fine. However, in my unit test when I try to test that when click is invoked on submit button then the call to the addUser is made. But unfortunately the addUser function is not invoked.

Below is my sample unit test

class RouterStub {
  navigateByUrl(url: string) { return url; }
}


let comp: UserComponent;
let fixture: ComponentFixture<UserComponent>;

describe('UserComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ UserComponent ],
      schemas:      [NO_ERRORS_SCHEMA]
    });
  });

  compileAndCreate();
  tests();
});

function compileAndCreate() {
  beforeEach( async(() => {
    TestBed.configureTestingModule({
      providers: [        
        { provide: Router,      useClass: RouterStub },
        { provide: AuthService, useValue: authServiceStub },
        FormBuilder
      ]
    })
    .compileComponents().then(() => {
      fixture = TestBed.createComponent(UserComponent);
      comp = fixture.componentInstance;
    });
  }));
}

function tests() {
    it('should call addUser when submitted', () => { 
        const spy = spyOn(comp, 'addUser');  

        //*************below method doesn't work and it refreshes the page***************
        //let btnSubmit = fixture.debugElement.query(By.css('#btnSubmit'));
        //btnSubmit.nativeElement.click();

        let form = fixture.debugElement.query(By.css('form'));
        form.triggerEventHandler('submit', null);
        fixture.detectChanges();

        expect(comp.addUser).toHaveBeenCalled();
        expect(authServiceStub.register).toHaveBeenCalled();
        expect(comp.registered).toBeTruthy('user registered'); 
    });

}

I've tried

fixture.debugElement.query(By.css('#btnSubmit')).nativeElement.click()

and

fixture.debugElement.query(By.css('form')).triggerEventHandler('submit', null)

but I am still unable to invoke addUser function. I've seen a question already posted on SO here but it's not helpful either.

like image 504
A J Qarshi Avatar asked Nov 21 '16 14:11

A J Qarshi


People also ask

How to test submit in Angular?

Form Submit Event Testing Note. In order to test the form submit feature with this approach, you must make sure the type property on the submit button element is not set to button. If the button type is set to button, it will not trigger form submit on click.

How do you write a test case for reactive form?

Step 1: Get the login form from component. Step 2: Create a dummy login form default value object. Step 3: At-last, compare both the form group values with dummy object. Step 2: Get the username value from the component form builder.

What is SpyOn in Angular unit testing?

Test the Component logic using SpyOn. SpyOn is a Jasmine feature that allows dynamically intercepting the calls to a function and change its result. This example shows how spyOn works, even if we are still mocking up our service.


1 Answers

Here is sample code: 1 : Replace Xcomponent with your component name 2 : Replace formID with id of your form.

import {async, ComponentFixture, TestBed} from '@angular/core/testing';

    import {FormsModule} from '@angular/forms';
    import {By} from '@angular/platform-browser';

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

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

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

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

      it('should call save() method on form submit', () => {
        /*Get button from html*/
        fixture.detectChanges();
        const compiled = fixture.debugElement.nativeElement;
        // Supply id of your form below formID
        const getForm = fixture.debugElement.query(By.css('#formID'));
        expect(getForm.triggerEventHandler('submit', compiled)).toBeUndefined();
      });

    });
like image 63
XmenR Avatar answered Oct 23 '22 19:10

XmenR