├── .npmignore ├── .gitignore ├── src ├── models │ ├── employee.ts │ └── employee.spec.ts ├── main.ts ├── pages │ ├── app.component.html │ ├── employee-list.component.html │ ├── employee-detail.component.html │ ├── employee-form.component.html │ └── employee-edit-form.component.html ├── tsconfig.json ├── assets │ └── stylesheets │ │ └── style.css ├── services │ ├── employee-list-service.component.ts │ ├── employee-detail-service.component.ts │ ├── employee-delete-service.component.ts │ ├── employee-edit-form-service.component.ts │ ├── employee-form-service.component.ts │ ├── employee-form-service.component.spec.ts │ ├── employee-delete-service.component.spec.ts │ ├── employee-list-service.component.spec.ts │ └── employee-detail-service.component.spec.ts ├── components │ ├── employee-form.component.ts │ ├── list.component.ts │ ├── employee-edit-form.component.ts │ ├── employee-detail.component.ts │ ├── employee-form.component.spec.ts │ ├── employee-edit-form.component.spec.ts │ ├── employee-detail.component.spec.ts │ └── list.component.spec.ts └── app.component.ts ├── typings.json ├── LICENSE ├── index.html ├── package.json ├── README.md ├── karma-test-shim.js └── karma.conf.js /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | coverage 4 | src 5 | typings 6 | typings.json -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | coverage 4 | dist 5 | typings 6 | npm-debug.log 7 | db.json 8 | listing.md 9 | -------------------------------------------------------------------------------- /src/models/employee.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export class Employee { 4 | constructor ( 5 | public id: number, 6 | public name: string 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrap } from 'angular2/platform/browser'; 2 | import { AppComponent } from './app.component'; 3 | import { ROUTER_PROVIDERS } from 'angular2/router'; 4 | import 'rxjs/Rx'; 5 | 6 | bootstrap(AppComponent, [ROUTER_PROVIDERS]); -------------------------------------------------------------------------------- /src/pages/app.component.html: -------------------------------------------------------------------------------- 1 |

EMPLOYEE CRUD APP

2 | 3 |

Employee List

4 |
5 | 6 |

Add Employee

7 |
8 | 9 | -------------------------------------------------------------------------------- /src/pages/employee-list.component.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-testing", 3 | "dependencies": {}, 4 | "devDependencies": {}, 5 | "ambientDependencies": { 6 | "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", 7 | "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#dd638012d63e069f2c99d06ef4dcc9616a943ee4" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "sourceMap": true, 9 | "removeComments": true, 10 | "declaration": true, 11 | "outDir": "../dist" 12 | }, 13 | "exclude": [ 14 | "node_modules" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/pages/employee-detail.component.html: -------------------------------------------------------------------------------- 1 |

EMPLOYEE DETAIL

2 | 3 |

4 | Name: {{currentEmployee.name}} 5 |
6 | 7 | EDIT 8 | 9 | 13 |

14 | -------------------------------------------------------------------------------- /src/assets/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | /* Master Styles */ 2 | h1 { 3 | color: #369; 4 | font-family: Arial, Helvetica, sans-serif; 5 | font-size: 250%; 6 | } 7 | 8 | h2, h3 { 9 | color: #444; 10 | font-family: Arial, Helvetica, sans-serif; 11 | font-weight: lighter; 12 | } 13 | 14 | body { 15 | margin: 2em; 16 | } 17 | 18 | body, input[text], button { 19 | color: #888; 20 | font-family: Cambria, Georgia; 21 | } 22 | 23 | .headings { 24 | display: inline-block; 25 | margin-right: 10px; 26 | } -------------------------------------------------------------------------------- /src/models/employee.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import {it, describe, expect} from "angular2/testing"; 4 | 5 | import { Employee } from './employee'; 6 | 7 | describe('Tests for Employee Model', () => { 8 | let employee; 9 | 10 | beforeEach(function() { 11 | employee = new Employee(1, 'Abhinav Mishra'); 12 | }); 13 | 14 | it('should have name as assigned',() => { 15 | expect(employee.name).toEqual('Abhinav Mishra'); 16 | }); 17 | 18 | it('should have id as assigned',() => { 19 | expect(employee.id).toEqual(1); 20 | }); 21 | }); -------------------------------------------------------------------------------- /src/pages/employee-form.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Employee Form

3 |
4 |
5 | 6 | 9 |
10 | Name is required 11 |
12 |
13 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /src/pages/employee-edit-form.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Employee Edit Form

3 |
4 |
5 | 6 | 8 |
9 | Name is required 10 |
11 |
12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/services/employee-list-service.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Injectable } from 'angular2/core'; 4 | import {Http, Response } from 'angular2/http'; 5 | import { Observable } from 'rxjs/Observable'; 6 | 7 | import { Employee } from '../models/employee'; 8 | 9 | @Injectable() 10 | export class EmployeeListServiceComponent { 11 | constructor(private http: Http) { } 12 | 13 | private _employeesUrl: string = 'http://localhost:3000/employees'; 14 | 15 | getEmployees () { 16 | return this.http.get(this._employeesUrl) 17 | .map(res => res.json()) 18 | .catch(this._handleError); 19 | } 20 | 21 | private _handleError (error: Response) { 22 | console.error(error); 23 | return Observable.throw(error.json().error || 'Server error'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/components/employee-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from 'angular2/core'; 2 | 3 | import { Employee } from '../models/employee'; 4 | import { EmployeeFormServiceComponent } from '../services/employee-form-service.component'; 5 | 6 | @Component({ 7 | selector: 'employee-form', 8 | templateUrl: 'src/pages/employee-form.component.html', 9 | providers: [EmployeeFormServiceComponent] 10 | }) 11 | 12 | export class EmployeeFormComponent { 13 | constructor( 14 | private _employeeService: EmployeeFormServiceComponent 15 | ){} 16 | 17 | public model: Employee = {name: '', id: 1 }; 18 | public errorMessage: string; 19 | 20 | newEmployee() { 21 | this._employeeService.addEmployee(this.model.name) 22 | .subscribe( 23 | employee => this.model = employee, 24 | error => this.errorMessage = error 25 | ); 26 | window.history.back(); 27 | } 28 | 29 | onKey(event: any) { 30 | this.model.name = event.target.value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/services/employee-detail-service.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Injectable } from 'angular2/core'; 4 | import {Http, Response } from 'angular2/http'; 5 | import { Observable } from 'rxjs/Observable'; 6 | 7 | import { Employee } from '../models/employee'; 8 | 9 | @Injectable() 10 | export class EmployeeDetailServiceComponent { 11 | constructor(private http: Http) { } 12 | 13 | private _employeesUrl: string = 'http://localhost:3000/employees/'; 14 | 15 | getEmployee (id: number): Observable { 16 | this._employeesUrl += id; 17 | 18 | return this.http.get(this._employeesUrl) 19 | .map(res => this._log(res)) 20 | .catch(this._handleError); 21 | } 22 | 23 | private _handleError (error: Response) { 24 | console.error(error); 25 | return Observable.throw(error.json().error || 'Server error'); 26 | } 27 | 28 | private _log(res): Employee { 29 | return res.json(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/services/employee-delete-service.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Injectable } from 'angular2/core'; 4 | import {Http, Response } from 'angular2/http'; 5 | import { Observable } from 'rxjs/Observable'; 6 | 7 | import { Employee } from '../models/employee'; 8 | 9 | @Injectable() 10 | export class EmployeeDeleteServiceComponent { 11 | public currentEmployee: Employee; 12 | public errorMessage: string; 13 | 14 | constructor( 15 | private http: Http 16 | ) {} 17 | 18 | private _employeesUrl: string = 'http://localhost:3000/employees/'; 19 | 20 | deleteEmployee (id: number): Observable { 21 | this._employeesUrl += id; 22 | 23 | return this.http.delete(this._employeesUrl) 24 | .map(res => res.json()) 25 | .catch(this._handleError); 26 | } 27 | 28 | private _handleError (error: Response) { 29 | console.error(error); 30 | return Observable.throw(error.json().error || 'Server error'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/list.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Component, OnInit } from 'angular2/core'; 3 | import { ROUTER_DIRECTIVES } from 'angular2/router'; 4 | 5 | import { Employee } from '../models/employee'; 6 | import { EmployeeListServiceComponent } from '../services/employee-list-service.component'; 7 | 8 | @Component({ 9 | selector: 'employee-list', 10 | templateUrl: 'src/pages/employee-list.component.html', 11 | directives: [ROUTER_DIRECTIVES], 12 | providers: [EmployeeListServiceComponent] 13 | }) 14 | 15 | export class EmployeeListComponent implements OnInit { 16 | public employees: Employee[]; 17 | public errorMessage: string; 18 | 19 | constructor( 20 | private _listingService: EmployeeListServiceComponent 21 | ){} 22 | 23 | ngOnInit() { 24 | this._listingService.getEmployees().subscribe( 25 | employees => this.employees = employees, 26 | error => this.errorMessage = error 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/services/employee-edit-form-service.component.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from 'angular2/core'; 2 | import {Http, Response, Headers, RequestOptions } from 'angular2/http'; 3 | import { Observable } from 'rxjs/Observable'; 4 | 5 | import { Employee } from '../models/employee'; 6 | 7 | @Injectable() 8 | export class EmployeeEditFormServiceComponent { 9 | constructor(private http: Http) { } 10 | 11 | private _employeesUrl: string = 'http://localhost:3000/employees/'; 12 | 13 | editEmployee (employee: Employee) : Observable { 14 | this._employeesUrl += employee.id; 15 | 16 | let body = JSON.stringify({ name: employee.name }); 17 | let headers = new Headers({ 'Content-Type': 'application/json' }); 18 | let options = new RequestOptions({ headers: headers }); 19 | 20 | return this.http.patch(this._employeesUrl, body, options) 21 | .map(res => res.json()) 22 | .catch(this._handleError) 23 | } 24 | 25 | private _handleError (error: Response) { 26 | console.error(error); 27 | return Observable.throw(error.json().error || 'Server error'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Abhinav Mishra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Angular 2 Testing 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/services/employee-form-service.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Injectable } from 'angular2/core'; 4 | import {Http, Response, Headers, RequestOptions } from 'angular2/http'; 5 | import { Observable } from 'rxjs/Observable'; 6 | 7 | import { Employee } from '../models/employee'; 8 | 9 | @Injectable() 10 | export class EmployeeFormServiceComponent { 11 | constructor(private http: Http) { } 12 | 13 | private _employeesUrl: string = 'http://localhost:3000/employees'; 14 | 15 | addEmployee (name: string) : Observable { 16 | 17 | let body = JSON.stringify({ name: name }); 18 | let headers = new Headers({ 'Content-Type': 'application/json' }); 19 | let options = new RequestOptions({ headers: headers }); 20 | 21 | return this.http.post(this._employeesUrl, body, options) 22 | .map(res => res.json()) 23 | .catch(this._handleError) 24 | } 25 | 26 | private _handleError (error: Response) { 27 | // in a real world app, we may send the error to some remote logging infrastructure 28 | // instead of just logging it to the console 29 | console.error(error); 30 | return Observable.throw(error.json().error || 'Server error'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core'; 2 | import { 3 | RouteConfig, 4 | ROUTER_DIRECTIVES 5 | } from 'angular2/router'; 6 | import {HTTP_PROVIDERS} from 'angular2/http'; 7 | 8 | import {EmployeeListComponent} from './components/list.component'; 9 | import {EmployeeFormComponent} from './components/employee-form.component'; 10 | import {EmployeeDetailComponent} from './components/employee-detail.component'; 11 | import {EmployeeEditFormComponent} from './components/employee-edit-form.component'; 12 | 13 | @Component({ 14 | selector: 'my-app', 15 | templateUrl: 'src/pages/app.component.html', 16 | styleUrls: ['src/assets/stylesheets/style.css'], 17 | directives: [ 18 | ROUTER_DIRECTIVES 19 | ], 20 | providers: [HTTP_PROVIDERS] 21 | }) 22 | 23 | @RouteConfig([ 24 | { 25 | path: '/employee', 26 | name: 'EmployeeList', 27 | component: EmployeeListComponent 28 | }, 29 | { 30 | path: '/employee/new', 31 | name: 'NewEmployee', 32 | component: EmployeeFormComponent 33 | }, 34 | { 35 | path: '/employee/:id', 36 | name: 'EmployeeDetail', 37 | component: EmployeeDetailComponent 38 | }, 39 | { 40 | path: '/employee/:id/edit', 41 | name: 'EditEmployee', 42 | component: EmployeeEditFormComponent 43 | } 44 | ]) 45 | 46 | export class AppComponent {} 47 | -------------------------------------------------------------------------------- /src/components/employee-edit-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from 'angular2/core'; 2 | import { RouteParams, Router } from 'angular2/router'; 3 | 4 | import { Employee } from '../models/employee'; 5 | import { EmployeeDetailServiceComponent } from '../services/employee-detail-service.component'; 6 | import { EmployeeEditFormServiceComponent } from '../services/employee-edit-form-service.component'; 7 | 8 | @Component({ 9 | selector: 'employee-edit-form', 10 | templateUrl: 'src/pages/employee-edit-form.component.html', 11 | providers: [ 12 | EmployeeDetailServiceComponent, 13 | EmployeeEditFormServiceComponent 14 | ] 15 | }) 16 | 17 | export class EmployeeEditFormComponent implements OnInit { 18 | public currentEmployee: Employee; 19 | public errorMessage: string; 20 | 21 | constructor( 22 | private _router: Router, 23 | private _routeParams: RouteParams, 24 | private _detailService: EmployeeDetailServiceComponent, 25 | private _editService: EmployeeEditFormServiceComponent 26 | ){} 27 | 28 | ngOnInit() { 29 | let id = parseInt(this._routeParams.get('id')); 30 | this._detailService.getEmployee(id).subscribe( 31 | employee => this.currentEmployee = employee 32 | ); 33 | } 34 | 35 | editEmployee() { 36 | this._editService.editEmployee(this.currentEmployee) 37 | .subscribe( 38 | employee => this.currentEmployee = employee, 39 | error => this.errorMessage = error, 40 | () => this._router.navigate(['EmployeeDetail', {id: this.currentEmployee.id}]) 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2", 3 | "version": "1.0.0", 4 | "description": "Angular 2 testing with Karma, Jasmine and Istanbul", 5 | "main": "index.js", 6 | "scripts": { 7 | "postinstall": "npm run typings", 8 | "typings": "typings install", 9 | "lite": "lite-server", 10 | "start": "concurrently \"tsc -w -p src/ \" \"npm run lite .\"", 11 | "build": "rm -rf dist && tsc -p src", 12 | "pretest": "npm run build", 13 | "test": "karma start karma.conf.js", 14 | "posttest": "node_modules/.bin/remap-istanbul -i coverage/coverage-final.json -o coverage -t html" 15 | }, 16 | "author": "Abhinav Mishra ", 17 | "license": "MIT", 18 | "dependencies": { 19 | "angular2": "2.0.0-beta.13", 20 | "bootstrap": "^3.3.6", 21 | "es6-promise": "3.0.2", 22 | "es6-shim": "0.35.0", 23 | "reflect-metadata": "0.1.2", 24 | "rxjs": "5.0.0-beta.2", 25 | "zone.js": "0.6.6" 26 | }, 27 | "devDependencies": { 28 | "concurrently": "^2.0.0", 29 | "lite-server": "^2.2.0", 30 | "jasmine-core": "2.4.1", 31 | "karma": "0.13.19", 32 | "karma-chrome-launcher": "0.2.2", 33 | "karma-coverage": "0.5.3", 34 | "karma-jasmine": "0.3.6", 35 | "remap-istanbul": "0.5.1", 36 | "systemjs": "0.19.17", 37 | "typescript": "1.7.5", 38 | "typings": "0.6.8" 39 | }, 40 | "repository": { 41 | "type": "git", 42 | "url": "git+https://github.com/abhinavmsra/angular2.git" 43 | }, 44 | "keywords": [ 45 | "angular2", 46 | "karma", 47 | "jasmine", 48 | "istanbul", 49 | "unit-testing", 50 | "typescript" 51 | ], 52 | "bugs": { 53 | "url": "https://github.com/abhinavmsra/angular2/issues" 54 | }, 55 | "homepage": "https://github.com/abhinavmsra/angular2#readme" 56 | } 57 | -------------------------------------------------------------------------------- /src/components/employee-detail.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Component, OnInit } from 'angular2/core'; 4 | import { RouteParams, Router, ROUTER_DIRECTIVES } from 'angular2/router'; 5 | 6 | import { EmployeeEditFormComponent } from './employee-edit-form.component'; 7 | import { EmployeeDetailServiceComponent } from '../services/employee-detail-service.component'; 8 | import { EmployeeDeleteServiceComponent } from '../services/employee-delete-service.component'; 9 | 10 | @Component({ 11 | selector: 'employee-detail', 12 | templateUrl: 'src/pages/employee-detail.component.html', 13 | providers: [ 14 | EmployeeDetailServiceComponent, 15 | EmployeeDeleteServiceComponent 16 | ], 17 | directives: [ ROUTER_DIRECTIVES, EmployeeEditFormComponent ] 18 | }) 19 | 20 | export class EmployeeDetailComponent implements OnInit { 21 | public currentEmployee; 22 | public errorMessage: string; 23 | 24 | constructor( 25 | private _router: Router, 26 | private _routeParams: RouteParams, 27 | private _detailService: EmployeeDetailServiceComponent, 28 | private _deleteService: EmployeeDeleteServiceComponent 29 | ){} 30 | 31 | ngOnInit() { 32 | let id = parseInt(this._routeParams.get('id')); 33 | this._detailService.getEmployee(id).subscribe( 34 | employee => this.currentEmployee = employee, 35 | error => this.errorMessage = error 36 | ); 37 | } 38 | 39 | deleteHandler(id: number) { 40 | this._deleteService.deleteEmployee(id).subscribe( 41 | employee => this.currentEmployee = employee, 42 | errorMessage => this.errorMessage = errorMessage, 43 | () => this._router.navigate(['EmployeeList']) 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/services/employee-form-service.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | it, 5 | describe, 6 | expect, 7 | beforeEachProviders, 8 | inject 9 | } from "angular2/testing"; 10 | import { 11 | Response, 12 | XHRBackend, 13 | ResponseOptions, 14 | HTTP_PROVIDERS 15 | } from "angular2/http"; 16 | import {MockConnection, MockBackend} from "angular2/src/http/backends/mock_backend"; 17 | import {provide} from "angular2/core"; 18 | import 'rxjs/Rx'; 19 | 20 | import { EmployeeFormServiceComponent } from './employee-form-service.component'; 21 | 22 | describe('Employee Detail Service Tests', () => { 23 | beforeEachProviders(() => { 24 | return [ 25 | HTTP_PROVIDERS, 26 | provide(XHRBackend, {useClass: MockBackend}), 27 | EmployeeFormServiceComponent 28 | ] 29 | }); 30 | 31 | it('should create an employee', 32 | inject([XHRBackend, EmployeeFormServiceComponent], (backend, service) => { 33 | backend.connections.subscribe( 34 | (connection:MockConnection) => { 35 | var options = new ResponseOptions({ 36 | body: { 37 | "name": "Abhinav Mishra", 38 | "id": 1 39 | } 40 | }); 41 | 42 | var response = new Response(options); 43 | 44 | connection.mockRespond(response); 45 | } 46 | ); 47 | 48 | service.addEmployee('Abhinav Mishra').subscribe( 49 | (employee) => { 50 | expect(employee.name).toBe('Abhinav Mishra'); 51 | } 52 | ); 53 | }) 54 | ); 55 | }); 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Intro 2 | 3 | This repository is a basic CRUD Angular2 application, with an intention to learn Angular2 along with unit testing in it. 4 | 5 | ## Software Prerequisites 6 | 7 | In order to run this project, the following software is required 8 | 9 | ### Git 10 | 11 | See [Setting Up Git](https://help.github.com/articles/set-up-git/) from the GitHub guides. 12 | 13 | ### Node.js and npm 14 | 15 | Node.js and Node's package manager, npm, are used for installing dependencies, 16 | running the build steps, and running tests. 17 | 18 | 19 | ## Getting Started 20 | 21 | Begin by cloning the repository. 22 | 23 | Use npm to get dependencies: 24 | 25 | `npm install` 26 | 27 | Take a look at the `src` folder. All application and test code are placed here. Typings configuration are also placed in this folder in `tsconfig.json`. 28 | 29 | ### Build 30 | 31 | The build step invokes the TypeScript compiler to create ES5 javascript 32 | files and source maps from the `.ts` files. Run with: 33 | 34 | `npm run build` 35 | 36 | You can examine the configuration for the TypeScript compiler in `tsconfig.json`. 37 | The generated files are output in the `dist` folder which provides as a destination to fetch pure `Javascript` files and also provides good separation of `Typescript` and `Javascript` files. 38 | 39 | ### Serve 40 | 41 | The app uses `json-server` to simulate client-server communication. Follow the [GIT Repo](https://github.com/typicode/json-server) to configure it to run on port 3000. 42 | 43 | To see the app, run 44 | 45 | `npm run start` 46 | 47 | and navigate to `localhost:3001`. 48 | 49 | ### Test 50 | 51 | I used Karma with the `Jasmine` test framework to run unit tests. Try them with 52 | 53 | `npm run test` 54 | 55 | I have also used `karma-coverage` to generate the coverage report. The corresponding reports can be found under `coverage` directory. 56 | -------------------------------------------------------------------------------- /src/services/employee-delete-service.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import {it, describe, expect, beforeEachProviders, inject} from "angular2/testing"; 4 | import {Response, XHRBackend, ResponseOptions, HTTP_PROVIDERS} from "angular2/http"; 5 | import 'rxjs/Rx'; 6 | 7 | import { EmployeeDeleteServiceComponent } from './employee-delete-service.component'; 8 | import {MockConnection, MockBackend} from "angular2/src/http/backends/mock_backend"; 9 | import {provide} from "angular2/core"; 10 | 11 | describe('Employee Delete Service Tests', () => { 12 | beforeEachProviders(() => { 13 | return [ 14 | HTTP_PROVIDERS, 15 | provide(XHRBackend, {useClass: MockBackend}), 16 | EmployeeDeleteServiceComponent 17 | ] 18 | }); 19 | 20 | it('should delete an employee', 21 | inject([XHRBackend, EmployeeDeleteServiceComponent], (backend, service) => { 22 | backend.connections.subscribe( 23 | (connection:MockConnection) => { 24 | var options = new ResponseOptions({ 25 | body: { 26 | "name": "Abhinav Mishra", 27 | "id": 1 28 | } 29 | }); 30 | 31 | var response = new Response(options); 32 | 33 | connection.mockRespond(response); 34 | } 35 | ); 36 | 37 | service.deleteEmployee(1).subscribe( 38 | (employee) => { 39 | expect(employee.name).toBe('Abhinav Mishra'); 40 | } 41 | ); 42 | 43 | service.deleteEmployee(1).subscribe( 44 | (employee) => { 45 | expect(employee.id).toBe(1); 46 | } 47 | ); 48 | }) 49 | ); 50 | }); 51 | 52 | -------------------------------------------------------------------------------- /src/services/employee-list-service.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import {it, describe, expect, beforeEachProviders, inject} from "angular2/testing"; 4 | import {Response, XHRBackend, ResponseOptions, HTTP_PROVIDERS} from "angular2/http"; 5 | import 'rxjs/Rx'; 6 | 7 | import { EmployeeListServiceComponent } from './employee-list-service.component'; 8 | import {MockConnection, MockBackend} from "angular2/src/http/backends/mock_backend"; 9 | import {provide} from "angular2/core"; 10 | 11 | describe('Employee List Service Tests', () => { 12 | beforeEachProviders(() => { 13 | return [ 14 | HTTP_PROVIDERS, 15 | provide(XHRBackend, {useClass: MockBackend}), 16 | EmployeeListServiceComponent 17 | ] 18 | }); 19 | 20 | it('should return a list of employees', 21 | inject([XHRBackend, EmployeeListServiceComponent], (backend, service) => { 22 | backend.connections.subscribe( 23 | (connection:MockConnection) => { 24 | var options = new ResponseOptions({ 25 | body: [ 26 | { 27 | "name": "Abhinav Mishra", 28 | "id": 1 29 | } 30 | ] 31 | }); 32 | 33 | var response = new Response(options); 34 | 35 | connection.mockRespond(response); 36 | } 37 | ); 38 | 39 | service.getEmployees().subscribe( 40 | (employees) => { 41 | expect(employees[0].name).toBe('Abhinav Mishra'); 42 | } 43 | ); 44 | 45 | service.getEmployees().subscribe( 46 | (employees) => { 47 | expect(employees[0].id).toBe(1); 48 | } 49 | ); 50 | }) 51 | ); 52 | }); 53 | 54 | -------------------------------------------------------------------------------- /src/services/employee-detail-service.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | it, 5 | describe, 6 | expect, 7 | beforeEachProviders, 8 | inject 9 | } from "angular2/testing"; 10 | import { 11 | Response, 12 | XHRBackend, 13 | ResponseOptions, 14 | HTTP_PROVIDERS 15 | } from "angular2/http"; 16 | import {MockConnection, MockBackend} from "angular2/src/http/backends/mock_backend"; 17 | import {provide} from "angular2/core"; 18 | import 'rxjs/Rx'; 19 | 20 | import { EmployeeDetailServiceComponent } from './employee-detail-service.component'; 21 | 22 | describe('Employee Detail Service Tests', () => { 23 | beforeEachProviders(() => { 24 | return [ 25 | HTTP_PROVIDERS, 26 | provide(XHRBackend, {useClass: MockBackend}), 27 | EmployeeDetailServiceComponent 28 | ] 29 | }); 30 | 31 | it('should return details of employee', 32 | inject([XHRBackend, EmployeeDetailServiceComponent], (backend, service) => { 33 | backend.connections.subscribe( 34 | (connection:MockConnection) => { 35 | var options = new ResponseOptions({ 36 | body: { 37 | "name": "Abhinav Mishra", 38 | "id": 1 39 | } 40 | }); 41 | 42 | var response = new Response(options); 43 | 44 | connection.mockRespond(response); 45 | } 46 | ); 47 | 48 | service.getEmployee(1).subscribe( 49 | (employee) => { 50 | expect(employee.name).toBe('Abhinav Mishra'); 51 | } 52 | ); 53 | 54 | service.getEmployee(1).subscribe( 55 | (employee) => { 56 | expect(employee.id).toBe(1); 57 | } 58 | ); 59 | }) 60 | ); 61 | }); 62 | 63 | -------------------------------------------------------------------------------- /karma-test-shim.js: -------------------------------------------------------------------------------- 1 | // Tun on full stack traces in errors to help debugging 2 | Error.stackTraceLimit = Infinity; 3 | 4 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; 5 | 6 | // // Cancel Karma's synchronous start, 7 | // // we will call `__karma__.start()` later, once all the specs are loaded. 8 | __karma__.loaded = function() {}; 9 | 10 | System.config({ 11 | packages: { 12 | 'base/dist': { 13 | defaultExtension: false, 14 | format: 'cjs', 15 | map: Object.keys(window.__karma__.files).filter(onlyAppFiles).reduce(createPathRecords, {}) 16 | } 17 | } 18 | }); 19 | 20 | System.import('angular2/src/platform/browser/browser_adapter') 21 | .then(function(browser_adapter) { browser_adapter.BrowserDomAdapter.makeCurrent(); }) 22 | .then(function() { return Promise.all(resolveTestFiles()); }) 23 | .then(function() { __karma__.start(); }, function(error) { __karma__.error(error.stack || error); }); 24 | 25 | function createPathRecords(pathsMapping, appPath) { 26 | // creates local module name mapping to global path with karma's fingerprint in path, e.g.: 27 | // './vg-player/vg-player': 28 | // '/base/dist/vg-player/vg-player.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' 29 | var moduleName = './' + resolveKeyPathForMapping('base/dist/', appPath); 30 | moduleName = moduleName.replace(/\.js$/, ''); 31 | pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]; 32 | return pathsMapping; 33 | } 34 | 35 | function onlyAppFiles(filePath) { 36 | return /\/base\/dist\/(?!.*\.spec\.js$).*\.js$/.test(filePath); 37 | } 38 | 39 | function onlySpecFiles(path) { 40 | return /\.spec\.js$/.test(path); 41 | } 42 | 43 | function resolveTestFiles() { 44 | return Object.keys(window.__karma__.files) // All files served by Karma. 45 | .filter(onlySpecFiles) 46 | .map(function(moduleName) { 47 | // loads all spec files via their global module names (e.g. 48 | // 'base/dist/vg-player/vg-player.spec') 49 | return System.import(moduleName); 50 | }); 51 | } 52 | 53 | function resolveKeyPathForMapping(basePathWhereToStart, appPath) { 54 | var location = appPath.indexOf(basePathWhereToStart); 55 | if (location > -1) { 56 | return appPath.substring(basePathWhereToStart.length + 1); 57 | } else { 58 | return appPath; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | 4 | basePath: '.', 5 | 6 | frameworks: ['jasmine'], 7 | 8 | files: [ 9 | // paths loaded by Karma 10 | {pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', included: true, watched: true}, 11 | {pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: true}, 12 | {pattern: 'node_modules/rxjs/bundles/Rx.js', included: true, watched: true}, 13 | {pattern: 'node_modules/angular2/bundles/angular2.dev.js', included: true, watched: true}, 14 | {pattern: 'node_modules/angular2/bundles/testing.dev.js', included: true, watched: true}, 15 | {pattern: 'node_modules/angular2/bundles/http.dev.js', included: true, watched: true}, 16 | {pattern: 'node_modules/angular2/bundles/router.dev.js', included: true, watched: true}, 17 | {pattern: 'karma-test-shim.js', included: true, watched: true}, 18 | 19 | // paths loaded via module imports 20 | {pattern: 'dist/**/*.js', included: false, watched: true}, 21 | {pattern: 'src/pages/**/*.html', included: false, watched: true}, 22 | 23 | // paths to support debugging with source maps in dev tools 24 | {pattern: 'src/**/*.ts', included: false, watched: false}, 25 | {pattern: 'dist/**/*.js.map', included: false, watched: false} 26 | ], 27 | 28 | // proxied base paths 29 | proxies: { 30 | // required for component assests fetched by Angular's compiler 31 | '/src/': '/base/src/' 32 | }, 33 | 34 | port: 9876, 35 | 36 | logLevel: config.LOG_INFO, 37 | 38 | colors: true, 39 | 40 | autoWatch: true, 41 | 42 | browsers: ['Chrome'], 43 | 44 | // Karma plugins loaded 45 | plugins: [ 46 | 'karma-jasmine', 47 | 'karma-coverage', 48 | 'karma-chrome-launcher' 49 | ], 50 | 51 | // Coverage reporter generates the coverage 52 | reporters: ['progress', 'dots', 'coverage'], 53 | 54 | // Source files that you wanna generate coverage for. 55 | // Do not include tests or libraries (these files will be instrumented by Istanbul) 56 | preprocessors: { 57 | 'dist/**/!(*spec).js': ['coverage'] 58 | }, 59 | 60 | coverageReporter: { 61 | reporters:[ 62 | {type: 'json', subdir: '.', file: 'coverage-final.json'} 63 | ] 64 | }, 65 | 66 | singleRun: true 67 | }) 68 | }; 69 | -------------------------------------------------------------------------------- /src/components/employee-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | it, 5 | describe, 6 | expect, 7 | TestComponentBuilder, 8 | injectAsync, 9 | setBaseTestProviders, 10 | beforeEachProviders, 11 | resetBaseTestProviders 12 | } from "angular2/testing"; 13 | import { 14 | Component, 15 | provide, 16 | ApplicationRef 17 | } from "angular2/core"; 18 | import { 19 | TEST_BROWSER_PLATFORM_PROVIDERS, 20 | TEST_BROWSER_APPLICATION_PROVIDERS 21 | } from "angular2/platform/testing/browser"; 22 | import { 23 | ROUTER_DIRECTIVES, 24 | ROUTER_PROVIDERS, 25 | ROUTER_PRIMARY_COMPONENT, 26 | APP_BASE_HREF, 27 | Router, 28 | RouteParams, 29 | RouteRegistry 30 | } from 'angular2/router'; 31 | import {RootRouter} from "angular2/src/router/router"; 32 | import {SpyLocation} from "angular2/src/mock/location_mock"; 33 | import {Location} from "angular2/src/router/location/location"; 34 | import { 35 | XHRBackend, 36 | HTTP_PROVIDERS, 37 | Response, 38 | ResponseOptions 39 | } from "angular2/http"; 40 | import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref'; 41 | import { 42 | MockBackend, 43 | MockConnection 44 | } from "angular2/src/http/backends/mock_backend"; 45 | import { BrowserDomAdapter } from 'angular2/src/platform/browser/browser_adapter'; 46 | import 'rxjs/Rx'; 47 | 48 | import { AppComponent } from '../app.component'; 49 | import { EmployeeFormComponent } from './employee-form.component'; 50 | import { EmployeeFormServiceComponent } from '../services/employee-form-service.component'; 51 | 52 | 53 | class MockEmployeeFormServiceComponent {} 54 | 55 | @Component({ 56 | template: '', 57 | directives: [EmployeeFormComponent], 58 | providers: [ 59 | MockEmployeeFormServiceComponent 60 | ] 61 | }) 62 | class TestMyDetail {} 63 | 64 | 65 | describe('Employee Form Tests', () => { 66 | resetBaseTestProviders(); 67 | setBaseTestProviders( 68 | TEST_BROWSER_PLATFORM_PROVIDERS, 69 | TEST_BROWSER_APPLICATION_PROVIDERS 70 | ); 71 | beforeEachProviders(() => { 72 | return [ 73 | ROUTER_DIRECTIVES, 74 | ROUTER_PROVIDERS, 75 | HTTP_PROVIDERS, 76 | EmployeeFormServiceComponent, 77 | provide(XHRBackend, {useClass: MockBackend}), 78 | provide(APP_BASE_HREF, {useValue: '/'}), 79 | provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppComponent}), 80 | provide(ApplicationRef, {useClass: MockApplicationRef}), 81 | RouteRegistry, 82 | provide(Location, {useClass: SpyLocation}), 83 | provide(Router, {useClass: RootRouter}) 84 | ] 85 | }); 86 | 87 | it('Should display the list of employees', 88 | injectAsync([XHRBackend, TestComponentBuilder], (backend, tcb) => { 89 | backend.connections.subscribe( 90 | (connection:MockConnection) => { 91 | var options = new ResponseOptions({ 92 | body: { 93 | "id": 1, 94 | "name": "Roshan Shrestha" 95 | } 96 | }); 97 | 98 | var response = new Response(options); 99 | 100 | connection.mockRespond(response); 101 | } 102 | ); 103 | 104 | return tcb 105 | .createAsync(TestMyDetail) 106 | .then((fixture) => { 107 | fixture.detectChanges(); 108 | var compiled = fixture.nativeElement; 109 | 110 | expect(compiled.innerHTML).toContain('Employee Form'); 111 | }); 112 | }) 113 | ); 114 | }); 115 | -------------------------------------------------------------------------------- /src/components/employee-edit-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | it, 5 | describe, 6 | expect, 7 | TestComponentBuilder, 8 | injectAsync, 9 | setBaseTestProviders, 10 | beforeEachProviders, 11 | resetBaseTestProviders 12 | } from "angular2/testing"; 13 | import { 14 | Component, 15 | provide, 16 | ApplicationRef 17 | } from "angular2/core"; 18 | import { 19 | TEST_BROWSER_PLATFORM_PROVIDERS, 20 | TEST_BROWSER_APPLICATION_PROVIDERS 21 | } from "angular2/platform/testing/browser"; 22 | import { 23 | ROUTER_DIRECTIVES, 24 | ROUTER_PROVIDERS, 25 | ROUTER_PRIMARY_COMPONENT, 26 | APP_BASE_HREF, 27 | Router, 28 | RouteParams, 29 | RouteRegistry 30 | } from 'angular2/router'; 31 | import {RootRouter} from "angular2/src/router/router"; 32 | import {SpyLocation} from "angular2/src/mock/location_mock"; 33 | import {Location} from "angular2/src/router/location/location"; 34 | import { 35 | XHRBackend, 36 | HTTP_PROVIDERS, 37 | Response, 38 | ResponseOptions 39 | } from "angular2/http"; 40 | import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref'; 41 | import { 42 | MockBackend, 43 | MockConnection 44 | } from "angular2/src/http/backends/mock_backend"; 45 | import { BrowserDomAdapter } from 'angular2/src/platform/browser/browser_adapter'; 46 | import 'rxjs/Rx'; 47 | 48 | import { AppComponent } from '../app.component'; 49 | import { EmployeeEditFormComponent } from './employee-edit-form.component'; 50 | import { EmployeeDetailServiceComponent } from '../services/employee-detail-service.component'; 51 | import { EmployeeEditFormServiceComponent } from '../services/employee-edit-form-service.component'; 52 | 53 | 54 | class MockEmployeeDetailServiceComponent {} 55 | 56 | class MockEmployeeEditFormServiceComponent {} 57 | 58 | 59 | @Component({ 60 | template: '', 61 | directives: [EmployeeEditFormComponent] 62 | }) 63 | class TestMyEditForm{} 64 | 65 | 66 | describe('Employee Edit Form Tests', () => { 67 | resetBaseTestProviders(); 68 | setBaseTestProviders( 69 | TEST_BROWSER_PLATFORM_PROVIDERS, 70 | TEST_BROWSER_APPLICATION_PROVIDERS 71 | ); 72 | beforeEachProviders(() => { 73 | return [ 74 | ROUTER_DIRECTIVES, 75 | ROUTER_PROVIDERS, 76 | HTTP_PROVIDERS, 77 | EmployeeEditFormComponent, 78 | EmployeeDetailServiceComponent, 79 | EmployeeEditFormServiceComponent, 80 | provide(XHRBackend, {useClass: MockBackend}), 81 | provide(APP_BASE_HREF, {useValue: '/'}), 82 | provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppComponent}), 83 | provide(ApplicationRef, {useClass: MockApplicationRef}), 84 | RouteRegistry, 85 | provide(Location, {useClass: SpyLocation}), 86 | provide(Router, {useClass: RootRouter}), 87 | provide(RouteParams, { useValue: new RouteParams({ id: '1' }) }) 88 | ] 89 | }); 90 | 91 | it('Should display the edit form of employees', 92 | injectAsync([XHRBackend, TestComponentBuilder], (backend, tcb) => { 93 | backend.connections.subscribe( 94 | (connection:MockConnection) => { 95 | var options = new ResponseOptions({ 96 | body: { 97 | "id": 1, 98 | "name": "Roshan Shrestha" 99 | } 100 | }); 101 | 102 | var response = new Response(options); 103 | 104 | connection.mockRespond(response); 105 | } 106 | ); 107 | 108 | return tcb 109 | .createAsync(TestMyEditForm) 110 | .then((fixture) => { 111 | fixture.detectChanges(); 112 | var compiled = fixture.nativeElement; 113 | expect(compiled.innerHTML).toContain('Employee Edit Form'); 114 | }); 115 | }) 116 | ); 117 | }); 118 | -------------------------------------------------------------------------------- /src/components/employee-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | it, 5 | describe, 6 | expect, 7 | TestComponentBuilder, 8 | injectAsync, 9 | setBaseTestProviders, 10 | beforeEachProviders, 11 | resetBaseTestProviders 12 | } from "angular2/testing"; 13 | import { 14 | Component, 15 | provide, 16 | ApplicationRef 17 | } from "angular2/core"; 18 | import { 19 | TEST_BROWSER_PLATFORM_PROVIDERS, 20 | TEST_BROWSER_APPLICATION_PROVIDERS 21 | } from "angular2/platform/testing/browser"; 22 | import { 23 | ROUTER_DIRECTIVES, 24 | ROUTER_PROVIDERS, 25 | ROUTER_PRIMARY_COMPONENT, 26 | APP_BASE_HREF, 27 | Router, 28 | RouteParams, 29 | RouteRegistry 30 | } from 'angular2/router'; 31 | import {RootRouter} from "angular2/src/router/router"; 32 | import {SpyLocation} from "angular2/src/mock/location_mock"; 33 | import {Location} from "angular2/src/router/location/location"; 34 | import { 35 | XHRBackend, 36 | HTTP_PROVIDERS, 37 | Response, 38 | ResponseOptions 39 | } from "angular2/http"; 40 | import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref'; 41 | import { 42 | MockBackend, 43 | MockConnection 44 | } from "angular2/src/http/backends/mock_backend"; 45 | import { BrowserDomAdapter } from 'angular2/src/platform/browser/browser_adapter'; 46 | import 'rxjs/Rx'; 47 | 48 | import { AppComponent } from '../app.component'; 49 | import { EmployeeDetailComponent } from './employee-detail.component'; 50 | import { EmployeeDetailServiceComponent } from '../services/employee-detail-service.component'; 51 | import { EmployeeDeleteServiceComponent } from '../services/employee-delete-service.component'; 52 | import { EmployeeEditFormComponent } from './employee-edit-form.component'; 53 | 54 | 55 | class MockEmployeeDetailServiceComponent {} 56 | 57 | class MockEmployeeDeleteServiceComponent {} 58 | 59 | 60 | @Component({ 61 | template: '', 62 | directives: [EmployeeDetailComponent], 63 | providers: [ 64 | MockEmployeeDetailServiceComponent, 65 | MockEmployeeDeleteServiceComponent 66 | ] 67 | }) 68 | class TestMyDetail {} 69 | 70 | 71 | describe('Employee Detail Tests', () => { 72 | resetBaseTestProviders(); 73 | setBaseTestProviders( 74 | TEST_BROWSER_PLATFORM_PROVIDERS, 75 | TEST_BROWSER_APPLICATION_PROVIDERS 76 | ); 77 | beforeEachProviders(() => { 78 | return [ 79 | ROUTER_DIRECTIVES, 80 | ROUTER_PROVIDERS, 81 | HTTP_PROVIDERS, 82 | EmployeeDetailServiceComponent, 83 | EmployeeDeleteServiceComponent, 84 | provide(XHRBackend, {useClass: MockBackend}), 85 | provide(APP_BASE_HREF, {useValue: '/'}), 86 | provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppComponent}), 87 | provide(ApplicationRef, {useClass: MockApplicationRef}), 88 | RouteRegistry, 89 | provide(Location, {useClass: SpyLocation}), 90 | provide(Router, {useClass: RootRouter}), 91 | provide(RouteParams, { useValue: new RouteParams({ id: '1' }) }) 92 | ] 93 | }); 94 | 95 | it('Should display the list of employees', 96 | injectAsync([XHRBackend, TestComponentBuilder], (backend, tcb) => { 97 | backend.connections.subscribe( 98 | (connection:MockConnection) => { 99 | var options = new ResponseOptions({ 100 | body: { 101 | "id": 1, 102 | "name": "Roshan Shrestha" 103 | } 104 | }); 105 | 106 | var response = new Response(options); 107 | 108 | connection.mockRespond(response); 109 | } 110 | ); 111 | 112 | return tcb 113 | .createAsync(TestMyDetail) 114 | .then((fixture) => { 115 | fixture.detectChanges(); 116 | var compiled = fixture.nativeElement; 117 | expect(compiled.innerHTML).toContain('Roshan Shrestha'); 118 | 119 | var src = (new BrowserDomAdapter()).getProperty(compiled.querySelector('a'), 'href'); 120 | 121 | // Employee link expectation 122 | expect(src).toBe('http://localhost:9876/employee/1/edit'); 123 | }); 124 | }) 125 | ); 126 | }); 127 | -------------------------------------------------------------------------------- /src/components/list.component.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | it, 5 | describe, 6 | expect, 7 | TestComponentBuilder, 8 | injectAsync, 9 | setBaseTestProviders, 10 | beforeEachProviders, 11 | resetBaseTestProviders 12 | } from "angular2/testing"; 13 | import { 14 | Component, 15 | provide, 16 | ApplicationRef 17 | } from "angular2/core"; 18 | import { 19 | TEST_BROWSER_PLATFORM_PROVIDERS, 20 | TEST_BROWSER_APPLICATION_PROVIDERS 21 | } from "angular2/platform/testing/browser"; 22 | import { 23 | ROUTER_DIRECTIVES, 24 | ROUTER_PROVIDERS, 25 | ROUTER_PRIMARY_COMPONENT, 26 | APP_BASE_HREF, 27 | Router, 28 | RouteRegistry 29 | } from 'angular2/router'; 30 | import {RootRouter} from "angular2/src/router/router"; 31 | import {SpyLocation} from "angular2/src/mock/location_mock"; 32 | import {Location} from "angular2/src/router/location/location"; 33 | import { 34 | XHRBackend, 35 | HTTP_PROVIDERS, 36 | Response, 37 | ResponseOptions 38 | } from "angular2/http"; 39 | import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref'; 40 | import { 41 | MockBackend, 42 | MockConnection 43 | } from "angular2/src/http/backends/mock_backend"; 44 | import { BrowserDomAdapter } from 'angular2/src/platform/browser/browser_adapter'; 45 | import 'rxjs/Rx'; 46 | 47 | import { AppComponent } from '../app.component'; 48 | import { EmployeeListComponent } from './list.component'; 49 | import { EmployeeListServiceComponent } from '../services/employee-list-service.component'; 50 | 51 | class MockEmployeeListServiceComponent {} 52 | 53 | @Component({ 54 | template: '', 55 | directives: [EmployeeListComponent], 56 | providers: [MockEmployeeListServiceComponent] 57 | }) 58 | class TestMyList {} 59 | 60 | 61 | describe('Employee List Tests', () => { 62 | resetBaseTestProviders(); 63 | setBaseTestProviders( 64 | TEST_BROWSER_PLATFORM_PROVIDERS, 65 | TEST_BROWSER_APPLICATION_PROVIDERS 66 | ); 67 | //resetBaseTestProviders(); 68 | beforeEachProviders(() => { 69 | return [ 70 | ROUTER_DIRECTIVES, 71 | ROUTER_PROVIDERS, 72 | HTTP_PROVIDERS, 73 | EmployeeListServiceComponent, 74 | provide(XHRBackend, {useClass: MockBackend}), 75 | provide(APP_BASE_HREF, {useValue: '/'}), 76 | provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppComponent}), 77 | provide(ApplicationRef, {useClass: MockApplicationRef}), 78 | RouteRegistry, 79 | provide(Location, {useClass: SpyLocation}), 80 | provide(Router, {useClass: RootRouter}) 81 | ] 82 | }); 83 | 84 | it('Should display the list of employees', 85 | injectAsync([XHRBackend, TestComponentBuilder], (backend, tcb) => { 86 | backend.connections.subscribe( 87 | (connection:MockConnection) => { 88 | var options = new ResponseOptions({ 89 | body: [ 90 | { 91 | "id": 1, 92 | "name": "Abhinav Mishra" 93 | }, 94 | { 95 | "id": 2, 96 | "name": "Roshan Shrestha" 97 | } 98 | ] 99 | }); 100 | 101 | var response = new Response(options); 102 | 103 | connection.mockRespond(response); 104 | } 105 | ); 106 | 107 | return tcb 108 | .createAsync(TestMyList) 109 | .then((fixture) => { 110 | fixture.detectChanges(); 111 | var compiled = fixture.nativeElement; 112 | 113 | var listCount = compiled.querySelectorAll('a').length; 114 | 115 | // Employee count expectation 116 | expect(listCount).toBe(2); 117 | 118 | // Employee name expectation 119 | expect(compiled.innerHTML).toContain('Abhinav Mishra'); 120 | 121 | var src = (new BrowserDomAdapter()).getProperty(compiled.querySelector('a'), 'href'); 122 | 123 | // Employee link expectation 124 | expect(src).toBe('http://localhost:9876/employee/1'); 125 | }); 126 | }) 127 | ); 128 | }); 129 | --------------------------------------------------------------------------------