Unit Testing Angular component with service : Cannot read property 'diagonisticData' of undefi - json

I am new to angular testing. I have a component, nested json and a service. The app works fine but during testing values are not being populated into the component. Please help.I have attached the service, json object,component and spec file.
I am not sure if I am following the right approach in spec file.
App component -Hub-Details-component.ts
export class HubDetailsComponent implements OnInit {
ngOnInit(): void {}
public jsonData:any = []
public diagnosticsData:any = [];
public dummy:any = [];
public hubData:any;
constructor(private dataService: DataService) {}
handleData()
{
this.dataService.getData()
.subscribe(response =>{
if(response!=null)
{
this.jsonData=response;
console.log(this.jsonData);
this.dummy=this.jsonData.result;
console.log(this.dummy);
this.diagnosticsData=this.dummy.diagnosticData;
const DataArray = [];
for(const element in this.diagnosticsData)
{
DataArray.push({
id:element,
name:this.diagnosticsData[element]
});
}
console.log(DataArray);
this.hubData=DataArray;
}
});
}
}
DataService
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'})
export class DataService {
public url = '/assets/Data/Data.json'
constructor(private http: HttpClient ) { }
getData = () => {
const url = 'assets/Data/Data.json';
return this.http.get(url);
}}
json file
{
"result"
{
"abc"
{
"name" :"abc",
"tag" : "xyz",
"status": "qwe"
}
}
}
spec.ts
it('should get data from dataservice',fakeAsync(()=>{
const fixture =
TestBed.createComponent(HubDetailsComponent);
const component =
fixture.debugElement.componentInstance;
const service =
fixture.debugElement.injector.get(DataService);
let spy_getPosts =
spyOn(service,'getData').and.callFake(() => {
return of([{"result"{
"abc"
{
"name" :"abc",
"tag" : "xyz",
"status": "qwe"
}
}
}]).pipe(delay(2000));});
fixture.detectChanges();
component.handleData();
tick(2000);
expect(component.jsonData).toEqual([{
{"result"{
"abc"
{
"name" :"abc",
"tag" : "xyz",
"status": "qwe"
}
}
}
}]);
}));
Thanks in advance.

Try this:
// In your spec file, mock the service;
#Injectable()
class MockDataService extends DataService {
getData() {
const mockData = {
result: {
diagnosticData: [
{ mock1: 'value1' },
{ mock2: 'value2' }
]
}
}
return of(mockData);
}
}
describe('Your Component Name you are testing', () => {
let dataService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [],
imports: [...yourImports],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{
provide: DataService,
useClass: MockDataService
}
]
}).compileComponents();
dataService = TestBed.get(DataService);
}));
// Now your test case:
it('should call #handleData() method', () => {
spyOn(component, 'handleData').and.callThrough();
component.handleData();
expect(component.handleData).toHaveBeenCalled();
});
// Thats it. You do not need to do anything else;
})

Related

Angular 6 - Get current route and its data

How to get the current route you're in and its data, children and parent?
If this is the route structure:
const routes: Routes = [
{path: 'home', component: HomeComponent, data: {title: 'Home'}},
{
path: 'about',
component: AboutComponent,
data: {title: 'About'},
children: [
{
path: 'company',
component: 'CompanyComponent',
data: {title: 'Company'}
},
{
path: 'mission',
component: 'MissionComponent',
data: {title: 'Mission'}
},
...
]
},
...
]
If I am currently in CompanyComponent, how do I get my current route w/c is Company, get its parent w/c is about, its data and its siblings such as mission, etc.?
#Component({...})
export class CompanyComponent implements OnInit {
constructor(
private router: Router,
private route: ActivatedRoute
) {}
ngOnInit() {
// Parent: about
this.route.parent.url.subscribe(url => console.log(url[0].path));
// Current Path: company
this.route.url.subscribe(url => console.log(url[0].path));
// Data: { title: 'Company' }
this.route.data.subscribe(data => console.log(data));
// Siblings
console.log(this.router.config);
}
}
constructor(
private router: Router,
private route: ActivatedRoute,
) {
}
ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => {
return this.getHeaderClasses();
}),
)
.subscribe((headerClasses: string | null) => {
this.headerClasses = headerClasses;
});
this.headerClasses = this.getHeaderClasses();
}
getHeaderClasses(): string | null {
let child = this.route.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['headerClasses']) {
return child.snapshot.data['headerClasses'];
} else {
return null;
}
}
return null;
}
routing
{
path: 'list',
component: DialogListComponent,
data: {
headerClasses: 'col-lg-8',
},
},
You can access the route's data property from the snapshot like this:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
templateUrl: './app/home/welcome.component.html'
})
export class WelcomeComponent implements OnInit {
public pageTitle: string;
constructor( private route: ActivatedRoute) {
}
ngOnInit(): void {
this.pageTitle = this.route.snapshot.data['title'];
}
}
#Component({...})
#UntilDestroy()
export class CompanyComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
this.router.events
.pipe(
untilDestroyed(this),
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
map((event: NavigationEnd) => event.url)
)
.subscribe(url=> {
console.log(url);
});
}
}

