Testing Angular services

 

Let's first create a Todo.ts model class that represents the Todo item. The following code snippet shows the content of the Todo class:

export class Todo { 
    title: string; 
    completed: boolean;
    constructor(title: string) { 
        this.title = title; 
        this.completed = false; 
    } 
    set isCompleted(value: boolean) { 
        this.completed = value; 
    } 
} 

 

Next, create a service todo.service.ts that constructs the list of Todo items in the constructor. The complete code of todo.service.ts is as shown:

import { Todo } from './todo' 
export class TodoService { 
    todos: Array<Todo> 
    constructor() { 
        this.todos = [new Todo('First item'), 
        new Todo('Second item'), 
        new Todo('Third item')]; 
    } 
    getPending() { 
        return this.todos.filter((todo: Todo) => todo.completed === 
false); } getCompleted() { return this.todos.filter((todo: Todo) => todo.completed ===
true); } remove(todo: Todo) { this.todos.splice(this.todos.indexOf(todo), 1); } add(title: string) { this.todos.push(new Todo(title)); } toggleCompletion(todo: Todo) { todo.completed = !todo.completed; } removeCompleted() { this.todos = this.getPending(); } }

We have the service that interacts with the data source in place. Now, let's write tests using the Jasmine framework to test the TodoService. We will test two methods, namely getPending() and getCompleted(). Create a file named todo.service.spec.ts.

Import the TodoService application-specific service, as follows:

import { TodoService } from "./todo.service"; 

Define the describe method: a global function that is the starting point of the Jasmine function that takes two parameters, a string that describes the tests and a function that has the actual implementation of testing:

describe("TodoService Testing",() => { 
}); 

Declare the beforeEach function that will be executed before running each test inside the describe global function. The code snippet of the describe function with beforeEach is given here:

describe('TodoService Testing', () => { 
  let service: TodoService; 
  beforeEach(() => { service = new TodoService(); });   
}); 

The beforeEach function will be executed before running each test method, and it serves an instance of TodoService for each test.

Now, let's define the it test methods, as demonstrated:

it('getPending length should return 3', () => { 
    expect(service.getPending().length).toBe(3); 
}); 
it('getCompleted length should return 0', () => { 
    expect(service.getCompleted().length).toBe(0); 
}); 

Here, we are verifying that the expectations of the length of the returned values of getPending() and getCompleted() match.

The complete code snippet of todo.service.spec.ts is this:

import { TodoService } from "./todo.service";  
describe('TodoService Testing', () => { 
  let service: TodoService; 
  beforeEach(() => { service = new TodoService(); }); 
  it('getPending length should return 3', () => { 
    expect(service.getPending().length).toBe(3); 
  }); 
  it('getCompleted length should return 0', () => { 
    expect(service.getCompleted().length).toBe(0); 
  }); 
}); 

We have the spec or tests ready to run; let's run them by executing the following commands:

    npm run build:watch
    karma start karma.conf.js

The npm run build:watch command will build your application and transpile the TypeScript files into JavaScript. Then, the karma start karma.config command is executed to start the test runner for our application.

Karma is a test runner that can be used to run tests for any JavaScript application. The karma.config.js file is a configuration file for karma that provides information about our application to karma in order for it to understand and test the application. The karma configuration file has details of the path of JavaScript libraries and frameworks that the application is consuming, and also, it provides details about the plugins used by karma.

Karma config file has the configuration details for basePath, frameworks, plugins, client, and custom launcher in our application. We have configured Jasmine as our test framework in karma, we have added the list of required modules under plugins to load when running the test. We also configured the client with buildPaths and clearContext. The buildPaths will have path details to look for the transpiled app JS and map files. The following is the complete karma configuration file for your reference:

module.exports = function(config)   {    
  var appBase    = 'src/';         // transpiled app JS and map files   
  var appAssets  = '/base/app/';   // component assets fetched by  
Angular's compiler // Testing helpers (optional) are conventionally in a folder called
`testing` var testingBase = 'src/testing/'; // transpiled test JS and map
files var testingSrcBase = 'src/testing/'; // test source TS
files config.set({ basePath: '', frameworks: ['jasmine'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-jasmine-html-reporter') ], client:
{ builtPaths: [appBase, testingBase], // add more
spec base paths
as needed clearContext: false // leave Jasmine Spec Runner
output visible
in browser }, customLaunchers: { // From the CLI. Not used here but interesting // chrome setup for travis CI using chromium Chrome_travis_ci: { base: 'Chrome', flags: ['--no-sandbox'] } }, files: [ // System.js for module loading 'node_modules/systemjs/dist/system.src.js', // Polyfills 'node_modules/core-js/client/shim.js', // zone.js 'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-
zone.js', 'node_modules/zone.js/dist/proxy.js', 'node_modules/zone.js/dist/sync-test.js', 'node_modules/zone.js/dist/jasmine-patch.js', 'node_modules/zone.js/dist/async-test.js', 'node_modules/zone.js/dist/fake-async-test.js', // RxJs { pattern: 'node_modules/rxjs/**/*.js', included:
false,
watched: false }, { pattern: 'node_modules/rxjs/**/*.js.map',
included: false,
watched: false }, // Paths loaded via module imports: // Angular itself { pattern: 'node_modules/@angular/**/*.js',
included: false,
watched: false }, { pattern: 'node_modules/@angular/**/*.js.map',
included:
false, watched: false }, { pattern: appBase + '/systemjs.config.js',
included: false,
watched: false }, { pattern: appBase + '/systemjs.config.extras.js',
included:
false, watched: false }, 'karma-test-shim.js', // optionally extend
SystemJS mapping
e.g., with barrels // transpiled application & spec code paths loaded
via module
imports { pattern: appBase + '**/*.js', included: false,
watched: true
}, { pattern: testingBase + '**/*.js', included:
false, watched:
true
}, // Asset (HTML & CSS) paths loaded via Angular's
component
compiler // (these paths need to be rewritten, see proxies
section) { pattern: appBase + '**/*.html', included: false,
watched:
true
}, { pattern: appBase + '**/*.css', included: false,
watched: true
}, // Paths for debugging with source maps in dev
tools { pattern: appBase + '**/*.ts', included: false,
watched: false
}, { pattern: appBase + '**/*.js.map', included:
false, watched:
false
}, { pattern: testingSrcBase + '**/*.ts', included:
false,
watched: false }, { pattern: testingBase + '**/*.js.map', included:
false,
watched: false} ], // Proxied base paths for loading assets proxies:
{ // required for modules fetched by SystemJS '/base/src/node_modules/': '/base/node_modules/' }, exclude: [], preprocessors: {}, reporters: ['progress', 'kjhtml'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false }) }

The command, karma start, takes the karma config file path as argument and will start the karma test runner. The npm run build command is configured in pretest so that it will be executed before a test is run. It executes the tsc -p src command, a TypeScript compiler that transpiles the code in the src folder. The following screenshot illustrates the command window that executes these commands as per the configuration in package.json under the scripts item:

          C:Users
ajesh.gPacktChapter8mytodos>npm     
test
> [email protected] pretest
C:Users ajesh.gPacktChapter8mytodos
> npm run build > [email protected] build
C:Users ajesh.gPacktChapter8mytodos
> tsc -p src/ > [email protected] test
C:Users ajesh.gPacktChapter8mytodos
> concurrently "npm run build:watch" "karma
start
karma.conf.js"

Karma launches the application in a browser and runs all the tests in the specs. The http-server command will start the development server to host the mytodo Angular application. The result of the test execution is as shown:

The test results of TodoService
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset