My apis is http://dradiobeats.x10host.com/public/api/areas
my app.component.ts:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
import { Subscription } from 'rxjs';
import { Post } from './post.model';
import { PostsService } from './posts.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
loadedPosts: Post[] = [];
isFetching = false;
error = null;
private errorSub: Subscription;
constructor(private http: HttpClient, private postsService: PostsService) {}
ngOnInit() {
this.errorSub = this.postsService.error.subscribe(errorMessage => {
this.error = errorMessage;
});
this.isFetching = true;
this.postsService.fetchPosts().subscribe(
posts => {
this.isFetching = false;
this.loadedPosts = posts;
},
error => {
this.isFetching = false;
this.error = error.message;
}
);
}
onCreatePost(postData: Post) {
// Send Http request
this.postsService.createAndStorePost( postData.id, postData.name, postData.domain, postData.description , postData.picture);
}
onFetchPosts() {
// Send Http request
this.isFetching = true;
this.postsService.fetchPosts().subscribe(
posts => {
this.isFetching = false;
this.loadedPosts = posts;
},
error => {
this.isFetching = false;
this.error = error.message;
console.log(error);
}
);
}
onClearPosts() {
// Send Http request
this.postsService.deletePosts().subscribe(() => {
this.loadedPosts = [];
});
}
onHandleError() {
this.error = null;
}
ngOnDestroy() {
this.errorSub.unsubscribe();
}
}
my posts.service.ts
import { Injectable } from '#angular/core';
import {
HttpClient,
HttpHeaders,
HttpParams,
HttpEventType
} from '#angular/common/http';
import { map, catchError, tap } from 'rxjs/operators';
import { Subject, throwError } from 'rxjs';
import { Post } from './post.model';
#Injectable({ providedIn: 'root' })
export class PostsService {
error = new Subject<string>();
constructor(private http: HttpClient) {}
createAndStorePost( id: string,
name: string,
description: string,
domain: string,
picture: any ) {
const postData: Post = { id , domain , name, description, picture };
this.http
.post<{ name: string , description: string , domain: string , picture: string }>(
'http://dradiobeats.x10host.com/api/areas',
postData,
{
observe: 'response'
}
)
.subscribe(
responseData => {
console.log(responseData);
},
error => {
this.error.next(error.message);
}
);
}
fetchPosts() {
let searchParams = new HttpParams();
searchParams = searchParams.append('print', 'pretty');
searchParams = searchParams.append('custom', 'key');
return this.http
.get<{ [key: string]: Post}>(
'http://dradiobeats.x10host.com/api/areas',
{
headers: new HttpHeaders({ 'Custom-Header': 'Hello' }),
params: searchParams,
responseType: 'json'
}
)
.pipe(
map(responseData => {
const postsArray: Post[] = [];
for (const key in responseData) {
if (responseData.hasOwnProperty(key)) {
postsArray.push({ ...responseData[key], id: key });
}
}
return postsArray;
}),
catchError(errorRes => {
// Send to analytics server
return throwError(errorRes);
})
);
}
deletePosts() {
return this.http
.delete('http://dradiobeats.x10host.com/api/areas', {
observe: 'events',
responseType: 'text'
})
.pipe(
tap(event => {
console.log(event);
if (event.type === HttpEventType.Sent) {
// ...
}
if (event.type === HttpEventType.Response) {
console.log(event.body);
}
})
);
}
}
my posts.model.ts
export interface Post {
id: string;
name: string;
domain: string;
description: string;
picture: any;
}
my logging-interceptor.service.ts
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEventType
} from '#angular/common/http';
import { tap } from 'rxjs/operators';
export class LoggingInterceptorService implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
console.log('Outgoing request');
console.log(req.url);
console.log(req.headers);
return next.handle(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
console.log('Incoming response');
console.log(event.body);
}
})
);
}
}
my auth-interceptor.service.ts
import {
HttpInterceptor,
HttpRequest,
HttpHandler
} from '#angular/common/http';
export class AuthInterceptorService implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
const modifiedRequest = req.clone({
headers: req.headers.append('Auth', 'xyz')
});
return next.handle(modifiedRequest);
}
}
my app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
const routes: Routes = [];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
my app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { AppComponent } from './app.component';
import { AuthInterceptorService } from './auth-interceptor.service';
import { LoggingInterceptorService } from './logging-interceptor.service';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule, HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: LoggingInterceptorService,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptorService,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
my app.component.spec.ts
import { TestBed, async } from '#angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'ng-complete-guide-update'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('ng-complete-guide-update');
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to ng-complete-guide-update!');
});
});
my app.component.html
import { TestBed, async } from '#angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'ng-complete-guide-update'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('ng-complete-guide-update');
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to ng-complete-guide-update!');
});
});
my app.component.css
.container {
margin-top: 30px;
}
.row {
margin: 20px 0;
}
I am only getting data not elements [id ,name,description,domain,picture]why??
Related
I have created a test case for my component with all dependency but when I execute the test case it shows error.
My unit test scenario is when form data is submitted formSubmit() method will be called and it send the data authservice there it makes an HTTP request and return some response. After that it navigate to another page.
Can anyone provide a solution for this test case??
Here are my code
login.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
// Services
import { ActivatedRoute, Router } from '#angular/router';
import { AuthService } from 'src/app/Service/auth.service';
// Material Component
import { MatSnackBar } from '#angular/material/snack-bar';
import { Title } from '#angular/platform-browser';
import { HttpErrorResponse } from '#angular/common/http';
import { LoginResponse } from '../../Model/auth';
import { duration, Notify } from '../../Model/notify';
import { NotificationComponent } from '../../shared/notification/notification.component';
import { NotifyService } from '../../Service/notify.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
})
export class LoginComponent implements OnInit {
constructor(
private documentTitle: Title,
private fb: FormBuilder,
private router: Router,
private route: ActivatedRoute,
private auth: AuthService,
private notify: NotifyService
) {}
passwordHide!: boolean;
returnUrl!: string;
pageTitle!: string;
loginForm!: FormGroup;
res!: LoginResponse;
ngOnInit(): void {
this.passwordHide = true;
this.pageTitle = 'Login | Online Shopping for Men & Women Shoes';
this.documentTitle.setTitle(this.pageTitle);
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '';
this.loginForm = this.fb.group({
username: ['', [Validators.required, Validators.minLength(8)]],
password: ['', [Validators.required, Validators.minLength(6)]],
});
}
/**
* send a request to auth service to make HTTP POST request
* if form is valid
*/
formSubmit() {
if (this.loginForm.valid) {
console.log(this.returnUrl);
this.auth.login(this.loginForm.value).subscribe({
next: (data: LoginResponse) => {
console.log(data);
this.res = data;
localStorage.setItem('access_token', data.accessToken);
this.auth.authStatusToggle(true);
this.router.navigateByUrl(this.returnUrl);
},
error: (error: HttpErrorResponse) => {
console.log(error);
if (error.status == 400) {
this.notify.warning(error.error.message);
} else {
this.notify.warning(error.error.message);
}
},
});
}
}
}
login.component.spec.ts
import { CommonModule } from '#angular/common';
import { ComponentFixture, TestBed, getTestBed } from '#angular/core/testing';
import {
FormBuilder,
FormsModule,
ReactiveFormsModule,
Validators,
} from '#angular/forms';
import { AppModule } from 'src/app/app.module';
import { AuthService } from 'src/app/Service/auth.service';
import { LoginComponent } from './login.component';
import * as Rx from 'rxjs';
import { Title } from '#angular/platform-browser';
import { HttpClientModule } from '#angular/common/http';
import {
HttpClientTestingModule,
HttpTestingController,
} from '#angular/common/http/testing';
import { LoginResponse } from 'src/app/Model/auth';
import { ActivatedRoute, Router } from '#angular/router';
import { RouterTestingModule } from '#angular/router/testing';
import { NotifyService } from 'src/app/Service/notify.service';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let authService = jasmine.createSpyObj('AuthService', ['login']);
let mockRouter = jasmine.createSpyObj('Router', ['navigate']);
let route: ActivatedRoute;
let documentTitle: Title;
let injector: TestBed;
let fb = new FormBuilder();
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [LoginComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
AppModule,
HttpClientModule,
HttpClientTestingModule,
RouterTestingModule,
],
providers: [
{ provide: FormBuilder, useValue: fb },
{ provide: AuthService, useValue: authService },
{ provide: Router, useValue: mockRouter },
{
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: {
returnUrl: '',
},
},
},
},
NotifyService,
Title,
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
fixture.detectChanges();
component = fixture.componentInstance;
injector = getTestBed();
route = TestBed.get(ActivatedRoute);
documentTitle = injector.get(Title);
fb = TestBed.inject(FormBuilder);
component.passwordHide = true;
component.pageTitle = 'Login | Online Shopping for Men & Women Shoes';
documentTitle.setTitle(component.pageTitle);
component.returnUrl = route.snapshot.queryParams['returnUrl'] || '';
component.loginForm = fb.group({
username: ['', [Validators.required, Validators.minLength(8)]],
password: ['', [Validators.required, Validators.minLength(6)]],
});
});
it('should form submit successfully', () => {
// console.log(route.snapshot.queryParamMap.get('returnUrl'))
// console.log(component.returnUrl);
component.loginForm.get('username')?.setValue('ramkumar');
component.loginForm.get('password')?.setValue('Ramkumar#45');
expect(component.loginForm.valid).toBeTruthy();
authService.login.and.returnValue(
Rx.of({
accessToken: 'testToken',
username: 'test',
userId: 1,
} as LoginResponse)
);
component.formSubmit();
expect(component.res).toEqual({
accessToken: 'testToken',
username: 'test',
userId: 1,
} as LoginResponse);
expect(mockRouter.navigate).toHaveBeenCalledWith(['']);
});
});
auth.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
import { Observable, Subject } from 'rxjs';
import { environment } from 'src/environments/environment';
import { Login, LoginResponse, Register } from '../Model/auth';
import { JwtHelperService } from '#auth0/angular-jwt';
import { UserResponse } from '../Model/user';
#Injectable({
providedIn: 'root',
})
export class AuthService {
private AUTH_API: string = environment.AUTH_API;
private USER_API: string = environment.USER_API;
public isUserLoggedIn: boolean = this.getAuthStatus();
private isLoggedIn: Subject<boolean> = new Subject<boolean>();
private token: any = localStorage.getItem('access_token')?.toString() || null;
private jwt: JwtHelperService;
/**
* Dependency Injections
* #param http
* #param route
*/
constructor(private http: HttpClient, private route: Router) {
this.jwt = new JwtHelperService();
this.isLoggedIn.subscribe((value) => {
console.log(value);
this.isUserLoggedIn = value;
});
}
/**
* Send user credentials to Auth API for create JWT token
* #param data
*/
login(data: Login): Observable<LoginResponse> {
return this.http.post<LoginResponse>(`${this.AUTH_API}/CreateToken`, data);
}
/**
* Send HTTP request to register new user
* #param data
*/
register(data: Register): Observable<UserResponse> {
return this.http.post<UserResponse>(`${this.USER_API}`, data);
}
/**
* Remove JWT token from localstorage to logout
*/
logout(): void {
localStorage.removeItem('access_token');
this.authStatusToggle(false);
if (this.getUserToken() == null) this.route.navigate(['login']);
}
/**
* get user JWT token from localstorage
* return token as string or null
*/
getUserToken(): string {
if (localStorage.getItem('access_token') != null) {
this.token = localStorage.getItem('access_token')?.toString() || null;
} else {
this.token = null;
}
return this.token;
}
authStatusToggle(value: boolean) {
this.isLoggedIn.next(value);
}
getAuthStatus(): boolean {
let token = localStorage.getItem('access_token')?.toString();
console.log(token);
if (token == null) {
return false;
}
return true;
}
}
I'm doing an angular project using the NZ-Zorro library and I'm having a hard time finding what are these parameters that aren't being solved from NzModalRef, when I try to run the test --code-coverage to do the tests. I get this error.
Error: NG0204: Can't resolve all parameters for NzModalRef: (?, ?, ?).
That's my .spec
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { MinistryService } from './../../ministry.service';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import {
NzModalModule,
NzModalService,
NzModalRef,
} from 'ng-zorro-antd/modal';
import { MembersService } from '../../members.service';
import { ComponentFixture } from '#angular/core/testing';
import {
HttpClientTestingModule,
HttpTestingController,
} from '#angular/common/http/testing';
import {
UntypedFormBuilder,
UntypedFormGroup,
Validators,
FormsModule,
} from '#angular/forms';
import { TestBed } from '#angular/core/testing';
import { HttpClient } from '#angular/common/http';
import { FormNewMemberComponent } from './form-new-member.component';
import { ReactiveFormsModule } from '#angular/forms';
describe('FormNewMemberComponent', () => {
let component: FormNewMemberComponent;
let fixture: ComponentFixture<FormNewMemberComponent>;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
let fb: UntypedFormBuilder;
let validateForm: UntypedFormGroup;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [FormNewMemberComponent],
imports: [
HttpClientTestingModule,
ReactiveFormsModule,
NzModalModule,
FormsModule,
BrowserAnimationsModule,
],
providers: [
MembersService,
NzModalService,
HttpClient,
Validators,
NzModalRef,
MinistryService,
NzNotificationService,
UntypedFormBuilder,
],
}).compileComponents();
httpClient = TestBed.inject(HttpClient);
httpTestingController = TestBed.inject(HttpTestingController);
fb = TestBed.inject(UntypedFormBuilder);
fixture = TestBed.createComponent(FormNewMemberComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
My .ts
import { NzModalRef } from 'ng-zorro-antd/modal';
import { Ministry } from './../../ministry/ministry.model';
import { MemberPageComponent } from './../member-page.component';
import { MembersService } from '../../members.service';
import { Component, OnInit } from '#angular/core';
import {
UntypedFormBuilder,
UntypedFormControl,
UntypedFormGroup,
Validators,
} from '#angular/forms';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { MinistryService } from '../../ministry.service';
#Component({
selector: 'app-form-new-member',
templateUrl: './form-new-member.component.html',
styleUrls: ['./form-new-member.component.scss'],
})
export class FormNewMemberComponent implements OnInit {
validateForm!: UntypedFormGroup;
isVisible = false;
pagina!: MemberPageComponent;
members: any;
ministrys: Ministry[] = []
listOfMinistrys!: Ministry[]
createNotificationSuccess(type: string): void {
this.notification.create(
type,
'Sucesso!',
'Membro adicionado.',
{nzDuration: 2000}
);
}
createNotificationError(type: string): void {
this.notification.create(
type,
'Erro!',
'Membro não foi adicionado.',
{nzDuration: 2000}
);
}
constructor(
private fb: UntypedFormBuilder,
private membersService: MembersService,
private nzModalRef: NzModalRef,
private notification: NzNotificationService,
private ministryService: MinistryService
) {}
ngOnInit(): void {
this.validateForm = this.fb.group({
email: [null, [Validators.email, Validators.required]],
password: [null, [Validators.required]],
checkPassword: [null, [Validators.required, this.confirmationValidator]],
name: [null, [Validators.required]],
phoneNumber: [null, [Validators.required]],
cpf: [null, [Validators.required]],
rg: [null, [Validators.required]],
ministry: [null, [Validators.required]],
address: [null, [Validators.required]],
});
this.showMinistry()
}
submitForm(): void {
if (this.validateForm.valid) {
this.membersService.create(this.validateForm.value).subscribe(
(success) => {
this.createNotificationSuccess('success')
this.destroyModal();
},
(error) => {
this.createNotificationError('error')
}
);
} else {
Object.values(this.validateForm.controls).forEach((control) => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
updateConfirmValidator(): void {
Promise.resolve().then(() =>
this.validateForm.controls['checkPassword'].updateValueAndValidity()
);
}
confirmationValidator = (
control: UntypedFormControl
): { [s: string]: boolean } => {
if (!control.value) {
return { required: true };
} else if (control.value !== this.validateForm.controls['password'].value) {
return { confirm: true, error: true };
}
return {};
};
destroyModal(): void {
this.nzModalRef.destroy({ newMember: this.validateForm.value });
}
showMinistry(){
this.ministryService.getMinistrys().subscribe((data) => {
this.ministrys = data;
this.listOfMinistrys = [...this.ministrys];
});
}
}
My service
import { Injectable } from '#angular/core';
import { Member } from './member-page/members.model';
import { Observable, take} from 'rxjs';
import { HttpClient } from '#angular/common/http';
const apiMembers = 'http://localhost:3000/membrosBd';
#Injectable({
providedIn: 'root',
})
export class MembersService {
constructor(private http: HttpClient) { }
getMembers(): Observable<Member[]> {
return this.http.get<Member[]>(apiMembers)
}
create(member: Member): Observable<Member>{
return this.http.post<Member>(apiMembers, member).pipe(take(1));
}
}
And my module
import { NzNotificationModule } from 'ng-zorro-antd/notification';
import { HttpClientModule } from '#angular/common/http';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { NzPaginationModule } from 'ng-zorro-antd/pagination';
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { MemberPageComponent } from './member-page/member-page.component';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
import { NzModalModule, NzModalRef } from 'ng-zorro-antd/modal';
import { FormNewMemberComponent } from './member-page/form-new-member/form-new-member.component';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzSelectModule } from 'ng-zorro-antd/select';
import { MinistryComponent } from './ministry/ministry.component';
import { NzListModule } from 'ng-zorro-antd/list';
#NgModule({
declarations: [
MemberPageComponent,
FormNewMemberComponent,
MinistryComponent,
],
imports: [
CommonModule,
NzTableModule,
NzPaginationModule,
NzAutocompleteModule,
NzButtonModule,
NzInputModule,
NzIconModule,
NzDropDownModule,
ReactiveFormsModule,
HttpClientModule,
FormsModule,
NzModalModule,
NzFormModule,
NzSelectModule,
NzNotificationModule,
NzListModule,
],
providers: [NzModalRef],
exports: [
MemberPageComponent
]
})
export class MembrosModule { }
I thank anyone who can help me.
hope that the nzmodalref parameters can be solved
I have created a route after user logged-in in my angular app (Angular 8). now am trying to write a test case. But its giving below error.
route (/profile) page was not able to call.
Expected spy navigate to have been called with:
[ [ '/profile' ] ]
but it was never called.
login.component.js
import { Component, OnInit } from '#angular/core';
import { UserService } from '../../services/user.service';
import { User } from '../../models/user';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
user: User = new User();
errorMessage: string;
constructor(private userService: UserService, private router: Router){ }
ngOnInit(): void {
if(this.userService.currentUserValue){
this.router.navigate(['/home']);
return;
}
}
login() {
this.userService.login(this.user).subscribe(data => {
this.router.navigate(['/profile']);
}, err => {
this.errorMessage = "Username or password is incorrect.";
});
}
}
login.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { LoginComponent } from './login.component';
import { UserService } from 'src/app/services/user.service';
import { Router } from '#angular/router';
import { FormsModule } from '#angular/forms';
import { ExpectedConditions } from 'protractor';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { HomeComponent } from '../home/home.component';
import { ProfileComponent } from '../profile/profile.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let debugElement: DebugElement;
let location, router: Router;
let mockRouter;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, FormsModule ],
declarations: [ LoginComponent, ProfileComponent ],
providers: [UserService]
})
.compileComponents();
}));
beforeEach(() => {
mockRouter = { navigate: jasmine.createSpy('navigate') };
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'profile', component: ProfileComponent }
])],
declarations: [LoginComponent, ProfileComponent],
providers: [
{ provide: Router, useValue: mockRouter},
]
});
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement;
});
it('should go profile ', async(() => {
fixture.detectChanges();
component.login();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/profile']);
}));
});
Why are you configuringTestingModule twice?
You should mock userService.
Try:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { LoginComponent } from './login.component';
import { UserService } from 'src/app/services/user.service';
import { Router } from '#angular/router';
import { FormsModule } from '#angular/forms';
import { ExpectedConditions } from 'protractor';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { HomeComponent } from '../home/home.component';
import { ProfileComponent } from '../profile/profile.component';
import { of } from 'rxjs'; // import of from rxjs
import { throwError } from 'rxjs'; // import throwError
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let debugElement: DebugElement;
let mockUserService = jasmine.createSpyObj('userService', ['login']);
mockUserService.currentUserValue = /* mock currentUserValue to what it should be */
let router: Router;
beforeEach(async(() => {
// I don't think you need HttpClientTestingModule or maybe FormsModule
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, FormsModule, RouterTestingModule.withRoutes([
{ path: 'profile', component: ProfileComponent }
])],
declarations: [LoginComponent, ProfileComponent],
providers: [{ provide: UserService, useValue: mockUserService }]
})
.compileComponents();
}));
beforeEach(() => {
router = TestBed.get(Router); // remove the let here !!!!
spyOn(router, 'navigate'); // spy on router navigate
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement;
});
it('should go profile ', async(() => {
fixture.detectChanges();
mockUserService.login.and.returnValue(of({})); // mock login method on userService when it is called
component.login();
expect(router.navigate).toHaveBeenCalledWith(['/profile']);
}));
it('should set error message on error ', async(() => {
fixture.detectChanges();
mockUserService.login.and.returnValue(throwError('Error')); // mock login method on userService when it is called
component.login();
expect(component.errorMessage).toBe('Username or password is incorrect.');
}));
});
I have an Angular method that simply loads the contents of a locally stored JSON file featuring an array, however I cannot seem to test it.
test.ts (shortened for conciseness)
describe('MyComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyComponent],
imports: [HttpClientTestingModule],
});
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
component.ngOnInit();
it('should load status data from local json', () => {
const data = require('../../../assets/myData.json');
component.getThings();
expect(component.data).toEqual(data);
});
}
MyComponent.ts
data: string[];
constructor(private httpClient: HttpClient) {}
ngOnInit() {
this.getThings().subscribe(data =
this.data = data;
}
}
getData(): Observable<any> {
const data = '../../../assets/data.json';
return this.httpClient.get(data);
}
When testing for http request you need to mock the request.
Check out more about HttpClientTestingModule below:
https://angular.io/api/common/http/testing/HttpClientTestingModule
https://medium.com/spektrakel-blog/angular-testing-snippets-httpclient-d1dc2f035eb8
The below code is working,updated the component code as well a bit:
Component:
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Component({
selector: 'app-load-local-file',
templateUrl: './load-local-file.component.html',
styleUrls: ['./load-local-file.component.css']
})
export class LoadLocalFileComponent implements OnInit {
data: string[];
constructor(private httpClient: HttpClient) { }
ngOnInit() {
this.getData().subscribe(data => {
this.data = data;
});
}
getData(): Observable<any> {
const data = './data.json';
return this.httpClient.get(data);
}
}
Spec:
import { TestBed, async, fakeAsync, tick } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing'
import { LoadLocalFileComponent } from 'src/app/load-local-file/load-local-file.component';
describe('MyComponent', () => {
let fixture, component, httpMock: HttpTestingController;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [LoadLocalFileComponent],
imports: [HttpClientTestingModule]
});
fixture = TestBed.createComponent(LoadLocalFileComponent);
component = fixture.componentInstance;
httpMock = TestBed.get(HttpTestingController);
}));
it('should load status data from local json', fakeAsync(() => {
const data = require('./data.json');
component.ngOnInit();
tick();
const request = httpMock.expectOne('./data.json');
request.flush(data);
expect(component.data).toEqual(data);
}));
});
I know how to test http with a mock backend, as well as promises. Though I am struggling to find a solution to test http methods in a promise. Any advice will be much appreciated. Here's the function which contain the function with the http method inside the promise:
import { Injectable } from '#angular/core';
import { AbstractControl, FormGroup, FormControl, ValidatorFn, AsyncValidatorFn } from '#angular/forms';
import { Headers, RequestOptions } from '#angular/http';
import { Store } from '#ngrx/store';
import { HttpService, IHttpResponse } from '#mystique/mystique-utils/http';
import { IRootState } from '#mystique/mystique-state/root';
#Injectable()
export class ValidatorsService {
regex: { email: string; password: string } = { email: null, password: null };
constructor(private _http: HttpService, private _store: Store<IRootState>) {
this._store.select('config', 'regex').subscribe(regex => (this.regex = regex));
}
recordExistsOnServer(model: string, lookupField: string, savedValue: string, authToken: string): AsyncValidatorFn {
model += 's';
let validationDebounce;
return (control: AbstractControl) => {
const queryParams = [{ key: lookupField, value: control.value }];
clearTimeout(validationDebounce);
return new Promise((resolve, reject) => {
validationDebounce = setTimeout(() => {
if (control.value === '' || control.value === savedValue) {
return resolve(null);
}
this._http.get$(`/${model}`, authToken, queryParams).subscribe((httpResponse: IHttpResponse) => {
if (!httpResponse.data) {
savedValue = control.value;
}
return !httpResponse.data ? resolve(null) : resolve({ recordExistsOnServer: true });
});
}, 400);
});
};
}
Throws this error: Uncaught TypeError:
_this._http.get$ is not a function at localhost:9876/_karma_webpack_/polyfills.bundle.js:2281
Here is my test cases, the last it() fails:
import { TestBed, inject } from '#angular/core/testing';
import { FormGroup, FormControl } from '#angular/forms';
import { StoreModule, Store } from '#ngrx/store';
import { Observable } from 'rxjs/Observable';
import { HttpService } from '#mystique/mystique-utils/http';
import { HttpServiceStub } from '#mystique/mystique-stubs';
import { ValidatorsService } from './validators.service';
import { rootReducer } from '#mystique/mystique-state/root';
describe('ValidatorsService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({
config: rootReducer.config
})
],
providers: [{ provide: HttpService, useClass: HttpServiceStub }, ValidatorsService]
});
});
let service, http, store;
beforeEach(() => {
http = TestBed.get(HttpService);
store = TestBed.get(Store);
service = TestBed.get(ValidatorsService);
});
describe('when checking if a record exists on the server', () => {
let control, result, getSpy;
beforeEach(() => {
getSpy = spyOn(http, 'getAll$');
});
it('returns null if the user types the same value', done => {
control = new FormControl('bob');
result = service.recordExistsOnServer('user', 'username', 'bob', 'token');
result(control)['then'](r => {
expect(r).toEqual(null);
done();
});
});
it('returns null if the user types an empty string', done => {
control = new FormControl('');
result = service.recordExistsOnServer('user', 'username', 'bob');
result(control)['then'](r => {
console.log('r: ' + r)
expect(r).toEqual(null);
done();
});
});
it('returns null if the http call cannot find a record', done => {
getSpy.and.returnValue(Observable.of({ data: null }));
control = new FormControl('bobby');
result = service.recordExistsOnServer('user', 'username', 'bob');
result(control)['then'](r => {
expect(r).toEqual(null);
done();
});
});
});
});
Here is my http.service.ts:
import { Injectable } from '#angular/core';
import { Store } from '#ngrx/store';
import { IRootState } from '#mystique/mystique-state/root';
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/retry';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { IBaseModel } from '#spawntech/xmen-core-domain-models';
export interface IHttpQuery {
key: string;
value: string | number;
}
export interface IHttpResponse {
success: boolean;
status: number;
statusText: string;
message: string;
data?: any | any[];
error?: string;
token?: string;
}
#Injectable()
export class HttpService {
apiBaseUrl: string = null;
httpRetries = 3;
constructor(private _http: HttpClient, private _store: Store<IRootState>) {
this._store.select('config', 'apiBaseUrl').subscribe(url => (url ? (this.apiBaseUrl = url) : this.apiBaseUrl));
}
get$(restUrl: string, authToken: string, queryParams?: IHttpQuery[]): Observable<IHttpResponse> {
if (!restUrl) {
throw new Error('A restful url extension must be supplied');
}
const headers = this._prepareAuthHeader(authToken);
const params = this._prepareQueryParams(queryParams);
console.log('in http service---------------')
return this._http
.get<IHttpResponse>(this.apiBaseUrl + restUrl, { headers, params })
.retry(this.httpRetries)
.catch((response: HttpErrorResponse) => this._handleError(response));
}
}
use HttpClientTestingModule for mock http request
TestBed.configureTestingModule({
imports: [..., HttpClientTestingModule],
providers: [...]
})
in the development of applications, I call the service method which returns a query, then I subscribe () and I already consider successful and erroneous queries in the current component, displaying some notifications to the user
then you can take a query from a function to a separate function and do something like this:
spyOn (service, 'confirmEmail').
.returnValue (Observable.of (new HttpResponse ({body: '', status: 204}))));