As i am trying to perform unit testing on angular application..but i am getting below error while running the test - angular6

1 spec, 1 failure
Spec List | Failures
OverviewComponent should create
Failed: Can't resolve all parameters for Router: (?, ?, ?, ?, ?, ?, ?, ?).
Error: Can't resolve all parameters for Router: (?, ?, ?, ?, ?, ?, ?, ?).
at syntaxError (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:215:1)
at CompileMetadataResolver._getDependenciesMetadata (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10807:1)
at CompileMetadataResolver._getTypeMetadata (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10700:1)
at CompileMetadataResolver._getInjectableTypeMetadata (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10922:1)
at CompileMetadataResolver.getProviderMetadata (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10931:1)
at http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10869:1
at Array.forEach ()
at CompileMetadataResolver._getProvidersMetadata (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10829:1)
at CompileMetadataResolver.getNgModuleMetadata (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:10548:1)
at JitCompiler._loadModules (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/compiler/fesm5/compiler.js:22567:1)
============================================
describe('OverviewComponent', () => {
let component: OverviewComponent;
let fixture: ComponentFixture<OverviewComponent>;
let router : Router
const fakeActivatedRoute = {
snapshot: { data: { } }
} as ActivatedRoute;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports:[
SharedModule,
FlexLayoutModule,
// RouterModule.forRoot(routes),
RouterTestingModule
],
declarations: [ OverviewComponent,
FooterComponent,
LoginComponent,
ChangePasswordComponent,
ForgotPasswordComponent,
AppComponent],
providers:[
HttpClient,
HttpHandler,
DataService,
NgxSpinnerService,
Router,
RouterModule,
EmitterService,
{provide: ActivatedRoute,
useValue: fakeActivatedRoute}
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

You need create mock to Service Router.
You can also just use the RouterTestingModule and just spyOn the navigate function like this...
import { TestBed } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { Router } from '#angular/router';
import { MyModule } from './my-module';
import { MyComponent } from './my-component';
describe('something', () => {
let fixture: ComponentFixture<LandingComponent>;
let router: Router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
MyModule,
RouterTestingModule.withRoutes([]),
],
}).compileComponents();
fixture = TestBed.createComponent(MyComponent);
router = TestBed.get(Router);
});
it('should navigate', () => {
const component = fixture.componentInstance;
const navigateSpy = spyOn(router, 'navigate');
component.goSomewhere();
expect(navigateSpy).toHaveBeenCalledWith(['/expectedUrl']);
});
});
Font: stackoverflow

Related

'xxxxx' is not a known element on Karma+Jasmine testing Angular

I'm new in Angular 10 testing and I'm continuously receiving the next message when I run ng test, so despite I had been looking for the same issue I did not find it.
This is my app.component.html and app.component.ts
<app-navbar></app-navbar>
<div class="container pt-4">
<flash-messages></flash-messages>
<router-outlet></router-outlet>
</div>
import {FlashMessagesModule} from 'angular2-flash-messages'; // installed by: npm i angular2-flash-messages
import {RouterModule} from '#angular/router';
import { NavbarComponent } from './components/navbar/navbar.component';
...
#NgModule({
declarations: [
NavbarComponent,
...
],
imports: [
RouterModule.forRoot(appRoutes), //routes array
FlashMessagesModule.forRoot(),
...
],
.spec.ts files:
app.component.spec.ts
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
...
navbar.component.spec.ts
describe('NavbarComponent', () => {
let component: NavbarComponent;
let fixture: ComponentFixture<NavbarComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NavbarComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(NavbarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Flash-messages and router-outlet are not components created, even so I did not touch any test of any component.
Any idea? Thanks!
Summary
You should do all imports of modules, components, providers to test environment similar to NgModule decorator.
Example
In this case inside your app.component.html you are using, router, flash-messages, navbar
<app-navbar></app-navbar>
<div class="container pt-4">
<flash-messages></flash-messages>
<router-outlet></router-outlet>
</div>
So your test file should looks like this.
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent,
NavbarComponent // <-- becuase you use app-navbar
],
imports: [
RouterTestingModule // <-- because you use router-outlet
FlashMessagesModule.forRoot() // <-- because you use flash-messages
]
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});

How to interface JSON data and display table

So I am trying to display a list of devices from the database into an angular material table. I've written the REST api for it which is something like this:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const mysql = require('mysql');
//parse application/json
app.use(bodyParser.json());
//create database connection
const conn = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'project'
});
//connect to database
conn.connect((err) =>{
if(err) throw err;
console.log('Mysql connected....');
});
//server listening
app.listen(3000,() =>{
console.log('Server started on port 3000');
});
//show login page
app.use(express.static(__dirname+'/dashboard'))
app.get('/',(req,res) => {
res.send('Use /api/devices');
});
//show all devices
app.get('/api/devices',(req,res) => {
let sql = "SELECT * FROM tempstatus";
let query = conn.query(sql, (err, results) => {
if(err) throw err;
res.send(JSON.stringify({'status': 200, 'error': null, 'response': results}));
});
});
And now I have written a controller as follows:
var myApp = angular.module('myApp', [require('angular-material-data-table')]);
myApp.controller('DeviceController', function($scope, $http){
console.log('DeviceController loaded')
$scope.getDevices = function(){
var device = null;
$http.get('/api/devices').success(function(response) {
device = response;
});
}
}
I'm rather new to Angular and nodejs and I don't really know how what else I must do and how to display the data I get in an angular material table. Can you please help me out?
This is the JSON data I'm getting from the API:
"status":200,"error":null,"response": {"serialnum":"0","time":"2020-02-11T12:36:27.000Z","type":"","temparature":"","date":"2020-02-10T18:30:00.000Z","status":"not active","comments":""}
And this is the angular.module.ts file. As I said, I'm new to angular and I don't know how to write my code. So far I've only done this and the controller in angular:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Illegal state: Could not load the summary for directive AppComponent

I am writing a spec.ts file in angular and getting the following error:
Failed: Illegal state: Could not load the summary for directive
AppComponent.
Below is the code I tried
import { TestBed, async } from "#angular/core/testing";
import { AppComponent } from "./app.component";
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
});
});
});
it('should create the app', async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));``
It seems that you're using a component which includes another components inside. You have to add all the components that you used in AppComponent in declaration of configureTestingModule

angular2: Supplied parameters do not match any signature of call target, even though i have all the needed params