How to pass data received from service to angular datatable

I have just started working on Angular 4 and I am trying to render some data which I receive from angular service in json format, into angular-datatable, but whichever option i try its not working for me.
The table is coming, the columns are coming, however the data inside the columns are not displaying.
Any help would be great,
Thanks in advance..!!!!
Please find my code below:
component.html
<table datatable [dtOptions]="dtOptions" class="row-border hover"></table>
component.ts
import { Component, OnInit } from '#angular/core';
import { FleetDataService } from '../../services/fleet-data.service';
import { Subject } from 'rxjs/Subject';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
private fleetData: any;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private getFleetData:FleetDataService) { }
ngOnInit() {
this.getFleetData.getFleetData().subscribe(
fleetData => {
this.fleetData = fleetData;
console.log(this.fleetData);
this.dtTrigger.next();
},
err => {
console.log(err);
}
);
this.dtOptions = {
pagingType: 'full_numbers',
columns: [{
title: 'First Name',
data: this.fleetData
}, {
title: 'Last Name',
data: this.fleetData
}, {
title: 'Score',
data: this.fleetData
}]
};
}
}
component.service
import { Injectable } from '#angular/core';
import { HttpModule, Http, Response, Headers, RequestOptions } from
'#angular/http';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class FleetDataService {
constructor(private http: Http) { }
getFleetData() {
return this.http.get("../../assets/data/test.json")
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server
Error'));
}
}
test.json
[{
"FirstName": "Jill",
"LastName": "Smith",
"Score": "disqualified"
}, {
"FirstName": "Eve",
"LastName": "Jackson",
"Score": "94"
}, {
"FirstName": "John",
"LastName": "Doe",
"Score": "80"
}, {
"FirstName": "Adam",
"LastName": "Johnson",
"Score": "67"
}]
You set your dtOptions outside the subscribe.
If you do this the fleetData stays empty so dtOptions is never set correctly, because an Observable is asynchronous. I propose this code:
export class DashboardComponent implements OnInit {
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private getFleetData:FleetDataService) { }
ngOnInit() {
this.getFleetData.getFleetData().subscribe(
fleetData => {
console.log(fleetData);
this.buildDtOptions(fleetData)
this.dtTrigger.next();
},
err => {
console.log(err);
});
}
private buildDtOptions(fleetData: any): void {
this.dtOptions = {
pagingType: 'full_numbers',
columns: [
{title: 'First Name', data: fleetData},
{title: 'Last Name', data: fleetData},
{title: 'Score', data: fleetData}
]
};
}
}
For this error: ERROR TypeError: Cannot read property 'aDataSort' of undefined. You can do a spinner (ngIf / else) in the view and when data are loaded you display the datatable

Supplied parameters do not match any signature of call target on api call angular4

