×
Karma Installation
Install Karma Client on Windows 10 an run it from Command Line
D:\dev\myTestProjects\dobby-the-companion> npm install -g karma-cli
C:\Users\Helmut\AppData\Roaming\npm\karma -> C:\Users\Helmut\AppData\Roaming\npm\node_modules\karma-cli\bin\karma
+ karma-cli@1.0.1
updated 1 package in 0.421s
D:\dev\myTestProjects\dobby-the-companion> karma start
08 08 2018 16:03:24.227:WARN [karma]: No captured browser, open http://localhost:9876/
08 08 2018 16:03:24.232:WARN [karma]: Port 9876 in use
08 08 2018 16:03:24.233:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9877/
Run all Karma test
D:\dev\myTestProjects\dobby-the-companion> ng test
10% building modules 1/1 modules 0 active(node:25148) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
10 08 2018 14:07:37.807:WARN [karma]: No captured browser, open http://localhost:9876/
10 08 2018 14:07:37.813:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
10 08 2018 14:07:37.813:INFO [launcher]: Launching browser Chrome with unlimited concurrency
10 08 2018 14:07:37.817:INFO [launcher]: Starting browser Chrome 10 08 2018 14:07:43.581:WARN [karma]: No captured browser, open http://localhost:9876/
Missing Error Messages with Angular / Karma testing – add source-map=false parameter
D:\dev\myTestProjects\dobby-the-companion> ng test --source-map=false
10% building modules 1/1 modules 0 active(node:6332) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
10 08 2018 14:24:47.487:WARN [karma]: No captured browser, open http://localhost:9876/
10 08 2018 14:24:47.492:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
10 08 2018 14:24:47.492:INFO [launcher]: Launching browser Chrome with unlimited concurrency
10 08 2018 14:24:47.504:INFO [launcher]: Starting browser Chrome 10 08 2018 14:24:50.370:WARN [karma]: No captured browser, open http://localhost:9876/
10 08 2018 14:24:50.748:INFO [Chrome 67.0.3396 (Windows 10.0.0)]: Connected on socket Ml0r-gsA3JNw1F0sAAAA with id 52984303
Run ONLY a single Karma test
Change in your IDE :
describe('LoginComponent', () => {
-> fdescribe('LoginComponent', () => {
Reference
Using RouterTestingModule to test Angular Router Object
Code to be tested
import {Router} from '@angular/router';
export class myComponent {
constructor( private router: Router ) { }
triggerMessageAction(m: Message) {
if (m.messageClass === 'internal') {
this.router.navigate([m.messageLink]);
}
}
Karma/Jasmine Test Code
import {RouterTestingModule} from '@angular/router/testing';
import {Router} from '@angular/router';
describe('WarningDialogComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
...
imports: [ RouterTestingModule ],
}).compileComponents();
}));
beforeEach(inject([MessagesService], (service: MessagesService) => {
...
}));
it('should close Warning Dialog after pressing on a Warning Action ', inject([MessagesService, Router],
(service: MessagesService, router: Router) => {
spyOn(component, 'triggerMessageAction').and.callThrough();
spyOn(router, 'navigate').and.returnValue(true);
expect(component.triggerMessageAction).toHaveBeenCalledWith(jasmine.objectContaining( {messageType: 'logout'}));
expect(router.navigate).toHaveBeenCalledWith('login');
}));
});
Potential Error
Error: : Expected a spy, but got Function.
Usage: expect().toHaveBeenCalledWith(...arguments)
Fix: Add spyOn for the methode you want to spy
spyOn(router, 'navigate').and.returnValue(true)
Using SpyOn to run UNIT-tests for Angular Router Calls
- spyOn() takes two parameters: the first parameter is the name of the object and the second parameter is the name of the method to be spied upon
- It replaces the spied method with a stub, and does not actually execute the real method
- The spyOn() function can however be called only on existing methods.
- A spy only exists in the describe or it block in which it is defined, and will be removed after each spec
Sample Code
it(`Fake Login with should set isAuthenticated Flag and finally call route: ects`,
async(inject([AuthenticationService, HttpTestingController],
(service: AuthenticationService, backend: HttpTestingController) => {
spyOn(service.router, 'navigate').and.returnValue(true);
service.login('Helmut', 'mySecret');
// Fake a HTTP response with a Bearer Token
// Ask the HTTP mock to return some fake data using the flush method:
backend.match({
method: 'POST'
})[0].flush({ Bearer: 'A Bearer Token: XXXXXXX' });
expect(service.router.navigate).toHaveBeenCalled();
expect(service.router.navigate).toHaveBeenCalledWith(['ects']);
expect(service.isAuthenticated()).toEqual(true);
})));
Reference
My Fist Karma Sample
Screenshot Chrome Browser after running Tests |
Details |
|
- Karma verison is v1.7.1
- Only 1 of our 18 test was running as we use fdescribe
- The test shows no error
- The Screen is devided into 2 divs
- Div with class html-report shows the test details
- Div with class root0 shows the angular HTML components
|
Html Code |
Type Script TestCode: login.components.spec.ts |
TestKarma
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import {FormsModule} from '@angular/forms';
import {RouterTestingModule} from '@angular/router/testing';
import {AuthenticationService} from '../authentication.service';
import {AuthGuard} from '../auth-guard.service';
fdescribe ('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture;
let h1: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginComponent ],
imports: [FormsModule, RouterTestingModule ],
providers: [AuthenticationService]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
h1 = fixture.nativeElement.querySelector('h1');
console.log(h1);
fixture.detectChanges();
});
it('should have with TestKarma', () => {
const loginElement: HTMLElement = fixture.nativeElement;
h1 = loginElement.querySelector('h1');
expect(h1.textContent).toEqual('TestKarma');
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});
|
Debug Karma Test
- Add debugger keyword to your Java Script Code you want to debug
- Start Karma tests with : ng test
- Add Chrome Debugger Tools by pressing F12
- Reload your page – Javascript code should stop on the line with debugger statement
Screenshot Chrome Browser after running Tests |
Details |
|
|
A more complexer Sample setting up a Karma Test Environment for Integration Tests
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CurrentSemesterComponent } from './current-semester.component';
import { CommonHeaderComponent } from '../common-header/common-header.component';
import { NavigationComponent } from '../navigation/navigation.component';
import { RouterTestingModule } from '@angular/router/testing';
import { MatIconModule } from '@angular/material';
import {MatButtonToggleModule} from '@angular/material/button-toggle';
import {AuthenticationService} from '../auth/authentication.service';
fdescribe('CurrentSemesterComponent', () => {
let component: CurrentSemesterComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CurrentSemesterComponent,CommonHeaderComponent, NavigationComponent ],
providers: [AuthenticationService,],
imports: [RouterTestingModule, MatIconModule, MatButtonToggleModule ],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CurrentSemesterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Jasmine Test Order
- Currently (v2.x) Jasmine runs tests in the order they are defined
- However, there is a new (Oct 2015) option to run specs in a random order, which is still off by default
- According to the project owner, in Jasmine 3.x it will be converted to be the default.
Reference
Jasmine and Timeout
Reference
https://makandracards.com/makandra/32477-testing-settimeout-and-setinterval-with-jasmine
Error: router-outlet’ is not a known element:
Error Details
'router-outlet' is not a known element:
1. If 'router-outlet' is an Angular component, then verify that it is part of this module.
2. If 'router-outlet' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
"
[ERROR ->]
"): ng:///DynamicTestModule/AppComponent.html@2:2
Fix – import RouterTestingModule
import {RouterTestingModule} from '@angular/router/testing'
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [ RouterTestingModule ]
}).compileComponents();
}));
Reference
Error: app-navigation’ is not a known element:
Error Details
AppComponent should create the app
Failed: Template parse errors:
'app-navigation' is not a known element:
1. If 'app-navigation' is an Angular component, then verify that it is part of this module.
2. If 'app-navigation' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
app
[ERROR ->]
Angular code
app.component.html
navigation.component.ts
import {Component, OnInit} from '@angular/core';
import {AuthenticationService} from '../auth/authentication.service';
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
...
Fix – Add a stubbing Object
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import {RouterTestingModule} from '@angular/router/testing'
import {Component} from '@angular/core';
@Component({selector: 'app-navigation', template: ''})
class NavigationStubComponent {}
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
NavigationStubComponent
],
imports: [ RouterTestingModule ]
}).compileComponents();
})
Reference
Error Injecting a service
Error Datails: NullInjectorError: No provider for AuthenticationService!
NavigationComponent should create
Error: StaticInjectorError(DynamicTestModule)[NavigationComponent -> AuthenticationService]:
StaticInjectorError(Platform: core)[NavigationComponent -> AuthenticationService]:
NullInjectorError: No provider for AuthenticationService!
Fix add AuthenticationService to the provider Array
import {AuthenticationService} from '../auth/authentication.service';
describe('NavigationComponent', () => {
let component: NavigationComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NavigationComponent ],
providers: [
MatSnackBar,
Overlay,
AuthenticationService,
SnackBarComponent,
DatePipe],
})
.compileComponents();
}));
Error: Failed: Template parse errors
Error Datails: There is no directive with “exportAs” set to “ngForm”
LoginComponent should create
Failed: Template parse errors:
There is no directive with "exportAs" set to "ngForm" ("