×
Table of Contents
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 |
---|---|
“;[/insert_php] |
|
Html Code | Type Script TestCode: login.components.spec.ts |
---|---|
TestKarma
|
|
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 |
---|---|
“;[/insert_php] | “;[/insert_php] |
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.htmlnavigation.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" ("