Reputation: 2992
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.
Upvotes: 14
Views: 17467
Reputation: 27
I had the same problem and the solution for me was that I had to import the 'FormsModule' into the configuration of my testing module.
TestBed.configureTestingModule({
imports: [FormsModule]
});
Maybe this can help ?
Upvotes: 1
Reputation: 47
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();
});
});
Upvotes: 4
Reputation: 9392
I could do it like this:
let yourService: YourService;
beforeEach(() => {
fixture = TestBed.createComponent(YourComponent);
component = fixture.componentInstance;
store = TestBed.get(YourService);
fixture.detectChanges();
});
it('should call the right funtion', () => {
spyOn(yourService, 'yourMethod');// or spyOn(component, 'yourMethod');
const fakeEvent = { preventDefault: () => console.log('preventDefault') };
fixture.debugElement.query(By.css('form')).triggerEventHandler('submit', fakeEvent);
expect(yourService.yourMethod).toHaveBeenCalledWith(
//your logic here
);
});
Upvotes: 2