I am consuming an api to Covalent UI, on user service. Which needs to post some data from an endpoint to the table as illustrated on the example from the GitHub.
Here is the modification I have made to the service.
import { Provider, SkipSelf, Optional, InjectionToken } from '#angular/core';
import { Response, Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { HttpInterceptorService, RESTService } from '#covalent/http';
import { ApiService } from '../../../../services/api.service';
import { AuthService } from '../../../../services/auth.service';
export interface IUser {
_id: string;
email:string;
createdAt: Date;
profile: {
name: string;
gender: string;
location: String;
picture: {
// data: Buffer;
contentType: string;
}
}
}
export class UserService extends RESTService<IUser> {
constructor(private _http: HttpInterceptorService, api: string,
private authService: AuthService,
private api2: ApiService,) {
super(_http, {
baseUrl: api,
path: '/dashboard/users',
});
}
staticQuery(): Observable<IUser[]> {
// return this._http.get('data/users.json')
// .map((res: Response) => {
// return res.json();
// });
return this.api2.get('auth/account/users')
.map((res: Response) => {
return res.json();
});
}
}
export const USERS_API: InjectionToken<string> = new InjectionToken<string>('USERS_API');
export function USER_PROVIDER_FACTORY(
parent: UserService, interceptorHttp: HttpInterceptorService, api: string): UserService {
return parent || new UserService(interceptorHttp, api);//<---- This is where I get the error mention.
}
export const USER_PROVIDER: Provider = {
// If there is already a service available, use that. Otherwise, provide a new one.
provide: UserService,
deps: [[new Optional(), new SkipSelf(), UserService], HttpInterceptorService, USERS_API],
useFactory: USER_PROVIDER_FACTORY,
};
JSON api data
[
{
"_id": "59d665c3acbde702b47d3987",
"updatedAt": "2017-10-07T17:23:00.498Z",
"createdAt": "2017-10-05T17:02:59.526Z",
"email": "me#mail.com",
"password": "$2a$05$z1mRUWqqUfM8wKMU/y9/sOLssAKcV7ydxi0XJyTR1d3BI2X7SSsoy",
"tokens": [],
"role": "admin",
"__v": 0,
"profile": {
"name": "F.name L.name",
"gender": "Female",
"location": "my place",
"avatar": {
"contentType": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAaYAAAFmCAYAAAAmm....."
}
}
}
]
Am not sure what am doing wrong, I will appreciate your comment for this fix.
I get the error bellow.
users/services/user.service.ts (51,20): Supplied parameters do not match any signature of call target.
From this line of code
As #Philipp mentioned in the comments.
The class UserService expects 4 arguments in the constructor, but you are only providing 2 in the USER_PROVIDER_FACTORY function.
Therefore your factory should be defined:
export function USER_PROVIDER_FACTORY(
parent: UserService, interceptorHttp: HttpInterceptorService, api: string,
authService: AuthService, api2: ApiService
): UserService {
return parent || new UserService(interceptorHttp, api, authService, api2)
}

Angular : ERROR SyntaxError: Unexpected token < in JSON at position 0

Hi I need help I created an angular service but when I want to view the data from my json file it shows me this error, I tried a lot of unsuccessful solution
app.component.ts
import {Component, OnInit} from '#angular/core';
import {Car} from './domain/car';
import {CarService} from './service/carservice';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [CarService]
})
export class AppComponent implements OnInit {
cars1: Car[];
constructor(private carService: CarService) { }
ngOnInit() {
this.carService.getCarsSmall().subscribe(cars => this.cars1 = cars);
}
}
carservice.ts
#Injectable()
export class CarService {
private jsonUrl = './cars-smalll.json';
constructor(private http: Http) {}
getCarsSmall(): Observable<Car[]> {
return this.http.get(this.jsonUrl)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || { };
}
private handleError (error: Response | any) {
// In a real world app, you might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}
cars-smalll.json
[
{
"brand": "VW",
"year": 2012,
"color": "Orange",
"vin": "dsad231ff"
},
{
"brand": "Audi",
"year": 2011,
"color": "Black",
"vin": "gwregre345"
},
{
"brand": "Renault",
"year": 2005,
"color": "Gray",
"vin": "h354htr"
}
]
thank you in advance.
Besides using the correct path suggested in comments, your problem is that you are trying to extract data from something that does not exist. Take a look at your json, it's an array. But in your extractData-function you are trying to extract data from an object data, which is of course not present in your JSON. So change that function to:
private extractData(res: Response) {
let body = res.json();
// return just the response, or an empty array if there's no data
return body || [];
}
This should do it, as well as correcting the path of the JSON file.

Angular2 Ansychronous bootstrapping with external json configuration file

I have upgraded to angular2 RC6 and want to load an external JSON config file before bootstrapping my AppModule. I had this working before RC5 but am now having trouble finding an an equivalent way of injecting this data.
/** Create dummy XSRF Strategy for Http. */
const XRSF_MOCK = provide(XSRFStrategy, { provide: XSRFStrategy, useValue: new FakeXSRFStrategyService() });
/** Create new DI. */
var injector = ReflectiveInjector.resolveAndCreate([ConfigService, HTTP_PROVIDERS, XRSF_MOCK]);
/** Get Http via DI. */
var http = injector.get(Http);
/** Http load config file before bootstrapping app. */
http.get('./config.json').map(res => res.json())
.subscribe(data => {
/** Load JSON response into ConfigService. */
let jsonConfig: ConfigService = new ConfigService();
jsonConfig.fromJson(data);
/** Bootstrap AppCOmponent. */
bootstrap(AppComponent, [..., provide(ConfigService, { useValue: jsonConfig })
])
.catch(err => console.error(err));
});
This worked just fine but struggling to change to work with RC6.
I'm experimenting the following approach but struggling to modify my predefined AppModule with loaded data:
const platform = platformBrowserDynamic();
if (XMLHttpRequest) { // Mozilla, Safari, ...
request = new XMLHttpRequest();
} else if (ActiveXObject) { // IE
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
console.log(e);
}
}
}
request.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
var json = JSON.parse(this.responseText);
let jsonConfig: ConfigService = new ConfigService();
jsonConfig.fromJson(json);
/**** How do I pass jsConfig object into my AppModule here?? ****/
platform.bootstrapModule(AppModule);
}
};
// Open, send.
request.open('GET', './config.json', true);
request.send(null);
I had the same problem. Looks like you came across my Gist :-)
As far as the RC 6 update, you should check out the HttpModule source. It shows all the providers that were originally in the now removed HTTP_PROVIDERS. I just checked that out and came up with the following
function getHttp(): Http {
let providers = [
{
provide: Http, useFactory: (backend: XHRBackend, options: RequestOptions) => {
return new Http(backend, options);
},
deps: [XHRBackend, RequestOptions]
},
BrowserXhr,
{ provide: RequestOptions, useClass: BaseRequestOptions },
{ provide: ResponseOptions, useClass: BaseResponseOptions },
XHRBackend,
{ provide: XSRFStrategy, useValue: new NoopCookieXSRFStrategy() },
];
return ReflectiveInjector.resolveAndCreate(providers).get(Http);
}
As far as the
/**** How do I pass jsConfig object into my AppModule here?? ****/
platform.bootstrapModule(AppModule);
It's not the prettiest (it's really not that bad), but I found something I didn't even know was possible, from this post. Looks like you can declare the module inside the function.
function getAppModule(conf) {
#NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule ],
bootstrap: [ AppComponent ],
providers: [
{ provide: Configuration, useValue: conf }
]
})
class AppModule {
}
return AppModule;
}
Below is what I just used to test right now
import { ReflectiveInjector, Injectable, OpaqueToken, Injector } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
import {
Http, CookieXSRFStrategy, XSRFStrategy, RequestOptions, BaseRequestOptions,
ResponseOptions, BaseResponseOptions, XHRBackend, BrowserXhr, Response
} from '#angular/http';
import { AppComponent } from './app.component';
import { Configuration } from './configuration';
class NoopCookieXSRFStrategy extends CookieXSRFStrategy {
configureRequest(request) {
// noop
}
}
function getHttp(): Http {
let providers = [
{
provide: Http, useFactory: (backend: XHRBackend, options: RequestOptions) => {
return new Http(backend, options);
},
deps: [XHRBackend, RequestOptions]
},
BrowserXhr,
{ provide: RequestOptions, useClass: BaseRequestOptions },
{ provide: ResponseOptions, useClass: BaseResponseOptions },
XHRBackend,
{ provide: XSRFStrategy, useValue: new NoopCookieXSRFStrategy() },
];
return ReflectiveInjector.resolveAndCreate(providers).get(Http);
}
function getAppModule(conf) {
#NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule ],
bootstrap: [ AppComponent ],
providers: [
{ provide: Configuration, useValue: conf }
]
})
class AppModule {
}
return AppModule;
}
getHttp().get('/app/config.json').toPromise()
.then((res: Response) => {
let conf = res.json();
platformBrowserDynamic().bootstrapModule(getAppModule(conf));
})
.catch(error => { console.error(error) });