Skip to content

Added forms component unit test cases examples #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ All the scenarios are listed here below and nicely linked to the source file.
_Learn how to mock out nested components which you don't want to necessarily test_
* [testing component with service deps](./src/app/components/component-mock-external.component.spec.ts)
_Simple test of component logic by manually instantiating the component_
* [testing component with template-driven form](./src/app/components/template-driven-forms.component.spec.ts)
_Simple test of component with template driven form_
* [testing component with reactive (model-driven) form](./src/app/components/reactive-forms.compnent.spec.ts)
_Simple test of component with reactive form_
1. [**Testing Services**](./src/app/services)
* [Simple stateless function](./src/app/services/greeting.service.spec.ts)
_Learn about different ways of injecting a service into a test case as well as how to test service methods._
Expand Down
140 changes: 140 additions & 0 deletions src/app/components/reactive-forms.compnent.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { ReactiveFormsModule, FormsModule } from "@angular/forms";
import { ReactiveFormsComponent, User } from "./reactive-forms.component";


describe('Component: ReactiveForms', () => {

let component: ReactiveFormsComponent;
let fixture: ComponentFixture<ReactiveFormsComponent>;

beforeEach(() => {

// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [ReactiveFormsModule, FormsModule],
declarations: [ReactiveFormsComponent]
});

// create component and test fixture
fixture = TestBed.createComponent(ReactiveFormsComponent);

// get test component from the fixture
component = fixture.componentInstance;
component.ngOnInit();
});

it('form invalid when empty', () => {
expect(component.form.valid).toBeFalsy();
});

it('name field validity', () => {
let errors = {};
let name = component.form.get('name');
expect(name.valid).toBeFalsy();

errors = name.errors || {};
expect(errors['required']).toBeTruthy();

name.setValue("Jo");
errors = name.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['minlength']).toBeTruthy();

name.setValue("John qwerty asdfgh zxcvbnm Doe");
errors = name.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['minlength']).toBeFalsy();
expect(errors['maxlength']).toBeTruthy();

name.setValue("John Doe");
errors = name.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['minlength']).toBeFalsy();
expect(errors['maxlength']).toBeFalsy();
});

it('email field validity', () => {
let errors = {};
let email = component.form.get('email');
expect(email.valid).toBeFalsy();

errors = email.errors || {};
expect(errors['required']).toBeTruthy();

email.setValue("test");
errors = email.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['pattern']).toBeTruthy();

email.setValue("[email protected]");
errors = email.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['pattern']).toBeFalsy();
});

it('password field validity', () => {
let errors = {};
let password = component.form.get('password');

errors = password.errors || {};
expect(errors['required']).toBeTruthy();

password.setValue("Qwerty");
errors = password.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['minlength']).toBeTruthy();

password.setValue("Qwertyui9!");
errors = password.errors || {};
expect(errors['required']).toBeFalsy();
expect(errors['minlength']).toBeFalsy();
});

it('confirm password field validity', () => {
let passwordErrors = {};
let confirmPasswordErrors = {};
let password = component.form.get('password');
let confirmPassword = component.form.get('confirmPassword');

password.setValue("Qwertyui9!");
passwordErrors = password.errors || {};
confirmPasswordErrors = confirmPassword.errors || {};
expect(passwordErrors['required']).toBeFalsy();
expect(confirmPasswordErrors['required']).toBeTruthy();

password.setValue("Qwertyui9!");
confirmPassword.setValue("Qwertyui");
confirmPasswordErrors = confirmPassword.errors || {};
expect(confirmPasswordErrors['required']).toBeFalsy();
expect(confirmPasswordErrors['passwordDoesntMatch']).toBeTruthy();

password.setValue("Qwertyui9!");
confirmPassword.setValue("Qwertyui9!");
confirmPasswordErrors = confirmPassword.errors || {};
expect(confirmPasswordErrors['required']).toBeFalsy();
expect(confirmPasswordErrors['passwordDoesntMatch']).toBeFalsy();

});

it('submitting a form emits a user', () => {
expect(component.form.valid).toBeFalsy();
component.form.get('name').setValue("John Doe");
component.form.get('email').setValue("[email protected]");
component.form.get('password').setValue("Qwertyui9!");
component.form.get('confirmPassword').setValue("Qwertyui9!");
expect(component.form.valid).toBeTruthy();

let user: User;
component.register.subscribe((value) => user = value);

// Trigger the signup function
component.signup();

// Testing the emitted value is correct
expect(user.name).toBe("John Doe");
expect(user.email).toBe("[email protected]");
expect(user.password).toBe("Qwertyui9!");
expect(user.confirmPassword).toBe("Qwertyui9!");
});
});
70 changes: 70 additions & 0 deletions src/app/components/reactive-forms.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { FormGroup, Validators, FormBuilder, FormControl } from "@angular/forms";

