Skip to content

Commit 1d4aa93

Browse files
committed
Fourth step: Login component
1 parent d3f6778 commit 1d4aa93

File tree

5 files changed

+103
-13
lines changed

5 files changed

+103
-13
lines changed

‎src/app/login/login.component.css‎

Whitespace-only changes.

‎src/app/login/login.component.html‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1-
<p>login works!</p>
1+
<form[formGroup]="form" (ngSubmit)="onSubmit()">
2+
<inputid="email" type="email" placeholder="Your email" />
3+
<span*ngIf="submitted && form.controls.email.invalid" id="email-error">
4+
Please enter a valid email.
5+
</span>
6+
<inputid="password" type="password" placeholder="********" />
7+
<span*ngIf="submitted && form.controls.password.invalid" id="password-error">
8+
Please enter a valid password.
9+
</span>
10+
<buttontype="submit">Sign in</button>
11+
</form>

‎src/app/login/login.component.spec.ts‎

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import{async,ComponentFixture,TestBed}from'@angular/core/testing';
22

33
import{LoginComponent}from'./login.component';
4+
import{ReactiveFormsModule}from'@angular/forms';
45

56
describe('LoginComponent',()=>{
67
letcomponent: LoginComponent;
78
letfixture: ComponentFixture<LoginComponent>;
89

910
beforeEach(async(()=>{
1011
TestBed.configureTestingModule({
11-
declarations: [LoginComponent]
12-
})
13-
.compileComponents();
12+
declarations: [LoginComponent],
13+
imports: [ReactiveFormsModule]
14+
}).compileComponents();
1415
}));
1516

1617
beforeEach(()=>{
@@ -22,4 +23,77 @@ describe('LoginComponent', () =>{
2223
it('should create',()=>{
2324
expect(component).toBeTruthy();
2425
});
26+
27+
it('should render form with email and password inputs',()=>{
28+
constelement=fixture.nativeElement;
29+
30+
expect(element.querySelector('form')).toBeTruthy();
31+
expect(element.querySelector('#email')).toBeTruthy();
32+
expect(element.querySelector('#password')).toBeTruthy();
33+
expect(element.querySelector('button')).toBeTruthy();
34+
});
35+
36+
it('should return model invalid when form is empty',()=>{
37+
expect(component.form.valid).toBeFalsy();
38+
});
39+
40+
it('should validate email input as required',()=>{
41+
constemail=component.form.controls.email;
42+
43+
expect(email.valid).toBeFalsy();
44+
expect(email.errors.required).toBeTruthy();
45+
});
46+
47+
it('should validate password input as required',()=>{
48+
constpassword=component.form.controls.password;
49+
50+
expect(password.valid).toBeFalsy();
51+
expect(password.errors.required).toBeTruthy();
52+
});
53+
54+
it('should validate email format',()=>{
55+
constemail=component.form.controls.email;
56+
email.setValue('test');
57+
consterrors=email.errors;
58+
59+
expect(errors.required).toBeFalsy();
60+
expect(errors.pattern).toBeTruthy();
61+
expect(email.valid).toBeFalsy();
62+
});
63+
64+
it('should validate email format correctly',()=>{
65+
constemail=component.form.controls.email;
66+
email.setValue('[email protected]');
67+
consterrors=email.errors||{};
68+
69+
expect(email.valid).toBeTruthy();
70+
expect(errors.required).toBeFalsy();
71+
expect(errors.pattern).toBeFalsy();
72+
});
73+
74+
it('should render email validation message when formControl is submitted and invalid',()=>{
75+
constelements: HTMLElement=fixture.nativeElement;
76+
expect(elements.querySelector('#email-error')).toBeFalsy();
77+
78+
elements.querySelector('button').click();
79+
80+
fixture.detectChanges();
81+
expect(elements.querySelector('#email-error')).toBeTruthy();
82+
expect(elements.querySelector('#email-error').textContent).toContain(
83+
'Please enter a valid email.'
84+
);
85+
});
86+
87+
it('should render password validation message when formControl is submitted and invalid',()=>{
88+
constelements: HTMLElement=fixture.nativeElement;
89+
expect(elements.querySelector('#password-error')).toBeFalsy();
90+
91+
elements.querySelector('button').click();
92+
93+
fixture.detectChanges();
94+
expect(elements.querySelector('#password-error')).toBeTruthy();
95+
expect(elements.querySelector('#password-error').textContent).toContain(
96+
'Please enter a valid password.'
97+
);
98+
});
2599
});

‎src/app/login/login.component.ts‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import{Component,OnInit}from'@angular/core';
2+
import{FormGroup,FormBuilder,Validators}from'@angular/forms';
23

34
@Component({
45
selector: 'app-login',
5-
templateUrl: './login.component.html',
6-
styleUrls: ['./login.component.css']
6+
templateUrl: './login.component.html'
77
})
88
exportclassLoginComponentimplementsOnInit{
9+
form: FormGroup;
10+
submitted=false;
911

10-
constructor(){}
12+
constructor(privateformBuilder: FormBuilder){}
1113

1214
ngOnInit(){
15+
this.form=this.formBuilder.group({
16+
email: ['',[Validators.required,Validators.pattern('[^ @]*@[^ @]*')]],
17+
password: ['',Validators.required]
18+
});
1319
}
1420

21+
onSubmit(){
22+
this.submitted=true;
23+
}
1524
}

‎src/app/login/login.module.ts‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@ import{CommonModule } from '@angular/common'
33

44
import{LoginRoutingModule}from'./login-routing.module';
55
import{LoginComponent}from'./login.component';
6-
6+
import{ReactiveFormsModule}from'@angular/forms';
77

88
@NgModule({
99
declarations: [LoginComponent],
10-
imports: [
11-
CommonModule,
12-
LoginRoutingModule
13-
]
10+
imports: [CommonModule,LoginRoutingModule,ReactiveFormsModule]
1411
})
15-
exportclassLoginModule{}
12+
exportclassLoginModule{}

0 commit comments

Comments
(0)