push.component.ts
import { Component, OnInit } from '#angular/core';
import {PushResult} from './dto/pushResult';
import {PushRequest} from './dto/pushRequest';
import {PushService} from './push.service';
#Component({
// selector: 'push-comp',
template:
// `<form (submit)="submitForm()">
// <input [(ngModel)]="element.name"/>
//
// <button type="submit">Submit the form</button>
// </form>
// <br>
`<button (click)="getHeroes()"> get </button> <button (click)="saveHeroes()"> push </button>`,
// templateUrl: 'app/html/heroes.component.html',
providers: [PushService]
})
export class PushComponent implements OnInit {
pushResult:PushResult;
// selectedHero:Hero;
// addingHero = false;
error:any;
element:any;
constructor(private pushService:PushService) {
console.info("in PushComponent constructor()");
}
getHeroes() {
this.pushService
.doSomeGet();
// .then(pushResult => this.pushResult = pushResult)
// .catch(error => this.error = error);
}
saveHeroes() {
var pushRequest: PushRequest = new PushRequest();
// this.pushService.doSelectMessagesAttributesUrl2(pushRequest);
this.pushService.doFeatureCreateNewMessageUrl(pushRequest);
this.pushService.doFeatureSelectPushMessages(this.element);
// .then(pushResult => this.pushResult = pushResult)
// .catch(error => this.error = error);
}
ngOnInit() {
console.info("in PushComponent ngOnInit()");
// this.getHeroes();
// this.saveHeroes();
}
}
push.service.ts
import { Injectable } from '#angular/core';
import {Http, Response, Headers} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import 'rxjs/Rx';
import { PushResult } from './dto/pushResult';
import {PushRequest} from './dto/pushRequest';
import {StringUtilsService} from "../shared/stringUtils.service";
#Injectable()
export class PushService {
//private pushUrl = 'http://www.ynet.com'; // URL to web api
// private getUrl = '/app/eladb.json'; // URL to web api
private getUrl = '/SupporTool/ShowConfig?id=4'; // URL to web api
private selectMessagesAttributesUrl = '/SupporTool/Push/SelectMessagesAttributes'; // URL to web api
private postMultiMap = '/SupporTool/Push/FeatureCreateNewMessage'; // URL to web api
private postBoolean = '/SupporTool/Push/FeatureSelectPushMessages'; // URL to web api
private stringUtilsService : StringUtilsService;
constructor(private http: Http) {
this.stringUtilsService = new StringUtilsService();
}
doSomeGet() {
console.info("sending get request");
let headers = new Headers({
'Content-Type': 'application/xml'});
this.http.get(this.getUrl, {headers: headers})
.map(res => res.text())
.subscribe(
data => { console.info("next: "+data) },
err => console.error(err)
);
}
doSelectMessagesAttributesUrl2(pushRequest : PushRequest) {
console.info("sending post request");
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'});
return this.http
.post(this.selectMessagesAttributesUrl, "", {headers: headers})
.map(res => res.json())
.subscribe(
data => { console.info("next: "); console.info(data) },
err => console.error(err)
);
}
doFeatureCreateNewMessageUrl(pushRequest : PushRequest) {
console.info("sending post request");
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded'});
var isLimit = true;
return this.http
.post(this.postBoolean, "#limit="+isLimit, {headers: headers})
.map(res => res.json())
.subscribe(
data => { console.info("next: "); console.info(data) },
err => console.error(err)
);
}
doFeatureSelectPushMessages(element : any) {
console.info("sending post request");
let dict = {"limit":"true", "name":"foo"}
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded'});
var params = {};
params['push_input_internal_id'] = "1";
params['b'] = "2";
var formParamString = this.stringUtilsService.mapToFormParamsString(params);
return this.http
.post(this.postMultiMap, formParamString , {headers: headers})
.map(res => res.json())
.subscribe(
data => { console.info("next: "); console.info(data) },
err => console.error(err)
);
}
private handleError(error: any) {
console.error('An error occurred', error);
// return Promise.reject(error.message || error);
}
}
push.component.spec.ts
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { addProviders, async, inject } from '#angular/core/testing';
import { PushComponent } from './push.component';
describe('Component: Push', () => {
it('should create an instance', () => {
let component = new PushComponent();
expect(component).toBeTruthy();
});
});
app.routing.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { PushComponent } from './push/push.component';
const appRoutes: Routes = [
{ path: '', redirectTo: '/push', pathMatch: 'full' },
{ path: 'push', component: PushComponent}
];
export const appRoutingProviders: any[] = [];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
I read this post, but it used to work for me. So i cannt understand what i am missing.
and i get this error after npm start
Build error
The Broccoli Plugin: [BroccoliTypeScriptCompiler] failed with:
Error: Typescript found the following errors:
/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/tmp/broccoli_type_script_compiler-input_base_path-2GTEvnc7.tmp/0/src/app/push/push.component.spec.ts (10, 21): Supplied parameters do not match any signature of call target.
at BroccoliTypeScriptCompiler._doIncrementalBuild (/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:120:19)
at BroccoliTypeScriptCompiler.build (/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:43:10)
at /Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/node_modules/broccoli-caching-writer/index.js:152:21
at lib$rsvp$$internal$$tryCatch (/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1036:16)
at lib$rsvp$$internal$$invokeCallback (/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1048:17)
at lib$rsvp$$internal$$publish (/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1019:11)
at lib$rsvp$asap$$flush (/Users/eladb/WorkspaceQa/SupporTool/src/main/webapp/html/ng2/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1198:9)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
PushComponent expects a PushService instance as parameter
constructor(private pushService:PushService) {
but you don't provide one
new PushComponent(/* parameter value missing */);
If you create an instance yourself with new Xxx() then Angulars DI is not involved and no dependencies are passed.
Only when Angulars DI itself creates PushComponent does it resolve and pass dependencies.
import {beforeEachProviders, it, describe, inject} from '#angular/core/testing';
describe('my code', () => {
beforeEachProviders(() => [PushService, PushComponent]);
it('does stuff', inject([PushComponent], (pushComponent) => {
// actual test
});
});
Don't expect to get a component injected. What you get this way is an instance of the components class (without any change detection running, nor lifecycle hooks being called, ...)
If you want a component, then you need to use TestBed. See also https://github.com/angular/angular/blob/master/CHANGELOG.md

Testing routerLink directive in Angular 2

I'm trying to test the work of routing. I moved navbar to a separate component - MdNavbar. Basically only html and css in there, the RouteConfig is in other component and MdNavbar is injected in there. I want to test that route changes when clicking on the link. In test I'm looking for the Profile link and clicking on it. I expect the route to change. Here is the code from my tests -
import {it, inject,async, describe, beforeEachProviders, tick, fakeAsync} from '#angular/core/testing';
import {TestComponentBuilder} from '#angular/compiler/testing';
import {Component, provide} from '#angular/core';
import {RouteRegistry, Router, ROUTER_PRIMARY_COMPONENT, ROUTER_DIRECTIVES,RouteConfig} from '#angular/router-deprecated';
import {Location, LocationStrategy, PathLocationStrategy} from '#angular/common';
import {RootRouter} from '#angular/router-deprecated/src/router';
import {SpyLocation} from '#angular/common/testing';
import {IndexComponent} from '../../home/dashboard/index/index.component';
import {ProfileComponent} from '../../home/dashboard/profile/profile.component';
// Load the implementations that should be tested
import {MdNavbar} from './md-navbar.component';
describe('md-navbar component', () => {
// provide our implementations or mocks to the dependency injector
beforeEachProviders(() => [
RouteRegistry,
provide(Location, { useClass: SpyLocation }),
{ provide: LocationStrategy, useClass: PathLocationStrategy },
provide(Router, { useClass: RootRouter }),
provide(ROUTER_PRIMARY_COMPONENT, { useValue: TestComponent }),
]);
// Create a test component to test directives
#Component({
template: '',
directives: [ MdNavbar, ROUTER_DIRECTIVES ]
})
#RouteConfig([
{ path: '/', name: 'Index', component: IndexComponent, useAsDefault: true },
{ path: '/profile', name: 'Profile', component: ProfileComponent },
])
class TestComponent {}
it('should be able navigate to profile',
async(inject([TestComponentBuilder, Router, Location],
(tcb: TestComponentBuilder, router: Router, location: Location) => {
return tcb.overrideTemplate(TestComponent, '<md-navbar></md-navbar>')
.createAsync(TestComponent).then((fixture: any) => {
fixture.detectChanges();
let links = fixture.nativeElement.querySelectorAll('a');
links[8].click()
expect(location.path()).toBe('/profile');
// router.navigateByUrl('/profile').then(() => {
// expect(location.path()).toBe('/profile');
// })
})
})));
Test runs with the following result -
Expected '' to be '/profile'.
And the second one -
Could someone please give me a hint, what exactly I'm doing wrong?
Here is the part navbar component template -
<nav class="navigation mdl-navigation mdl-color--grey-830">
<a [routerLink]="['./Index']" class="mdl-navigation__link" href=""><i class="material-icons" role="presentation">home</i>Home</a>
<a [routerLink]="['./Profile']" class="mdl-navigation__link" href=""><i class="material-icons" role="presentation">settings</i>My Profile</a>
</nav>
ADDED:
Thanks to Günter Zöchbauer answer I managed to find a working solution for me.
it('should be able navigate to profile',
async(inject([TestComponentBuilder, Router, Location],
(tcb: TestComponentBuilder, router: Router, location: Location) => {
return tcb.overrideTemplate(TestComponent, '<md-navbar></md-navbar>')
.createAsync(TestComponent).then((fixture: any) => {
fixture.detectChanges();
let links = fixture.nativeElement.querySelectorAll('a');
links[8].click();
fixture.detectChanges();
setTimeout(() {
expect(location.path()).toBe('/profile');
});
})
})));
The click event is processed async. You would need to delay the check for the changed path.
it('should be able navigate to profile',
inject([TestComponentBuilder, AsyncTestCompleter, Router, Location],
(tcb: TestComponentBuilder, async:AsyncTestCompleter, router: Router, location: Location) => {
return tcb.overrideTemplate(TestComponent, '<md-navbar></md-navbar>')
.createAsync(TestComponent).then((fixture: any) => {
fixture.detectChanges();
let links = fixture.nativeElement.querySelectorAll('a');
links[8].click()
setTimeout(() {
expect(location.path()).toBe('/profile');
async.done();
});
// router.navigateByUrl('/profile').then(() => {
// expect(location.path()).toBe('/profile');
// })
})
})));
or
it('should be able navigate to profile',
async(inject([TestComponentBuilder, Router, Location],
(tcb: TestComponentBuilder, router: Router, location: Location) => {
return tcb.overrideTemplate(TestComponent, '<md-navbar></md-navbar>')
.createAsync(TestComponent).then((fixture: any) => {
fixture.detectChanges();
let links = fixture.nativeElement.querySelectorAll('a');
links[8].click()
return new Promise((resolve, reject) => {
expect(location.path()).toBe('/profile');
resolve();
});
// router.navigateByUrl('/profile').then(() => {
// expect(location.path()).toBe('/profile');
// })
})
})));
I'm not using TypeScript myself, therefore syntax might be off.