export class User {
constructor(public name: string, public email: string,
public password: string, public confirmPassword: string) {
}
}

@Component({
selector: 'app-signup',
template: `
<form (ngSubmit)="signup()" [formGroup]="form">
<label>Name</label>
<input type="text" formControlName="name">
<label>Email</label>
<input type="email" formControlName="email">
<label>Password</label>
<input type="password" formControlName="password">
<label>Confirm Password</label>
<input type="password" formControlName="confirmPassword">
<button type="submit">Sign up</button>
</form>
`
})
export class ReactiveFormsComponent {
@Output() register = new EventEmitter<User>();
form: FormGroup;

constructor(private formBuilder: FormBuilder) { }

ngOnInit() {
this.form = this.formBuilder.group({
name: ['', [
Validators.required,
Validators.minLength(3),
Validators.maxLength(20)]],
email: ['', [
Validators.required,
Validators.pattern("[^ @]*@[^ @]*")]],
password: ['', [
Validators.required,
Validators.minLength(8)]],
confirmPassword: ['', [
Validators.required,
this.checkConfirmPassword.bind(this)]],
});
}

checkConfirmPassword(control: FormControl):{[s: string]: boolean} {
if(this.form && this.form.value.password !== control.value) {
return { 'passwordDoesntMatch':true };
}
return null;
}

signup() {
console.log(`Signup` + JSON.stringify(this.form.value));
if (this.form.valid) {
this.register.emit(
new User(
this.form.value.name,
this.form.value.email,
this.form.value.password,
this.form.value.confirmPassword
)
);
}
}
}
79 changes: 79 additions & 0 deletions src/app/components/template-driven-forms.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { FormsModule } from "@angular/forms";
import { TemplateDrivenFormsComponent, UserLogin } from "./template-driven-forms.component";


describe('Component: TemplateDrivenFormsComponent', () => {

let component: TemplateDrivenFormsComponent;
let fixture: ComponentFixture<TemplateDrivenFormsComponent>;

beforeEach(() => {

// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [FormsModule],
declarations: [TemplateDrivenFormsComponent]
});

fixture = TestBed.createComponent(TemplateDrivenFormsComponent);

component = fixture.componentInstance;

fixture.detectChanges();

});

it('form invalid when empty', () => {
// The fixture.whenStable() returns a promise that resolves when the JavaScript engine's task queue becomes empty.
fixture.whenStable().then( () => {
expect(component.form.valid).toBeFalsy();
});

});

it('form invalid when incompletely filled', () => {
fixture.whenStable().then( () => {
component.form.controls['email'].setValue('[email protected]');
fixture.detectChanges();
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(component.form.valid).toBeFalsy();
expect(component.form.controls.password.errors.required).toBeTruthy();
});
});

});

it('form valid when completely filled', () => {
fixture.whenStable().then( () => {
component.form.controls['email'].setValue('[email protected]');
component.form.controls['password'].setValue('Qwertyui9!');
fixture.detectChanges();
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(component.form.valid).toBeTruthy();
});
});

});

it('form valid & expect correct logon credentials when clicked submit', () => {
fixture.whenStable().then( () => {
component.form.controls['email'].setValue('[email protected]');
component.form.controls['password'].setValue('Qwertyui9!');
fixture.detectChanges();
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(component.form.valid).toBeTruthy();
let user: UserLogin;
component.login.subscribe((value) => user = value);
component.logon();
expect(user.email).toBe("[email protected]");
expect(user.password).toBe("Qwertyui9!");
});
});

});

});
43 changes: 43 additions & 0 deletions src/app/components/template-driven-forms.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Component, EventEmitter, Output, ViewChild } from '@angular/core';

export class UserLogin {
constructor(public email: string, public password: string) {
}
}

@Component({
selector: 'app-login',
template: `
<form (ngSubmit)="logon()" #f="ngForm">
<label>Email</label>
<input type="email" name="email" [(ngModel)]="model.email" required pattern="[^ @]*@[^ @]*">
<label>Password</label>
<input type="password" name="password" [(ngModel)]="model.password" required minlength="8">
<button type="submit">Sign up</button>
</form>
`
})
export class TemplateDrivenFormsComponent {
@Output() login = new EventEmitter<UserLogin>();
@ViewChild('f') form: any;
model: UserLogin = {
email: '',
password: ''
};

constructor() { }

ngOnInit() { }

logon() {
console.log(`Logon` + JSON.stringify(this.model));
if (this.form.valid) {
this.login.emit(
new UserLogin(
this.form.value.email,
this.form.value.password
)
);
}
}
}