Angular Tutorial: App Testing using Karma

Sukra Trihatmaja | October 11th, 2017

Angular Tutorial: Setting up Unit Testing Using Karma on VS2017

This post is an Angular tutorial for setting up the test environment for an existing Angular application project and running unit tests using Karma on Visual Studio 2017 IDE. Karma is a tool which spawns a web server that executes tests defined by using supported test frameworks for each connected browser. Karma can be used to do testing using most of the common frameworks (including Jasmine, Mocha, QUnit). We use a number of testing tools, but we use Karma in particular because it is easy to configure, simple, and lightweight. It is our preferred task runner for Angular testing because it allows us to run tests on multiple real browsers, watch code changes, automatically re-run the tests, and makes debugging easy.
 

Other Testing Tools

There are some other tools we use to test Angular applications including Jasmine, Angular Testing Utilities, and Protractor.

Jasmine

Jasmine is an open source testing framework that uses a behavior driven development (BDD) style. In Jasmine tests, you describe what you will test, tell the test what it should do, then check the result against the expected conditions.

Angular Testing Utilities

Angular developers already provide utilities to test Angular applications. TestBed is the most important utility, which allows you to create a module environment for the class you want to test using the configureTestingModule method. For more details about Angular Testing Utilities, you can visit Angular Testing documentation here. In my next post I’ll talk about how to use Angular Testing Utilities.

Protractor

Protractor is a framework built on top of WebDriverJS used for end-to-end testing for Angular and AngularJS applications. Protractor is intended for use in testing applications from the user point-of-view. By default, Protractor uses the Jasmine test framework for its testing interface.

Prerequisites

This tutorial is using a Dashboard Application project as the tested application. This project is built using .NETCore 2.0 Framework, ASP.NET Core 2.0 on the back-end and Angular on the front-end. The project code can be accessed here.
 

Setting Up the Test Environment

  1. Install Jasmine
  2. > npm install jasmine @types/jasmine ––save-dev

  3. Install Karma
  4. > npm install karma ––save-dev

  5. Install Karma Plugins
  6. > npm install karma-jasmine karma-chrome-launcher karma-webpack @types/webpack-env ––save-dev

  7. Since we are going to use typescript, we need to configure jasmine and webpack-env type definitions on tsconfig.json. Add the following configuration on compilerOptions:
  8. 
    ...
    "typeRoots": [
        "node_modules/@types"
    ],
    "types": [
        "jasmine",
        "webpack-env"
    ]
    ...
    
    
  9. Create a new folder with the name “test” under the ClientApp folder. We will use this folder as the base folder of our testing environment.
  10.  

  11. Create configuration file that will let karma-webpack plugin to compile all test cases into one bundle.
  12. 
    // polyfills
    import "core-js";
    
    // zone.js
    import "zone.js/dist/zone";
    import "zone.js/dist/proxy";
    import "zone.js/dist/sync-test";
    import "zone.js/dist/async-test";
    import "zone.js/dist/fake-async-test";
    import "zone.js/dist/jasmine-patch";
    import "zone.js/dist/long-stack-trace-zone";
    
    // TestBed initialization
    import { TestBed } from "@angular/core/testing";
    import {
        BrowserDynamicTestingModule,
        platformBrowserDynamicTesting
    } from "@angular/platform-browser-dynamic/testing";
    
    TestBed.initTestEnvironment(
        BrowserDynamicTestingModule,
        platformBrowserDynamicTesting()
    );
    
    // Webpack test context initialization
    const context = require.context(".", true, /\.spec\.ts$/);
    context.keys().map(context);
    
  13. Add karma configuration file (karma.conf.js)
  14. 
    // reuse existing webpack.config
    // remove entry value since karma-webpack will set its value automatically
    var webpackConfig = require("../../webpack.config.js")();
    webpackConfig.entry = undefined;
    
    module.exports = (config) => {
        config.set({
            basePath: ".",
            frameworks: ["jasmine"],
            files: [
                "./test.main.ts"
            ],
            preprocessors: {
                "./test.main.ts": ["webpack"]
            },
            mime: {
                "text/x-typescript": ["ts"]
            },
            webpack: webpackConfig,
            webpackMiddleware: {
                stats: "error-only"
            },
            reporters: ["progress"],
            port: 9876,
            colors: true,
            logLevel: config.LOG_ERROR,
            singleRun: true,
            browsers: ["Chrome"],
            concurrency: Infinity
        });
    }
    
  15. Create test specification file (test.spec.ts)
  16. 
    import { TestBed, ComponentFixture, async } from "@angular/core/testing";
    import { NO_ERRORS_SCHEMA, DebugElement } from "@angular/core";
    import { By } from "@angular/platform-browser";
    import { AppComponent } from "../app/app.component";
    
    describe("AppComponent", () => {
        let componentFixture: ComponentFixture;
        let debugElement: DebugElement;
    
        beforeEach(async(() => {
            TestBed.configureTestingModule({
                declarations: [AppComponent],
                schemas: [NO_ERRORS_SCHEMA]
            });
    
            TestBed.compileComponents();
        }));
    
        it("should have 'Dashboard' on header text", () => {
            componentFixture = TestBed.createComponent(AppComponent);
            debugElement = componentFixture.debugElement;
            componentFixture.detectChanges();
            const headerElement = debugElement.query(By.css(".page-header h1")).nativeElement;
            expect(headerElement.textContent).toContain("Dashboard");
        });
    });
    

 

Running Tests Using NPM Script

  1. Add “test” script to package.json
  2. 
    ...
    "scripts": {
        "build": "webpack",
        "test": "karma start ClientApp/test/karma.conf.js"
    }
    ...
    
    
  3. Run the script via command prompt
  4. > npm test
    angular tutorial testing npm script

 

Running Tests Using Gulp

  1. Install Gulp
  2. > npm install gulp ––save-dev

  3. Add new gulp configuration file (gulpfile.js)
  4. angular tutorial testing gulp

  5. Configure gulp to start karma task runner (gulp-karma)
  6. 
    var gulp = require("gulp");
    var Server = require("karma").Server;
    
    const configPath = __dirname + "/ClientApp/test/karma.conf.js";
    
    gulp.task("test", function (done) {
        new Server({
            configFile: configPath,
            singleRun: true
        }, done).start();
    });
    
    gulp.task("tdd", function (done) {
        new Server({
            configFile: configPath,
            singleRun: false
        }, done).start();
    });
    
  7. Open Task Runner Explorer window and then run the tests
  8. angular tutorial testing gulp

 

Using karma-spec-reporter

If we use karma progress reporter, we can’t see the description of the test being executed by Karma. We could use karma-spec-reporter plugin to get the Karma report description of our tests. Here are the steps to use the plugin:

  1. Install karma-spec-reporter plugin
  2. > npm install karma-spec-reporter ––save-dev

  3. Update reporter configuration on karma.conf.js
  4. 
    ...
    
    reporters: ["spec"],
    
    ...
    
  5. Re-run the tests
  6. angular tutorial testing karma spec reporter

 
 
Now we have the test environment set. Then we can continue writing the rest of the test codes. Here is the project structure we have right now:

angular tutorial karma folder structure

On my next blog post, I will continue this angular tutorial series with Angular Tutorial: Testing using Angular Testing Utilities (TestBed).
 
The final code of this tutorial can be accessed on my GitHub repository here.
 
Thanks!

Sukra Trihatmaja

Sukra is a Software Developer at Palador. During his free time, he enjoys playing video games and doing research on electronics related technology.