A Tutorial of Angular, Karma and Jasmine

By Published On: April 7, 20226.4 min readViews: 182

Hey!

In my career, I haven’t spent much time on front-end programming. However, I had it now!
It’s a really exciting journey learning Angular/Karma/Jasmine and I feel like I will probably spent more time on it to gain more depth insights!

Today’s article is my learning journey on this, hope you will find it as a great tutorial ^^

Introductions

Angular Testing Utilities

Angular is a TypeScript-based free and open-source web application framework led by the Angular Team at Google and by a community of individuals and corporations. Angular is a complete rewrite from the same team that built AngularJS.

Angular testing utilities provide you a library to create a test environment for your application.

Classes such as TestBed and ComponentFixtures and helper functions such as async and fakeAsync are part of the @angular/core/testing package.

Getting acquainted with these utilities is necessary if you want to write tests that reveal how your components interact with their own template, services, and other components.

Ref Links

  1. Angular Testing Guide

Karma

Karma is a tool that lets you test your application on multiple browsers.
Karma has plugins for browsers like Chrome, Firefox, Safari, and many others.
But I prefer using a headless browser for testing.
A headless browser lacks a GUI, and that way, you can keep the test results inside your terminal.

Ref Links

  1. Karma github
  2. Karma package on npmjs

Jasmine

Jasmine is a popular behavior-driven testing framework for JavaScript. With Jasmine, you can write tests that are more expressive and straightforward.

Here is an example to get started:

it('should have a defined component', () => {
        expect(component).toBeDefined();
});

Ref Links

  1. Wiki
  2. Official website

Steps

Environment

❯ nvm ls
       v12.13.1
->     v16.14.0
        v17.6.0
default -> 16.14 (-> v16.14.0)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v17.6.0) (default)
stable -> 17.6 (-> v17.6.0) (default)
lts/* -> lts/gallium (-> v16.14.0)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.10 (-> N/A)
lts/fermium -> v14.19.0 (-> N/A)
lts/gallium -> v16.14.0
❯ npm -v
8.3.1
❯ node -v
v16.14.0
❯ ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 13.2.6
Node: 16.14.0
Package Manager: npm 8.3.1
OS: darwin x64

Angular: 13.2.7
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1302.6
@angular-devkit/build-angular   13.2.6
@angular-devkit/core            13.2.6
@angular-devkit/schematics      13.2.6
@angular/cli                    13.2.6
@schematics/angular             13.2.6
rxjs                            7.5.5
typescript                      4.5.5

New An Angular Project

The developers at Angular have made it easy for us to set up our test environment. To get started, we need to install Angular first.

I prefer using the Angular-CLI. It’s an all-in-one solution that takes care of creating, generating, building and testing your Angular project.

ng new Pastebin

Answer yes to Would you like to add Angular routing?; Answer CSS to Which stylesheet format would you like to use? CSS.

Directory structure:

❯ ls -l
total 1568
-rw-r--r--    1 geekcoding101  staff    1054 Apr  8 11:51 README.md
-rw-r--r--    1 geekcoding101  staff    3051 Apr  8 11:51 angular.json
-rw-r--r--    1 geekcoding101  staff    1425 Apr  8 11:51 karma.conf.js
drwxr-xr-x  600 geekcoding101  staff   19200 Apr  8 11:53 node_modules
-rw-r--r--    1 geekcoding101  staff  773285 Apr  8 11:53 package-lock.json
-rw-r--r--    1 geekcoding101  staff    1071 Apr  8 11:51 package.json
drwxr-xr-x   11 geekcoding101  staff     352 Apr  8 11:51 src
-rw-r--r--    1 geekcoding101  staff     287 Apr  8 11:51 tsconfig.app.json
-rw-r--r--    1 geekcoding101  staff     863 Apr  8 11:51 tsconfig.json
-rw-r--r--    1 geekcoding101  staff     333 Apr  8 11:51 tsconfig.spec.json
❯ tree src
src
├── app
│   ├── app-routing.module.ts
│   ├── app.component.css
│   ├── app.component.html
│   ├── app.component.spec.ts
│   ├── app.component.ts
│   └── app.module.ts
├── assets
├── environments
│   ├── environment.prod.ts
│   └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
└── test.ts

3 directories, 14 files

Launch Angular project:

Run karma:

You can define a headless browser in your karma.conf.js as below:

...
browsers: ['Chrome','ChromeNoSandboxHeadless'],

customLaunchers: {
 ChromeNoSandboxHeadless: {
    base: 'Chrome',
    flags: [
      '--no-sandbox',
      // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
      '--headless',
      '--disable-gpu',
      // Without a remote debugging port, Google Chrome exits immediately.
      ' --remote-debugging-port=9222',
    ],
  },
},
...

You can refer to Cheatsheet about how to run unit test and specify which browser to run your test.

Add Class

ng generate class Pastebin

Pastebin.ts:

export class Pastebin {
 
    id: number;
    title: string;
    language: string;
    paste: string;
 
    constructor(values: Object = {}) {
        Object.assign(this, values);
  }
 
}
 
export const Languages = ["Ruby","Java", "JavaScript", "C", "Cpp"];

pastebin.spec.ts:

import { Pastebin } from './pastebin';

describe('Pastebin', () => {
  it('should create an instance of Pastebin', () => {
    expect(new Pastebin()).toBeTruthy();
  });
  it('should accept values', () => {
    let pastebin = new Pastebin();
    pastebin = {
      id: 111,
      title: "Hello world",
      language: "Ruby",
      paste: 'print "Hello"',
    }
    expect(pastebin.id).toEqual(111);
    expect(pastebin.language).toEqual("Ruby");
    expect(pastebin.paste).toEqual('print "Hello"');
  });
});

Setting Up Angular-in-Memory-Web-API

We don’t have a server API for the application we are building. Therefore, we are going to simulate the server communication using a module known as InMemoryWebApiModule.

npm install angular-in-memory-web-api --save

Add Services

ng generate service pastebin
ng generate service in-memory-data

PastebinService will host the logic for sending HTTP requests to the server.

pastebin.service.ts

import { Injectable } from '@angular/core';
import { Pastebin } from './pastebin';
import { HttpClient, HttpHeaders } from '@angular/common/http';
// import { lastValueFrom } from 'rxjs';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class PastebinService {
  // The project uses InMemoryWebApi to handle the Server API. 
  // Here "api/pastebin" simulates a Server API url 
  private pastebinUrl = "api/pastebin";
  private headers = new Headers({ 'Content-Type': "application/json" });
  constructor(private http: HttpClient) { }

  // getPastebin() performs http.get() and returns a promise
  public getPastebin(): Promise<any> {
    return this.http.get(this.pastebinUrl)
      .toPromise()
      .then(response => response.json().data)
      .catch(this.handleError);
  }

  private handleError(error: any): Promise<any> {
    console.error('An error occurred', error);
    return Promise.reject(error.message || error);
  }
}

in-memory-data.service.ts will implement InMemoryDbService:

import { InMemoryDbService } from 'angular-in-memory-web-api';
import { Pastebin } from './pastebin';

export class InMemoryDataService implements InMemoryDbService {
  createDb() {
    const pastebin:Pastebin[] = [
      { id: 0,  title: "Hello world Ruby", language: "Ruby", paste: 'puts "Hello World"' },
      {id: 1, title: "Hello world C", language: "C", paste: 'printf("Hello world");'},
      {id: 2, title: "Hello world CPP", language: "C++", paste: 'cout<<"Hello world";'},
      {id: 3, title: "Hello world Javascript", language: "JavaScript", paste: 'console.log("Hello world")'}
       
    ];
    return {pastebin};
  }
}

Update app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule }    from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

//In memory Web api to simulate an http server
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService }  from './in-memory-data.service';

import { PastebinService } from "./pastebin.service";


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    InMemoryWebApiModule.forRoot(InMemoryDataService),
    AppRoutingModule
  ],
  providers: [PastebinService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Create

Cheatsheet

Operations Command Comments
New an Angular project ng new <project_name>  
Generate a new class ng generate class <component name>  
Generate a new service ng generate service <service component name>  
Launch Angular project ng serve or npm start  
Launch unit test ng test or npm test  
Launch unit test in specific browser npm test -- --browsers ChromeNoSandboxHeadless or ng test --browsers ChromeNoSandboxHeadless Prerequistes: You need have ChromeNoSandboxHeadless defined in your karma.conf.js
Create component without specs ng g component --skip-tests=true <component name> You can refer to Stackoverflow for more solutions.
Run specific unit test ng t -- --include "src/**/your_file_name.component.spec.ts"  
Run specific unit test with relative path ng test -- --include "relative_path_of_the_spec.ts " I’ve tried to use ./ start the relative path, it didn’t work. So you’d better to use src/….

Q/A

References

  1. Angular unit testing tutorial with examples

Share it:

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments