├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── DEVNOTES.md ├── README.md ├── TODO.md ├── app ├── app.module.ts ├── app.routes.ts ├── colors.styl ├── data │ ├── README.md │ ├── persons.json │ └── persons.ts ├── favicon.ico ├── global.styl ├── index.html ├── main.ts ├── models │ └── person.ts ├── routes │ ├── app │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.styl │ │ └── app.component.ts │ ├── route1 │ │ ├── detail │ │ │ ├── route1-detail.component.html │ │ │ ├── route1-detail.component.spec.ts │ │ │ ├── route1-detail.component.styl │ │ │ └── route1-detail.component.ts │ │ ├── list │ │ │ ├── route1-list.component.html │ │ │ ├── route1-list.component.spec.ts │ │ │ ├── route1-list.component.styl │ │ │ └── route1-list.component.ts │ │ ├── route1.component.html │ │ ├── route1.component.spec.ts │ │ ├── route1.component.styl │ │ └── route1.component.ts │ └── route2 │ │ ├── route2.component.html │ │ ├── route2.component.spec.ts │ │ ├── route2.component.styl │ │ └── route2.component.ts └── services │ └── person.service.ts ├── git-hook-pre-push.sh ├── gulp-core.js ├── gulp.config.js ├── gulp.png ├── gulp ├── build-hard.js ├── build-soft.js ├── low-level-coverage-tasks │ ├── coverage-clean.js │ ├── coverage-enforcer-hard.js │ ├── coverage-enforcer-soft.js │ ├── coverage-main.js │ ├── coverage-open.js │ ├── coverage-summary-long.js │ ├── coverage-summary-short.js │ └── enforcer-function.js ├── low-level-misc-tasks │ ├── build-clean.js │ ├── copy.js │ ├── eslint-hard.js │ ├── karma-build-hard.js │ ├── karma-build-soft.js │ ├── karma-watch.js │ ├── serve.js │ ├── styl-2-css.js │ ├── ts-2-js-hard.js │ ├── ts-2-js-soft.js │ ├── tslint-hard.js │ ├── tslint-reporter-function.js │ └── tslint-soft.js ├── test-npm-build.js ├── test-npm-start.js ├── test-npm-test.js └── watch.js ├── gulpfile.js ├── karma-test-shim.js ├── karma.conf.js ├── package.json ├── systemjs.config.js ├── tsconfig.json ├── tslint.json ├── typings.json ├── typings.sh └── update.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.js] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [app/**.ts] 13 | charset = utf-8 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [app/**.styl] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [app/**.html] 22 | indent_style = space 23 | indent_size = 2 24 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danday74/angular2-coverage/a72d6e6cf40b5827ae04b9dd15f12fd39391bc2a/.eslintignore -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "browser": true, 6 | "jasmine": true 7 | }, 8 | "extends": "eslint:recommended", 9 | "parserOptions": { 10 | "sourceType": "module" 11 | }, 12 | "rules": { 13 | "no-console": 0, 14 | "indent": [ 15 | "error", 16 | 2 17 | ], 18 | "linebreak-style": [ 19 | "error", 20 | "unix" 21 | ], 22 | "quotes": [ 23 | "error", 24 | "single" 25 | ], 26 | "semi": [ 27 | "error", 28 | "always" 29 | ] 30 | }, 31 | "globals": { 32 | "window": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /build/ 3 | /compiler/ 4 | /coverage/ 5 | /node_modules/ 6 | /typings/ 7 | npm-debug.log 8 | *.bak 9 | -------------------------------------------------------------------------------- /DEVNOTES.md: -------------------------------------------------------------------------------- 1 | # Third party libs 2 | 3 | To use third party libs you must follow these steps. 4 | 5 | (1) To install and save **lodash** run .. 6 | 7 | ``` 8 | npm i -S lodash 9 | ``` 10 | 11 | (2) To install and save **lodash** TypeScript definitions run .. 12 | 13 | ``` 14 | typings install dt~lodash --global --save 15 | ``` 16 | 17 | (3) Update **systemjs.config.js** to let SystemJS know where to find **lodash** 18 | 19 | ``` 20 | var map = { 21 | // ... 22 | 'lodash': 'node_modules/lodash/lodash.js' 23 | }; 24 | ``` 25 | 26 | (4) Update **karma.conf.js** to make **lodash** available to your karma test runner browser 27 | 28 | ``` 29 | {pattern: 'node_modules/lodash/**/*.js', included: false, watched: false} 30 | ``` 31 | 32 | (5) Then in your TypeScript .ts file ... 33 | 34 | ``` 35 | import * as _ from 'lodash'; 36 | ``` 37 | 38 | # Points of failure for build 39 | 40 | ## BUILD 41 | 42 | * eslint-hard: Linting JavaScript 43 | * tslint-hard: Linting TypeScript 44 | * ts-2-js-hard: Transpiling TypeScript to JavaScript 45 | * styl-2-css-hard: Transpiling Stylus to CSS 46 | * styl-2-css-stream-hard: Transpiling Stylus to CSS (streaming) 47 | 48 | ## UNIT TESTS 49 | 50 | * karma-build-hard: Running unit tests 51 | * coverage-enforcer-hard: PASSED thresholds 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angular2-coverage 2 | ----------------- 3 | ----------------- 4 | 5 | [![node version](https://img.shields.io/badge/node-6.2.2-brightgreen.svg)](https://nodejs.org) 6 | [![built with gulp](gulp.png)](http://gulpjs.com) 7 | 8 | An angular 2 gulp skeleton with unit testing and remapped coverage. 9 | 10 | **Updated to Angular 2.1.0** 11 | 12 | Install 13 | ------- 14 | 15 | **npm i** 16 | 17 | Commands 18 | -------- 19 | 20 | * **npm start -s** - Start dev server 21 | * **npm run build -s** - Kick off a build 22 | * **npm test -s** - Run test suite 23 | 24 | * **npm run checkupdates** - Check for package updates 25 | * **npm run typingsupdate** - Update typings (see [typings.sh](typings.sh)) 26 | 27 | Main features 28 | ------------- 29 | 30 | * unit testing 31 | * remapped coverage 32 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Gulp recipes 2 | 3 | See [Gulp recipes](https://github.com/gulpjs/gulp/tree/master/docs/recipes) 4 | 5 | * Incremental rebuilding, including operating on full file sets (TODO) 6 | * Only pass through changed files (TODO) 7 | * Sharing streams with stream factories (REVIEW) 8 | * Output both a minified and non-minified version (REVIEW) 9 | 10 | # Minify JS 11 | 12 | * Minify JS files generated by the 'ts-2-js' tasks (TODO) 13 | 14 | # Color updates 15 | 16 | * Updates to colors.styl only partially inject, some do not reflect until the server is restarted 17 | -------------------------------------------------------------------------------- /app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {HttpModule} from '@angular/http'; 3 | import {BrowserModule} from '@angular/platform-browser'; 4 | import {routing} from './app.routes'; 5 | import {AppComponent} from './routes/app/app.component'; 6 | import {Route1Component} from './routes/route1/route1.component'; 7 | import {Route1DetailComponent} from './routes/route1/detail/route1-detail.component'; 8 | import {Route1ListComponent} from './routes/route1/list/route1-list.component'; 9 | import {Route2Component} from './routes/route2/route2.component'; 10 | import {PersonService} from './services/person.service'; 11 | 12 | @NgModule({ 13 | imports: [BrowserModule, HttpModule, routing], // dependencies 14 | declarations: [AppComponent, Route1Component, Route1DetailComponent, Route1ListComponent, Route2Component], // components and directives 15 | bootstrap: [AppComponent], // root component 16 | providers: [PersonService] // services 17 | }) 18 | 19 | export class AppModule { 20 | } 21 | -------------------------------------------------------------------------------- /app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import {RouterModule, Routes} from '@angular/router'; 2 | import {Route1Component} from './routes/route1/route1.component'; 3 | import {Route1DetailComponent} from './routes/route1/detail/route1-detail.component'; 4 | import {Route1ListComponent} from './routes/route1/list/route1-list.component'; 5 | import {Route2Component} from './routes/route2/route2.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: 'route1', 10 | component: Route1Component, 11 | children: [ 12 | {path: ':id', component: Route1DetailComponent}, 13 | {path: '', component: Route1ListComponent} 14 | ] 15 | }, 16 | {path: 'route2', component: Route2Component}, 17 | { 18 | path: '', 19 | pathMatch: 'prefix', 20 | redirectTo: '/route1' 21 | } 22 | ]; 23 | 24 | export const routing = RouterModule.forRoot(routes); 25 | -------------------------------------------------------------------------------- /app/colors.styl: -------------------------------------------------------------------------------- 1 | myPrimaryColor = #FC4C02 2 | -------------------------------------------------------------------------------- /app/data/README.md: -------------------------------------------------------------------------------- 1 | The data folder contains up to two files for each API endpoint. 2 | 3 | (1) A TypeScript file 4 | 5 | This is imported by SystemJS during unit testing. The file: 6 | 7 | * contains mock unit test data. 8 | * should always be present. 9 | * would be present in a real application in the dev environment. 10 | 11 | (2) A JSON file 12 | 13 | This is requested over HTTP by the application. The file: 14 | 15 | * contains HTTP response data. 16 | * should be present if there is no backend API in place. 17 | * would not exist in a real application, one would use a backend API instead. 18 | -------------------------------------------------------------------------------- /app/data/persons.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Asa Israel", 5 | "age": 6, 6 | "hobby": "running" 7 | }, 8 | { 9 | "id": 10, 10 | "name": "Keziah Lewis", 11 | "age": 7, 12 | "hobby": "swimming" 13 | }, 14 | { 15 | "id": 20, 16 | "name": "Winnie Lewis", 17 | "age": 10, 18 | "hobby": "swimming" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /app/data/persons.ts: -------------------------------------------------------------------------------- 1 | let persons = [ 2 | { 3 | id: 1, 4 | name: 'Asa Israel', 5 | age: 6, 6 | hobby: 'running' 7 | }, 8 | { 9 | id: 10, 10 | name: 'Keziah Lewis', 11 | age: 7, 12 | hobby: 'swimming' 13 | }, 14 | { 15 | id: 20, 16 | name: 'Winnie Lewis', 17 | age: 10, 18 | hobby: 'swimming' 19 | } 20 | ]; 21 | 22 | export {persons}; 23 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danday74/angular2-coverage/a72d6e6cf40b5827ae04b9dd15f12fd39391bc2a/app/favicon.ico -------------------------------------------------------------------------------- /app/global.styl: -------------------------------------------------------------------------------- 1 | @import 'nib' 2 | @import 'colors' 3 | 4 | html 5 | height 100% 6 | 7 | body 8 | background linear-gradient(top, #A3B2B9, lighten(myPrimaryColor, 30)) 9 | color #FFF 10 | margin-top 1em 11 | 12 | a:link 13 | outline 0 14 | 15 | h1, h2, h3 16 | margin-top 0 17 | 18 | h1.loading 19 | color #000 20 | 21 | header, footer, section.route 22 | border 1px dashed #000 23 | padding 1em 24 | 25 | header 26 | background-color #999 27 | 28 | footer, header.sub 29 | background-color #666 30 | 31 | footer 32 | text-align center 33 | 34 | section.route 35 | background-color darken(myPrimaryColor, 25) 36 | 37 | .main-outlet 38 | background-color darken(myPrimaryColor, 28) 39 | min-height 250px 40 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular 2 Coverage 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 25 |
26 | 27 |

Loading...

28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /app/main.ts: -------------------------------------------------------------------------------- 1 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 2 | import {AppModule} from './app.module'; 3 | 4 | platformBrowserDynamic().bootstrapModule(AppModule); 5 | -------------------------------------------------------------------------------- /app/models/person.ts: -------------------------------------------------------------------------------- 1 | export class Person { 2 | // noinspection JSUnusedGlobalSymbols 3 | constructor(public id: number, public name: string, public age: number, public hobby: string) { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/routes/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |

My First Angular 2 App

3 | 7 |
8 |
9 | 10 |
11 | 14 | -------------------------------------------------------------------------------- /app/routes/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {APP_BASE_HREF} from '@angular/common'; 2 | import {async, ComponentFixture, TestBed} from '@angular/core/testing'; 3 | import {By} from '@angular/platform-browser'; 4 | import {AppComponent} from './app.component'; 5 | import {AppModule} from '../../app.module'; 6 | 7 | describe('app.component.ts', () => { 8 | 9 | let fix: ComponentFixture; 10 | let instance: AppComponent; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | imports: [AppModule], 15 | providers: [{provide: APP_BASE_HREF, useValue: '/'}] 16 | }).compileComponents() 17 | .then(() => { 18 | fix = TestBed.createComponent(AppComponent); 19 | instance = fix.componentInstance; 20 | }); 21 | })); 22 | 23 | it('should instantiate component', () => { 24 | expect(instance).toEqual(jasmine.any(AppComponent)); 25 | }); 26 | 27 | it('should have expected text', () => { 28 | let el = fix.debugElement.query(By.css('h1')).nativeElement; 29 | expect(el.textContent).toMatch(/angular 2 app/i); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /app/routes/app/app.component.styl: -------------------------------------------------------------------------------- 1 | @import 'colors' 2 | 3 | h1 4 | color myPrimaryColor 5 | text-shadow 2px 2px 3px #777 6 | 7 | a 8 | border-radius 3px 9 | color #FFF 10 | font-weight bold 11 | padding 0.2em 12 | text-decoration underline 13 | 14 | a.active 15 | background-color myPrimaryColor 16 | -------------------------------------------------------------------------------- /app/routes/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'my-app', 5 | templateUrl: 'build/routes/app/app.component.html', 6 | styleUrls: ['build/routes/app/app.component.css'] 7 | }) 8 | 9 | export class AppComponent { 10 | } 11 | -------------------------------------------------------------------------------- /app/routes/route1/detail/route1-detail.component.html: -------------------------------------------------------------------------------- 1 |
2 |

ROUTE 1 DETAIL VIEW

3 |
4 |
{{person | json}}
5 |
6 |
7 |
Can't find your man
8 |
9 |
10 | -------------------------------------------------------------------------------- /app/routes/route1/detail/route1-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {APP_BASE_HREF} from '@angular/common'; 2 | import {async, ComponentFixture, TestBed} from '@angular/core/testing'; 3 | import {By} from '@angular/platform-browser'; 4 | import {AppModule} from '../../../app.module'; 5 | import {persons} from '../../../data/persons'; 6 | import {Route1DetailComponent} from './route1-detail.component'; 7 | 8 | // HTTP mocking imports 9 | import {BaseRequestOptions, Http, Response, ResponseOptions} from '@angular/http'; 10 | import {MockBackend, MockConnection} from '@angular/http/testing'; 11 | 12 | describe('route1-detail.component.ts', () => { 13 | 14 | let fix: ComponentFixture; 15 | let instance: Route1DetailComponent; 16 | let injector: any; 17 | 18 | beforeEach(async(() => { 19 | TestBed.configureTestingModule({ 20 | imports: [AppModule], 21 | providers: [{provide: APP_BASE_HREF, useValue: '/'}, 22 | MockBackend, 23 | BaseRequestOptions, 24 | { 25 | provide: Http, 26 | useFactory: (pBackend: MockBackend, pOptions: BaseRequestOptions) => { 27 | return new Http(pBackend, pOptions); 28 | }, 29 | deps: [MockBackend, BaseRequestOptions] 30 | }] 31 | }).compileComponents() 32 | .then(() => { 33 | fix = TestBed.createComponent(Route1DetailComponent); 34 | instance = fix.componentInstance; 35 | injector = fix.debugElement.injector; 36 | }); 37 | })); 38 | 39 | it('should instantiate component', () => { 40 | expect(instance).toEqual(jasmine.any(Route1DetailComponent)); 41 | }); 42 | 43 | it('should have expected text', () => { 44 | let el = fix.debugElement.query(By.css('section.route1-detail')).nativeElement; 45 | expect(el.textContent).toMatch(/route 1 detail view/i); 46 | }); 47 | 48 | it('getPerson()', async(() => { 49 | let backend = injector.get(MockBackend); 50 | backend.connections.subscribe( 51 | (connection: MockConnection) => { 52 | connection.mockRespond(new Response( 53 | new ResponseOptions({ 54 | body: persons 55 | } 56 | ))); 57 | }); 58 | 59 | instance.getPerson(instance.DEFAULT_ID); 60 | expect(instance.person.name).toBe('Asa Israel'); 61 | })); 62 | 63 | it('getPerson() invalid ID', async(() => { 64 | const INVALID_ID = 9527; 65 | 66 | let backend = injector.get(MockBackend); 67 | backend.connections.subscribe( 68 | (connection: MockConnection) => { 69 | connection.mockRespond(new Response( 70 | new ResponseOptions({ 71 | body: persons 72 | } 73 | ))); 74 | }); 75 | 76 | instance.getPerson(INVALID_ID); 77 | expect(instance.person).toBeUndefined(); 78 | })); 79 | 80 | it('getPerson() failure', async(() => { 81 | let backend = injector.get(MockBackend); 82 | backend.connections.subscribe( 83 | (connection: MockConnection) => { 84 | connection.mockError(new Error('error')); 85 | }); 86 | 87 | instance.getPerson(instance.DEFAULT_ID); 88 | expect(instance.person).toBeUndefined(); 89 | })); 90 | 91 | }); 92 | -------------------------------------------------------------------------------- /app/routes/route1/detail/route1-detail.component.styl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danday74/angular2-coverage/a72d6e6cf40b5827ae04b9dd15f12fd39391bc2a/app/routes/route1/detail/route1-detail.component.styl -------------------------------------------------------------------------------- /app/routes/route1/detail/route1-detail.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ActivatedRoute} from '@angular/router'; 3 | import {Person} from '../../../models/person'; 4 | import {PersonService} from '../../../services/person.service'; 5 | import 'rxjs/add/operator/mergeMap'; 6 | import 'rxjs/add/operator/publish'; 7 | 8 | @Component({ 9 | templateUrl: 'build/routes/route1/detail/route1-detail.component.html', 10 | styleUrls: ['build/routes/route1/detail/route1-detail.component.css'] 11 | }) 12 | 13 | export class Route1DetailComponent implements OnInit { 14 | public DEFAULT_ID: number = 1; 15 | public person: Person; 16 | 17 | constructor(public route: ActivatedRoute, private personService: PersonService) { 18 | } 19 | 20 | /* istanbul ignore next */ 21 | // noinspection JSUnusedGlobalSymbols 22 | ngOnInit() { 23 | 24 | let paramsStream = this.route.params 25 | .map((params) => parseInt(params['id'], 10)) 26 | .map((id) => !isNaN(id) ? id : this.DEFAULT_ID); 27 | 28 | // We use flatMap instead of map to prevent this stream being a metastream - i.e. stream of streams 29 | let responseStream = paramsStream.flatMap((id) => { 30 | // noinspection UnnecessaryLocalVariableJS 31 | let personStream = this.personService.getPerson(id); 32 | return personStream; 33 | }).publish().refCount(); 34 | 35 | responseStream.subscribe((person: Person) => { 36 | this.person = person; 37 | }, 38 | (err) => console.error('oops', err) 39 | ); 40 | } 41 | 42 | // For testing purposes only since ngOnInit() is currently ignored 43 | // The correct RXJS approach is seen above 44 | getPerson(id: number): void { 45 | this.personService.getPerson(id) 46 | .subscribe( 47 | (person) => { 48 | this.person = person; 49 | }, 50 | (err) => console.error('oops', err)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/routes/route1/list/route1-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |

ROUTE 1 LIST VIEW

3 |
    4 |
  • 5 | {{person.name}} 6 |
  • 7 |
8 |
9 | -------------------------------------------------------------------------------- /app/routes/route1/list/route1-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {APP_BASE_HREF} from '@angular/common'; 2 | import {async, ComponentFixture, TestBed} from '@angular/core/testing'; 3 | import {By} from '@angular/platform-browser'; 4 | import {AppModule} from '../../../app.module'; 5 | import {persons} from '../../../data/persons'; 6 | import {Route1ListComponent} from './route1-list.component'; 7 | 8 | // HTTP mocking imports 9 | import {BaseRequestOptions, Http, Response, ResponseOptions} from '@angular/http'; 10 | import {MockBackend, MockConnection} from '@angular/http/testing'; 11 | 12 | describe('route1-list.component.ts', () => { 13 | 14 | let fix: ComponentFixture; 15 | let instance: Route1ListComponent; 16 | let injector: any; 17 | 18 | beforeEach(async(() => { 19 | TestBed.configureTestingModule({ 20 | imports: [AppModule], 21 | providers: [{provide: APP_BASE_HREF, useValue: '/'}, 22 | MockBackend, 23 | BaseRequestOptions, 24 | { 25 | provide: Http, 26 | useFactory: (pBackend: MockBackend, pOptions: BaseRequestOptions) => { 27 | return new Http(pBackend, pOptions); 28 | }, 29 | deps: [MockBackend, BaseRequestOptions] 30 | }] 31 | }).compileComponents() 32 | .then(() => { 33 | fix = TestBed.createComponent(Route1ListComponent); 34 | instance = fix.componentInstance; 35 | injector = fix.debugElement.injector; 36 | }); 37 | })); 38 | 39 | it('should instantiate component', () => { 40 | expect(instance).toEqual(jasmine.any(Route1ListComponent)); 41 | }); 42 | 43 | it('should have expected text', () => { 44 | let el = fix.debugElement.query(By.css('section.route1-list')).nativeElement; 45 | expect(el.textContent).toMatch(/route 1 list view/i); 46 | }); 47 | 48 | it('ngOnInit()', async(() => { 49 | let backend = injector.get(MockBackend); 50 | backend.connections.subscribe( 51 | (connection: MockConnection) => { 52 | connection.mockRespond(new Response( 53 | new ResponseOptions({ 54 | body: persons 55 | } 56 | ))); 57 | }); 58 | 59 | fix.detectChanges(); // Calls instance.ngOnInit() 60 | expect(instance.persons.length).toBe(3); 61 | })); 62 | 63 | it('ngOnInit() failure', async(() => { 64 | let backend = injector.get(MockBackend); 65 | backend.connections.subscribe( 66 | (connection: MockConnection) => { 67 | connection.mockError(new Error('error')); 68 | }); 69 | 70 | fix.detectChanges(); // Calls instance.ngOnInit() 71 | expect(instance.persons).toBeUndefined(); 72 | })); 73 | 74 | }); 75 | -------------------------------------------------------------------------------- /app/routes/route1/list/route1-list.component.styl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danday74/angular2-coverage/a72d6e6cf40b5827ae04b9dd15f12fd39391bc2a/app/routes/route1/list/route1-list.component.styl -------------------------------------------------------------------------------- /app/routes/route1/list/route1-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Person} from '../../../models/person'; 3 | import {PersonService} from '../../../services/person.service'; 4 | 5 | @Component({ 6 | templateUrl: 'build/routes/route1/list/route1-list.component.html', 7 | styleUrls: ['build/routes/route1/list/route1-list.component.css'] 8 | }) 9 | 10 | export class Route1ListComponent implements OnInit { 11 | // noinspection JSMismatchedCollectionQueryUpdate 12 | public persons: Person[]; 13 | 14 | constructor(private personService: PersonService) { 15 | console.log('Look at me in Chrome, sourcemaps are working!'); 16 | } 17 | 18 | // noinspection JSUnusedGlobalSymbols 19 | ngOnInit() { 20 | this.personService.getPersons() 21 | .subscribe( 22 | (persons) => { 23 | this.persons = persons; 24 | }, 25 | (err) => console.error('oops', err)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/routes/route1/route1.component.html: -------------------------------------------------------------------------------- 1 |
2 | Route 1 Header 3 |
4 | 5 | -------------------------------------------------------------------------------- /app/routes/route1/route1.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {APP_BASE_HREF} from '@angular/common'; 2 | import {async, ComponentFixture, TestBed} from '@angular/core/testing'; 3 | import {By} from '@angular/platform-browser'; 4 | import {AppModule} from '../../app.module'; 5 | import {Route1Component} from './route1.component'; 6 | 7 | describe('route1.component.ts', () => { 8 | 9 | let fix: ComponentFixture; 10 | let instance: Route1Component; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | imports: [AppModule], 15 | providers: [{provide: APP_BASE_HREF, useValue: '/'}] 16 | }).compileComponents() 17 | .then(() => { 18 | fix = TestBed.createComponent(Route1Component); 19 | instance = fix.componentInstance; 20 | }); 21 | })); 22 | 23 | it('should instantiate component', () => { 24 | expect(instance).toEqual(jasmine.any(Route1Component)); 25 | }); 26 | 27 | it('should have expected text', () => { 28 | let el = fix.debugElement.query(By.css('header.sub')).nativeElement; 29 | expect(el.textContent).toMatch(/route 1 header/i); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /app/routes/route1/route1.component.styl: -------------------------------------------------------------------------------- 1 | header 2 | font-weight bold 3 | text-shadow 2px 2px 3px #333 4 | -------------------------------------------------------------------------------- /app/routes/route1/route1.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | templateUrl: 'build/routes/route1/route1.component.html', 5 | styleUrls: ['build/routes/route1/route1.component.css'] 6 | }) 7 | 8 | export class Route1Component { 9 | } 10 | -------------------------------------------------------------------------------- /app/routes/route2/route2.component.html: -------------------------------------------------------------------------------- 1 |
2 |

ROUTE 2 VIEW

3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /app/routes/route2/route2.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {APP_BASE_HREF} from '@angular/common'; 2 | import {async, ComponentFixture, TestBed} from '@angular/core/testing'; 3 | import {Router} from '@angular/router'; 4 | import {AppModule} from '../../app.module'; 5 | import {Route2Component} from './route2.component'; 6 | 7 | describe('route2.component.ts', () => { 8 | 9 | let fix: ComponentFixture; 10 | let instance: Route2Component; 11 | let injector: any; 12 | 13 | beforeEach(async(() => { 14 | TestBed.configureTestingModule({ 15 | imports: [AppModule], 16 | providers: [{provide: APP_BASE_HREF, useValue: '/'}] 17 | }).compileComponents() 18 | .then(() => { 19 | fix = TestBed.createComponent(Route2Component); 20 | instance = fix.componentInstance; 21 | injector = fix.debugElement.injector; 22 | }); 23 | })); 24 | 25 | it('should instantiate component', () => { 26 | expect(instance).toEqual(jasmine.any(Route2Component)); 27 | }); 28 | 29 | it('should allow lodash access', () => { 30 | expect(instance.numArray).toEqual([3, 6, 9]); 31 | }); 32 | 33 | it('goToRoute1()', () => { 34 | let router = injector.get(Router); 35 | router.navigate = jasmine.createSpy('navigate'); 36 | instance.goToRoute1(); 37 | expect(router.navigate).toHaveBeenCalledWith(['/route1']); 38 | }); 39 | 40 | it('goToRoute1(id: number)', () => { 41 | let router = injector.get(Router); 42 | router.navigate = jasmine.createSpy('navigate'); 43 | instance.goToRoute1(10); 44 | expect(router.navigate).toHaveBeenCalledWith(['/route1', 10]); 45 | }); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /app/routes/route2/route2.component.styl: -------------------------------------------------------------------------------- 1 | .row 2 | text-align center 3 | 4 | button 5 | color #333 6 | font-weight bold 7 | padding 0.3em 8 | -------------------------------------------------------------------------------- /app/routes/route2/route2.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | import * as _ from 'lodash'; 4 | 5 | @Component({ 6 | templateUrl: 'build/routes/route2/route2.component.html', 7 | styleUrls: ['build/routes/route2/route2.component.css'] 8 | }) 9 | 10 | export class Route2Component { 11 | public numArray: number[]; 12 | 13 | constructor(private router: Router) { 14 | // numArray is an array of numbers and thus type can be inferred 15 | this.numArray = _.map([1, 2, 3], (n) => { 16 | return n * 3; 17 | }); 18 | } 19 | 20 | goToRoute1(id?: number): void { 21 | if (id == null) { 22 | this.router.navigate(['/route1']); 23 | } else { 24 | this.router.navigate(['/route1', id]); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/services/person.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Http, Response} from '@angular/http'; 3 | import {Person} from '../models/person'; 4 | import 'rxjs/add/operator/catch'; 5 | import 'rxjs/add/operator/map'; 6 | import {Observable} from 'rxjs/Observable'; 7 | 8 | @Injectable() 9 | export class PersonService { 10 | private personsUrl: string = 'app/data/persons.json'; 11 | 12 | static handleError(err: any): Observable { 13 | let errMsg = err.message; 14 | console.error(errMsg); 15 | return Observable.throw(errMsg); 16 | } 17 | 18 | constructor(private http: Http) { 19 | } 20 | 21 | getPersons(): Observable { 22 | return this.http.get(this.personsUrl) 23 | .map( 24 | (res: Response) => { 25 | return res.json(); 26 | } 27 | ) 28 | .catch(PersonService.handleError); 29 | } 30 | 31 | getPerson(id: number): Observable { 32 | return this.getPersons() 33 | .map((persons) => persons.filter((person) => person.id === id)[0]); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /git-hook-pre-push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This hook will PREVENT a GIT push where .. 4 | # * The build is passing AND a commit message starts with WIP 5 | # * The build is failing AND a commit message does not start with WIP 6 | # * The build is failing AND the branch is master or develop 7 | 8 | RED='\033[0;31m'; 9 | YELLOW='\033[0;33m'; 10 | GREEN='\033[0;32m'; 11 | NC='\033[0m'; # No color 12 | 13 | echo; 14 | echo -e "pre-push: Executing pre-push git hook"; 15 | echo -e "pre-push: Before pushing lets try building .."; 16 | echo; 17 | 18 | npm run build -s; 19 | if [ $? -eq 0 ]; then 20 | build=true; 21 | echo; 22 | echo -e "pre-push: Build passed"; 23 | else 24 | build=false; 25 | echo; 26 | echo -e "pre-push: Build failed"; 27 | fi 28 | 29 | remote="$1"; 30 | url="$2"; 31 | z40=0000000000000000000000000000000000000000; 32 | wip=false; 33 | branch=`git symbolic-ref --short HEAD`; 34 | prevent=false; 35 | 36 | while read local_ref local_sha remote_ref remote_sha; do 37 | if [ "$local_sha" = ${z40} ]; then 38 | # Handle delete 39 | : 40 | else 41 | if [ "$remote_sha" = ${z40} ]; then 42 | # New branch, examine all commits 43 | range="$local_sha"; 44 | else 45 | # Update to existing branch, examine new commits 46 | range="$remote_sha..$local_sha"; 47 | fi 48 | 49 | # Check for WIP commit 50 | commit=`git rev-list -n 1 --grep '^WIP' "$range"`; 51 | if [ -n "$commit" ]; then 52 | echo >&2 "pre-push: Found WIP commit"; 53 | wip=true; 54 | fi 55 | fi 56 | done 57 | 58 | echo -e "pre-push: SUMMARY: build=${build}, WIP=${wip}, branch=${branch}"; 59 | 60 | if [ "${build}" == "true" ] && [ "${wip}" == "true" ]; then 61 | echo -e "pre-push: ${RED}Push prevented .. The build is passing AND a commit message starts with WIP"; 62 | echo -e " TIP: Change your commit messages with .."; 63 | echo -e " git commit --amend -m \"new message\" OR git rebase -i (then use reword (r))${NC}"; 64 | prevent=true; 65 | fi 66 | 67 | if [ "${build}" == "false" ] && [ "${wip}" == "false" ]; then 68 | echo -e "pre-push: ${RED}Push prevented .. The build is failing AND a commit message does not start with WIP"; 69 | echo -e " TIP: Fix the build (preferred) OR change your commit messages with .."; 70 | echo -e " git commit --amend -m \"new message\" OR git rebase -i (then use reword (r))${NC}"; 71 | prevent=true; 72 | fi 73 | 74 | if [ "${build}" == "false" ] && [ "${branch}" == "master" ]; then 75 | echo -e "pre-push: ${RED}Push prevented .. The build is failing AND the branch is master${NC}"; 76 | prevent=true; 77 | fi 78 | 79 | if [ "${build}" == "false" ] && [ "${branch}" == "develop" ]; then 80 | echo -e "pre-push: ${RED}Push prevented .. The build is failing AND the branch is develop${NC}"; 81 | prevent=true; 82 | fi 83 | 84 | if [ "${prevent}" == "false" ] && [ "${wip}" == "true" ]; then 85 | echo -e "pre-push: ${YELLOW}Push permitted but it is against policy to push failing code - Please fix ASAP${NC}"; 86 | fi 87 | 88 | if [ "${prevent}" == "false" ] && [ "${wip}" == "false" ]; then 89 | echo -e "pre-push: ${GREEN}Push permitted${NC}"; 90 | fi 91 | 92 | test "${prevent}" == "false"; 93 | exitCode=$?; 94 | exit ${exitCode}; 95 | -------------------------------------------------------------------------------- /gulp-core.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const gulpif = require('gulp-if'); 3 | const intercept = require('gulp-intercept'); 4 | const sourcemaps = require('gulp-sourcemaps'); 5 | const browserSync = require('browser-sync').create(); 6 | const chalk = require('chalk'); 7 | const config = require('./gulp.config'); 8 | const path = require('path'); 9 | const runSequence = require('run-sequence'); 10 | const VALID_MODES = ['build', 'start', 'test']; 11 | const DEFAULT_MODE = VALID_MODES[1]; 12 | let modeCache; 13 | 14 | const getMode = () => { 15 | if (modeCache != null) return modeCache; 16 | modeCache = (process.argv.length > 2) ? process.argv[2] : DEFAULT_MODE; 17 | if (!VALID_MODES.includes(modeCache)) { 18 | modeCache = DEFAULT_MODE; 19 | } 20 | return modeCache; 21 | }; 22 | 23 | const mainHeading = (taskName, msg) => { 24 | console.log(chalk.bgWhite.black(`${taskName}: ${msg}`)); 25 | }; 26 | 27 | const subHeading = (taskName, msg) => { 28 | taskName = chalk.cyan(taskName); 29 | console.log(`${taskName}: ${msg}`); 30 | }; 31 | 32 | const link = (url) => { 33 | return chalk.bgCyan.black(url); 34 | }; 35 | 36 | const serious = (msg) => { 37 | return chalk.bgRed.white(msg); 38 | }; 39 | 40 | const watch = (msg) => { 41 | return chalk.bgBlue.white(msg); 42 | }; 43 | 44 | module.exports = { 45 | gulp, 46 | gulpif, 47 | intercept, 48 | sourcemaps, 49 | browserSync, 50 | chalk, 51 | config, 52 | path, 53 | runSequence, 54 | getMode, 55 | mainHeading, 56 | subHeading, 57 | link, 58 | serious, 59 | watch 60 | }; 61 | -------------------------------------------------------------------------------- /gulp.config.js: -------------------------------------------------------------------------------- 1 | const GLOBAL_STYL = 'app/global.styl'; 2 | const GLOBAL_THRESHOLD = 50; 3 | // noinspection JSUnusedGlobalSymbols 4 | const config = { 5 | browserSyncPort: 4000, 6 | apiPhp: 'http://localhost:7777', 7 | vmPhp: 'https://10.20.14.108:9100', 8 | files: { 9 | js: ['*.js', 'gulp/**/*.js'], 10 | ts: ['app/**/*.ts'], 11 | tsd: ['typings/**/*.d.ts'], 12 | styl: ['app/**/*.styl', '!' + GLOBAL_STYL], 13 | stylStream: [GLOBAL_STYL], 14 | copy: [ 15 | 'app/**/*.html', 16 | 'app/**/*.css', 17 | 'app/**/*.jpg', 18 | 'app/**/*.png', 19 | 'app/**/*.ico', 20 | 'app/**/*.eot', 21 | 'app/**/*.svg', 22 | 'app/**/*.ttf', 23 | 'app/**/*.woff', 24 | 'app/**/*.woff2', 25 | 'app/**/*.min.js' 26 | ] 27 | }, 28 | coverageThresholds: { 29 | statements: GLOBAL_THRESHOLD, 30 | branches: GLOBAL_THRESHOLD, 31 | functions: GLOBAL_THRESHOLD, 32 | lines: GLOBAL_THRESHOLD 33 | }, 34 | coverageOutput: 'coverage/coverage-js.json', 35 | coverageReports: { 36 | 'html': 'coverage/html', 37 | 'json-summary': 'coverage/coverage-ts-summary.json', 38 | 'json': 'coverage/coverage-ts.json', 39 | 'text-summary': 'coverage/coverage-ts-summary.txt', 40 | 'text': 'coverage/coverage-ts.txt' 41 | }, 42 | sourcemaps: { 43 | dir: '.', 44 | options: { 45 | includeContent: false, 46 | // Returns 'app' file relative to 'build' file 47 | // Used for locating the original file 48 | sourceRoot: () => { 49 | return '../app'; 50 | } 51 | } 52 | } 53 | }; 54 | 55 | module.exports = config; 56 | -------------------------------------------------------------------------------- /gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danday74/angular2-coverage/a72d6e6cf40b5827ae04b9dd15f12fd39391bc2a/gulp.png -------------------------------------------------------------------------------- /gulp/build-hard.js: -------------------------------------------------------------------------------- 1 | const TASK = 'build-hard'; 2 | const core = require('../gulp-core'); 3 | 4 | core.gulp.task(TASK, (done) => { 5 | core.mainHeading(TASK, 'Starting build'); 6 | core.runSequence( 7 | 'eslint-hard', 8 | 'build-clean', 9 | 'tslint-hard', 10 | 'ts-2-js-hard', 11 | 'styl-2-css-hard', 12 | 'styl-2-css-stream-hard', 13 | 'copy', 14 | done); 15 | }); 16 | -------------------------------------------------------------------------------- /gulp/build-soft.js: -------------------------------------------------------------------------------- 1 | const TASK = 'build-soft'; 2 | const core = require('../gulp-core'); 3 | 4 | core.gulp.task(TASK, (done) => { 5 | core.mainHeading(TASK, 'Starting build'); 6 | core.runSequence( 7 | 'eslint-hard', 8 | 'build-clean', 9 | 'tslint-soft', 10 | 'ts-2-js-soft', 11 | 'styl-2-css-soft', 12 | 'styl-2-css-stream-soft', 13 | 'copy', 14 | done); 15 | }); 16 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-clean.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-clean'; 2 | const core = require('../../gulp-core'); 3 | const del = require('del'); 4 | 5 | core.gulp.task(TASK, () => { 6 | core.subHeading(TASK, 'Deleting coverage folder'); 7 | return del(['coverage']); 8 | }); 9 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-enforcer-hard.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-enforcer-hard'; 2 | const core = require('../../gulp-core'); 3 | const enforcer = require('./enforcer-function'); 4 | 5 | core.gulp.task(TASK, () => { 6 | return core.gulp 7 | .src([core.config.coverageReports['json-summary']]) 8 | .pipe(core.intercept((file) => { 9 | let result = enforcer(file); 10 | core.subHeading(TASK, result.message); 11 | if (result.success === false) { 12 | process.exit(1); 13 | } 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-enforcer-soft.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-enforcer-soft'; 2 | const core = require('../../gulp-core'); 3 | const enforcer = require('./enforcer-function'); 4 | 5 | core.gulp.task(TASK, () => { 6 | return core.gulp 7 | .src([core.config.coverageReports['json-summary']]) 8 | .pipe(core.intercept((file) => { 9 | let result = enforcer(file); 10 | core.subHeading(TASK, result.message); 11 | })); 12 | }); 13 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-main.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-main'; 2 | const core = require('../../gulp-core'); 3 | const remapIstanbul = require('remap-istanbul/lib/gulpRemapIstanbul'); 4 | 5 | core.gulp.task(TASK, () => { 6 | core.subHeading(TASK, 'Generating remapped coverage reports'); 7 | return core.gulp 8 | .src(core.config.coverageOutput) 9 | .pipe(remapIstanbul({ 10 | reports: core.config.coverageReports 11 | })); 12 | }); 13 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-open.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-open'; 2 | const core = require('../../gulp-core'); 3 | 4 | core.gulp.task(TASK, () => { 5 | return core.gulp 6 | .src(core.config.coverageReports['html'] + '/index.html') 7 | .pipe(core.intercept((file) => { 8 | let link = core.link(`file:///${file.path.replace(/\\/g, '/')}`); 9 | core.subHeading(TASK, `CTRL CLICK to open ${link}`); 10 | })); 11 | }); 12 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-summary-long.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-summary-long'; 2 | const core = require('../../gulp-core'); 3 | 4 | core.gulp.task(TASK, () => { 5 | core.subHeading(TASK, '...'); 6 | return core.gulp 7 | .src([core.config.coverageReports['text'], core.config.coverageReports['text-summary']]) 8 | .pipe(core.intercept((file) => { 9 | console.log(file.contents.toString()); 10 | })); 11 | }); 12 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/coverage-summary-short.js: -------------------------------------------------------------------------------- 1 | const TASK = 'coverage-summary-short'; 2 | const core = require('../../gulp-core'); 3 | 4 | core.gulp.task(TASK, () => { 5 | core.subHeading(TASK, '...'); 6 | return core.gulp 7 | .src([core.config.coverageReports['text-summary']]) 8 | .pipe(core.intercept((file) => { 9 | console.log(file.contents.toString()); 10 | })); 11 | }); 12 | -------------------------------------------------------------------------------- /gulp/low-level-coverage-tasks/enforcer-function.js: -------------------------------------------------------------------------------- 1 | const core = require('../../gulp-core'); 2 | 3 | module.exports = (file) => { 4 | 5 | let thresholds = core.config.coverageThresholds; 6 | let failedThresholds = []; 7 | let total = JSON.parse(file.contents.toString()).total; 8 | let actuals = { 9 | statements: total.statements.pct, 10 | branches: total.branches.pct, 11 | functions: total.functions.pct, 12 | lines: total.lines.pct 13 | }; 14 | 15 | for (let key of Object.keys(actuals)) { 16 | if (actuals[key] < thresholds[key]) failedThresholds.push(key); 17 | } 18 | 19 | let strThresholds = ` of ${JSON.stringify(thresholds)}`; 20 | if (failedThresholds.length > 0) { 21 | return { 22 | message: core.chalk.red('FAILED thresholds') + strThresholds, 23 | success: false 24 | }; 25 | } else { 26 | return { 27 | message: core.chalk.green('PASSED thresholds') + strThresholds, 28 | success: true 29 | }; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/build-clean.js: -------------------------------------------------------------------------------- 1 | const TASK = 'build-clean'; 2 | const core = require('../../gulp-core'); 3 | const del = require('del'); 4 | 5 | core.gulp.task(TASK, () => { 6 | core.subHeading(TASK, 'Deleting build folder'); 7 | return del(['build']); 8 | }); 9 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/copy.js: -------------------------------------------------------------------------------- 1 | const TASK = 'copy'; 2 | const core = require('../../gulp-core'); 3 | 4 | core.gulp.task(TASK, () => { 5 | core.subHeading(TASK, 'Copying from \'app\' to \'build\''); 6 | return core.gulp 7 | .src(core.config.files.copy) 8 | .pipe(core.gulp.dest('build')); 9 | }); 10 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/eslint-hard.js: -------------------------------------------------------------------------------- 1 | const TASK = 'eslint-hard'; 2 | const core = require('../../gulp-core'); 3 | const eslint = require('gulp-eslint'); 4 | 5 | core.gulp.task(TASK, () => { 6 | core.subHeading(TASK, 'Linting JavaScript'); 7 | //noinspection JSCheckFunctionSignatures 8 | return core.gulp 9 | .src(core.config.files.js) 10 | .pipe(eslint()) 11 | .pipe(eslint.format('stylish', process.stdout)) 12 | .pipe(eslint.failAfterError()) 13 | .on('error', () => { 14 | process.exit(1); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/karma-build-hard.js: -------------------------------------------------------------------------------- 1 | const TASK = 'karma-build-hard'; 2 | const core = require('../../gulp-core'); 3 | const Server = require('karma').Server; 4 | 5 | core.gulp.task(TASK, (done) => { 6 | core.subHeading(TASK, 'Running unit tests'); 7 | new Server({ 8 | configFile: core.path.join(__dirname, '../../karma.conf.js'), 9 | reporters: ['mocha', 'coverage'] 10 | }, (exitCode) => { 11 | if (exitCode > 0) { 12 | process.exit(exitCode); 13 | } 14 | done(); 15 | }).start(); 16 | }); 17 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/karma-build-soft.js: -------------------------------------------------------------------------------- 1 | const TASK = 'karma-build-soft'; 2 | const core = require('../../gulp-core'); 3 | const Server = require('karma').Server; 4 | 5 | core.gulp.task(TASK, (done) => { 6 | core.subHeading(TASK, 'Running unit tests'); 7 | new Server({ 8 | configFile: core.path.join(__dirname, '../../karma.conf.js'), 9 | reporters: ['mocha', 'coverage'] 10 | }, () => { 11 | done(); 12 | }).start(); 13 | }); 14 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/karma-watch.js: -------------------------------------------------------------------------------- 1 | const TASK = 'karma-watch'; 2 | const core = require('../../gulp-core'); 3 | const Server = require('karma').Server; 4 | 5 | core.gulp.task(TASK, (done) => { 6 | core.subHeading(TASK, 'Running unit tests'); 7 | new Server({ 8 | configFile: core.path.join(__dirname, '../../karma.conf.js'), 9 | reporters: ['super-dots', 'coverage'] 10 | }, () => { 11 | console.log(); 12 | done(); 13 | }).start(); 14 | }); 15 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/serve.js: -------------------------------------------------------------------------------- 1 | const TASK = 'serve'; 2 | const core = require('../../gulp-core'); 3 | const rewrite = require('connect-modrewrite'); 4 | 5 | core.gulp.task(TASK, () => { 6 | core.browserSync.init({ 7 | port: core.config.browserSyncPort, 8 | server: { 9 | baseDir: ['build', '.'], 10 | middleware: [ 11 | rewrite([ 12 | '^/api/(.*)$ ' + core.config.apiPhp + '/$1 [P]', 13 | '^/vm/(.*)$ ' + core.config.vmPhp + '/$1 [P]', 14 | '^[^\\.]*$ /index.html [L]' 15 | ]) 16 | ] 17 | }, 18 | open: false 19 | }); 20 | core.browserSync.emitter.on('init', () => { 21 | // TODO: Should reload be here or inside timeout? 22 | core.browserSync.reload(); 23 | setTimeout(() => { 24 | let link = core.link(`http://localhost:${core.config.browserSyncPort}`); 25 | core.mainHeading(TASK, `CTRL CLICK to open ${link}`); 26 | }, 1000); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/styl-2-css.js: -------------------------------------------------------------------------------- 1 | const core = require('../../gulp-core'); 2 | const stylus = require('gulp-stylus'); 3 | const nib = require('nib'); 4 | const BASEMSG = 'Transpiling Stylus to CSS'; 5 | 6 | const taskFunc = (TASK) => { 7 | let isStream = TASK.includes('stream'); 8 | let msg = isStream ? `${BASEMSG} (streaming)` : BASEMSG; 9 | let srcFiles = isStream ? core.config.files.stylStream : core.config.files.styl; 10 | let isSoft = TASK.includes('soft'); 11 | 12 | core.subHeading(TASK, msg); 13 | let myStylus = stylus({ 14 | 'include css': true, 15 | // 'resolve url' : true, 16 | compress: true, 17 | use: nib(), 18 | include: 'app' 19 | }); 20 | 21 | return core.gulp 22 | .src(srcFiles) 23 | // TODO: Enforce sourcemaps for dev env only 24 | .pipe(core.gulpif(true, core.sourcemaps.init())) 25 | .pipe(myStylus) 26 | .on('error', (err) => { 27 | console.log(); 28 | console.log(err.message); 29 | if (isSoft) { 30 | if (isStream) { 31 | console.log(core.chalk.red(`Error whilst ${msg}`)); 32 | console.log(); 33 | } else { 34 | let serious1 = core.serious('Errors in a component\'s external stylesheets may cause unit test \'Failed to load CSS\' failures for that component'); 35 | console.log(serious1); 36 | let serious2 = core.serious('This is because errors prevent CSS file writing '); 37 | console.log(serious2); 38 | console.log(); 39 | } 40 | myStylus.emit('end'); 41 | } else { 42 | process.exit(1); 43 | } 44 | }) 45 | // TODO: Enforce sourcemaps for dev env only 46 | .pipe(core.gulpif(true, core.sourcemaps.write( 47 | core.config.sourcemaps.dir, 48 | core.config.sourcemaps.options))) 49 | .pipe(core.gulp.dest('build')) 50 | // Passing the match CSS object to browserSync.stream supports CSS injection and sourcemaps 51 | // However, the sourcemaps do not update on change without a manual refresh 52 | // Not passing the match CSS object to browserSync.stream fixes this but causes CSS injection failure 53 | .pipe(core.gulpif(isStream, core.browserSync.stream({match: '**/*.css'}))); 54 | }; 55 | 56 | const TASK1 = 'styl-2-css-soft'; 57 | const TASK2 = 'styl-2-css-stream-soft'; 58 | const TASK3 = 'styl-2-css-hard'; 59 | const TASK4 = 'styl-2-css-stream-hard'; 60 | 61 | core.gulp.task(TASK1, () => { 62 | return taskFunc(TASK1); 63 | }); 64 | 65 | core.gulp.task(TASK2, () => { 66 | return taskFunc(TASK2); 67 | }); 68 | 69 | core.gulp.task(TASK3, () => { 70 | return taskFunc(TASK3); 71 | }); 72 | 73 | core.gulp.task(TASK4, () => { 74 | return taskFunc(TASK4); 75 | }); 76 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/ts-2-js-hard.js: -------------------------------------------------------------------------------- 1 | const TASK = 'ts-2-js-hard'; 2 | const core = require('../../gulp-core'); 3 | const typescript = require('gulp-typescript'); 4 | let tscConfig = require('../../tsconfig.json'); 5 | delete tscConfig.compilerOptions.outDir; 6 | 7 | core.gulp.task(TASK, () => { 8 | core.subHeading(TASK, 'Transpiling TypeScript to JavaScript'); 9 | return core.gulp 10 | .src(core.config.files.ts.concat(core.config.files.tsd)) 11 | // TODO: Enforce sourcemaps for dev env only 12 | .pipe(core.gulpif(true, core.sourcemaps.init())) 13 | .pipe(typescript(tscConfig.compilerOptions)) 14 | .on('error', () => { 15 | process.exit(1); 16 | }) 17 | // TODO: Enforce sourcemaps for dev env only 18 | .pipe(core.gulpif(true, core.sourcemaps.write( 19 | core.config.sourcemaps.dir, 20 | core.config.sourcemaps.options))) 21 | .pipe(core.gulp.dest('build')); 22 | }); 23 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/ts-2-js-soft.js: -------------------------------------------------------------------------------- 1 | const TASK = 'ts-2-js-soft'; 2 | const core = require('../../gulp-core'); 3 | const typescript = require('gulp-typescript'); 4 | let tscConfig = require('../../tsconfig.json'); 5 | delete tscConfig.compilerOptions.outDir; 6 | 7 | core.gulp.task(TASK, () => { 8 | core.subHeading(TASK, 'Transpiling TypeScript to JavaScript'); 9 | return core.gulp 10 | .src(core.config.files.ts.concat(core.config.files.tsd)) 11 | // TODO: Enforce sourcemaps for dev env only 12 | .pipe(core.gulpif(true, core.sourcemaps.init())) 13 | .pipe(typescript(tscConfig.compilerOptions)) 14 | // TODO: Enforce sourcemaps for dev env only 15 | .pipe(core.gulpif(true, core.sourcemaps.write( 16 | core.config.sourcemaps.dir, 17 | core.config.sourcemaps.options))) 18 | .pipe(core.gulp.dest('build')); 19 | }); 20 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/tslint-hard.js: -------------------------------------------------------------------------------- 1 | const TASK = 'tslint-hard'; 2 | const core = require('../../gulp-core'); 3 | const tslint = require('gulp-tslint'); 4 | const reporter = require('./tslint-reporter-function'); 5 | 6 | core.gulp.task(TASK, () => { 7 | core.subHeading(TASK, 'Linting TypeScript'); 8 | return core.gulp 9 | .src(core.config.files.ts) 10 | .pipe(tslint()) 11 | .pipe(tslint.report(reporter, { 12 | emitError: true, 13 | summarizeFailureOutput: true 14 | })) 15 | .on('error', (err) => { 16 | console.log(err.message); 17 | process.exit(1); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/tslint-reporter-function.js: -------------------------------------------------------------------------------- 1 | const core = require('../../gulp-core'); 2 | const DIR = 'app'; 3 | 4 | module.exports = (errors, file) => { 5 | let temp = file.path.split(`${core.path.sep}${DIR}${core.path.sep}`)[1]; 6 | let filePath = `${DIR}/${temp}`; 7 | console.log(filePath); 8 | for (let err of errors) { 9 | let line = err.startPosition.line + 1; 10 | let char = err.startPosition.character + 1; 11 | line = (` ${line}`).slice(-3); 12 | char = (` ${char}`).slice(-3); 13 | let strPos = `${line}:${char}`; 14 | let strChalk = core.chalk.red('error'); 15 | let strErr = `${err.failure} (${err.ruleName})`; 16 | console.log(` ${strPos} ${strChalk} ${strErr}`); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /gulp/low-level-misc-tasks/tslint-soft.js: -------------------------------------------------------------------------------- 1 | const TASK = 'tslint-soft'; 2 | const core = require('../../gulp-core'); 3 | const tslint = require('gulp-tslint'); 4 | const reporter = require('./tslint-reporter-function'); 5 | 6 | core.gulp.task(TASK, () => { 7 | core.subHeading(TASK, 'Linting TypeScript'); 8 | return core.gulp 9 | .src(core.config.files.ts) 10 | .pipe(tslint()) 11 | .pipe(tslint.report(reporter, { 12 | emitError: false, 13 | summarizeFailureOutput: true 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /gulp/test-npm-build.js: -------------------------------------------------------------------------------- 1 | const TASK = 'test-npm-build'; 2 | const core = require('../gulp-core'); 3 | 4 | core.gulp.task(TASK, (done) => { 5 | core.mainHeading(TASK, 'Starting test run'); 6 | core.runSequence( 7 | 'coverage-clean', 8 | 'karma-build-hard', 9 | 'coverage-main', 10 | 'coverage-summary-long', 11 | 'coverage-open', 12 | 'coverage-enforcer-hard', 13 | done); 14 | }); 15 | -------------------------------------------------------------------------------- /gulp/test-npm-start.js: -------------------------------------------------------------------------------- 1 | const TASK = 'test-npm-start'; 2 | const core = require('../gulp-core'); 3 | 4 | core.gulp.task(TASK, (done) => { 5 | core.mainHeading(TASK, 'Starting test run'); 6 | core.runSequence( 7 | 'coverage-clean', 8 | 'karma-watch', // brief output 9 | 'coverage-main', 10 | 'coverage-summary-short', // brief summary 11 | 'coverage-open', 12 | 'coverage-enforcer-soft', 13 | done); 14 | }); 15 | -------------------------------------------------------------------------------- /gulp/test-npm-test.js: -------------------------------------------------------------------------------- 1 | const TASK = 'test-npm-test'; 2 | const core = require('../gulp-core'); 3 | 4 | core.gulp.task(TASK, (done) => { 5 | core.mainHeading(TASK, 'Starting test run'); 6 | core.runSequence( 7 | 'coverage-clean', 8 | 'karma-build-soft', 9 | 'coverage-main', 10 | 'coverage-summary-long', 11 | 'coverage-open', 12 | 'coverage-enforcer-soft', 13 | done); 14 | }); 15 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | const TASK = 'watch'; 2 | const core = require('../gulp-core'); 3 | 4 | core.gulp.task(TASK, () => { 5 | core.mainHeading(TASK, 'Watching files'); 6 | 7 | core.gulp.task('reload', (done) => { 8 | // TODO: Should reload be here or inside timeout? 9 | core.browserSync.reload(); 10 | setTimeout(() => { 11 | done(); 12 | }, 1000); 13 | }); 14 | 15 | core.gulp.task('xxwatchxx-copy', (done) => { 16 | console.log(core.watch('WATCH: copy')); 17 | core.runSequence( 18 | 'copy', 19 | 'reload', 20 | 'test-npm-start', 21 | done); 22 | }); 23 | 24 | core.gulp.task('xxwatchxx-ts-2-js', (done) => { 25 | console.log(core.watch('WATCH: ts-2-js')); 26 | core.runSequence( 27 | 'tslint-soft', 28 | 'ts-2-js-soft', 29 | 'reload', 30 | 'test-npm-start', 31 | done); 32 | }); 33 | 34 | core.gulp.task('xxwatchxx-styl-2-css', (done) => { 35 | console.log(core.watch('WATCH: styl-2-css')); 36 | core.runSequence( 37 | 'styl-2-css-soft', 38 | 'reload', 39 | 'test-npm-start', 40 | done); 41 | }); 42 | 43 | core.gulp.watch(core.config.files.copy, ['xxwatchxx-copy']); 44 | core.gulp.watch(core.config.files.ts, ['xxwatchxx-ts-2-js']); 45 | core.gulp.watch(core.config.files.styl, ['xxwatchxx-styl-2-css']); 46 | core.gulp.watch(core.config.files.stylStream, ['styl-2-css-stream-soft']); 47 | }); 48 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const core = require('./gulp-core'); 2 | const requireDir = require('require-dir'); 3 | requireDir('gulp', {recurse: true}); 4 | 5 | console.log('mode =', core.getMode()); 6 | 7 | core.gulp.task('build', (done) => { 8 | core.runSequence( 9 | 'build-hard', 10 | 'test-npm-build', 11 | done); 12 | }); 13 | 14 | core.gulp.task('start', (done) => { 15 | core.runSequence( 16 | 'build-soft', 17 | 'test-npm-start', 18 | ['serve', 'watch'], 19 | done); 20 | }); 21 | 22 | core.gulp.task('test', (done) => { 23 | core.runSequence( 24 | 'build-soft', 25 | 'test-npm-test', 26 | done); 27 | }); 28 | 29 | core.gulp.task('default', (done) => { 30 | core.runSequence( 31 | 'start', 32 | done); 33 | }); 34 | -------------------------------------------------------------------------------- /karma-test-shim.js: -------------------------------------------------------------------------------- 1 | /* global __karma__ */ 2 | Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. 3 | 4 | // Uncomment to get full stacktrace output. Sometimes helpful, usually not. 5 | // Error.stackTraceLimit = Infinity; // 6 | 7 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; 8 | 9 | var builtPath = '/base/build/'; 10 | 11 | __karma__.loaded = function () { 12 | }; 13 | 14 | function isJsFile(path) { 15 | return path.slice(-3) == '.js'; 16 | } 17 | 18 | function isSpecFile(path) { 19 | return /\.spec\.(.*\.)?js$/.test(path); 20 | } 21 | 22 | function isBuiltFile(path) { 23 | return isJsFile(path) && (path.substr(0, builtPath.length) == builtPath); 24 | } 25 | 26 | var allSpecFiles = Object.keys(window.__karma__.files) 27 | .filter(isSpecFile) 28 | .filter(isBuiltFile); 29 | 30 | // noinspection ES6ModulesDependencies, NodeModulesDependencies 31 | System.config({ 32 | baseURL: '/base', 33 | // Extend usual application package list with test folder 34 | packages: {'testing': {main: 'index.js', defaultExtension: 'js'}}, 35 | 36 | // Assume npm: is set in `paths` in systemjs.config 37 | // Map the angular testing umd bundles 38 | map: { 39 | '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', 40 | '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', 41 | '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', 42 | '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', 43 | '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', 44 | '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', 45 | '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', 46 | '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', 47 | }, 48 | }); 49 | 50 | System.import('systemjs.config.js') 51 | .then(initTestBed) 52 | .then(initTesting); 53 | 54 | function initTestBed() { 55 | // noinspection JSFileReferences 56 | return Promise.all([ 57 | System.import('@angular/core/testing'), 58 | System.import('@angular/platform-browser-dynamic/testing') 59 | ]) 60 | 61 | .then(function (providers) { 62 | var coreTesting = providers[0]; 63 | var browserTesting = providers[1]; 64 | 65 | coreTesting.TestBed.initTestEnvironment( 66 | browserTesting.BrowserDynamicTestingModule, 67 | browserTesting.platformBrowserDynamicTesting()); 68 | }); 69 | } 70 | 71 | // Import all spec files and start karma 72 | function initTesting() { 73 | return Promise.all( 74 | allSpecFiles.map(function (moduleName) { 75 | return System.import(moduleName); 76 | }) 77 | ) 78 | .then(__karma__.start, __karma__.error); 79 | } 80 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = (config) => { 2 | 3 | config.set({ 4 | basePath: '', 5 | frameworks: ['jasmine'], 6 | plugins: [ 7 | require('karma-jasmine'), 8 | require('karma-phantomjs-launcher'), 9 | require('karma-coverage'), 10 | require('karma-mocha-reporter'), 11 | require('karma-super-dots-reporter') 12 | ], 13 | 14 | files: [ 15 | // System.js for module loading 16 | 'node_modules/systemjs/dist/system.src.js', 17 | 18 | // Polyfills 19 | 'node_modules/core-js/client/shim.js', 20 | 'node_modules/reflect-metadata/Reflect.js', 21 | 22 | // zone.js 23 | 'node_modules/zone.js/dist/zone.js', 24 | 'node_modules/zone.js/dist/long-stack-trace-zone.js', 25 | 'node_modules/zone.js/dist/proxy.js', 26 | 'node_modules/zone.js/dist/sync-test.js', 27 | 'node_modules/zone.js/dist/jasmine-patch.js', 28 | 'node_modules/zone.js/dist/async-test.js', 29 | 'node_modules/zone.js/dist/fake-async-test.js', 30 | 31 | // RxJs 32 | {pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false}, 33 | {pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false}, 34 | 35 | // Paths loaded via module imports: 36 | // Angular itself 37 | {pattern: 'node_modules/@angular/**/*.js', included: false, watched: false}, 38 | {pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false}, 39 | {pattern: 'systemjs.config.js', included: false, watched: false}, 40 | 'karma-test-shim.js', 41 | 42 | // lodash 43 | {pattern: 'node_modules/lodash/**/*.js', included: false, watched: false}, 44 | 45 | // Transpiled application & spec code paths loaded via module imports 46 | {pattern: 'build/**/*.js', included: false, watched: true}, 47 | // Asset (HTML & CSS) paths loaded via Angular's component compiler 48 | // (these paths need to be rewritten, see proxies section) 49 | {pattern: 'build/**/*.html', included: false, watched: true}, 50 | {pattern: 'build/**/*.css', included: false, watched: true}, 51 | {pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: false, watched: false}, // PhantomJS2 (and possibly others) might require it 52 | // Paths for debugging with source maps in dev tools 53 | {pattern: 'app/**/*.ts', included: false, watched: false}, 54 | {pattern: 'build/**/*.js.map', included: false, watched: false} 55 | ], 56 | 57 | proxies: { 58 | '/build/': '/base/build/' 59 | }, 60 | exclude: [], 61 | preprocessors: { 62 | 'build/**/!(*spec).js': ['coverage'] 63 | }, 64 | 65 | reporters: ['mocha', 'coverage'], 66 | mochaReporter: {}, 67 | coverageReporter: { 68 | reporters: [ 69 | {type: 'json', subdir: '.', file: 'coverage-js.json'} 70 | ] 71 | }, 72 | 73 | client: { 74 | captureConsole: false 75 | }, 76 | 77 | port: 9876, 78 | colors: true, 79 | logLevel: config.LOG_INFO, 80 | browsers: ['PhantomJS'], 81 | singleRun: true, 82 | autoWatch: false 83 | }); 84 | }; 85 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-coverage", 3 | "version": "7.0.0", 4 | "private": true, 5 | "//": "dev'd on v6.2.2 prob works on lesser versions too", 6 | "engine": "node >= 6.2.2", 7 | "scripts": { 8 | "ncu": "ncu", 9 | "typings": "typings", 10 | "preinstall": "npm list -g gulp-cli || npm i -g gulp-cli", 11 | "postinstall": "typings install && test -d .git && cp git-hook-pre-push.sh .git/hooks/pre-push || true", 12 | "checkupdates": "ncu", 13 | "typingsupdate": "sh typings.sh", 14 | "build": "gulp build --silent", 15 | "start": "gulp start --silent", 16 | "test": "gulp test --silent" 17 | }, 18 | "dependencies": { 19 | "@angular/common": "^2.1.0", 20 | "@angular/compiler": "^2.1.0", 21 | "@angular/core": "^2.1.0", 22 | "@angular/forms": "^2.1.0", 23 | "@angular/http": "^2.1.0", 24 | "@angular/platform-browser": "^2.1.0", 25 | "@angular/platform-browser-dynamic": "^2.1.0", 26 | "@angular/router": "^3.1.0", 27 | "@angular/router-deprecated": "^2.0.0-rc.2", 28 | "bootstrap": "^3.3.7", 29 | "core-js": "^2.4.1", 30 | "lodash": "^4.16.4", 31 | "reflect-metadata": "^0.1.8", 32 | "rxjs": "5.0.0-beta.12", 33 | "systemjs": "^0.19.39", 34 | "zone.js": "^0.6.25" 35 | }, 36 | "devDependencies": { 37 | "browser-sync": "^2.17.5", 38 | "chalk": "^1.1.3", 39 | "connect-modrewrite": "^0.9.0", 40 | "del": "^2.2.2", 41 | "eslint": "^3.8.1", 42 | "gulp": "^3.9.1", 43 | "gulp-eslint": "^3.0.1", 44 | "gulp-if": "^2.0.1", 45 | "gulp-intercept": "^0.1.0", 46 | "gulp-sourcemaps": "^2.1.1", 47 | "gulp-stylus": "^2.5.0", 48 | "gulp-tslint": "^6.1.2", 49 | "gulp-typescript": "^3.0.2", 50 | "jasmine-core": "^2.5.2", 51 | "karma": "^1.3.0", 52 | "karma-coverage": "^1.1.1", 53 | "karma-jasmine": "^1.0.2", 54 | "karma-mocha-reporter": "^2.2.0", 55 | "karma-phantomjs-launcher": "^1.0.2", 56 | "karma-super-dots-reporter": "^0.1.0", 57 | "nib": "^1.1.2", 58 | "node-cmd": "^1.1.1", 59 | "npm-check-updates": "^2.8.5", 60 | "phantomjs-prebuilt": "^2.1.13", 61 | "remap-istanbul": "^0.7.0", 62 | "require-dir": "^0.3.1", 63 | "run-sequence": "^1.2.2", 64 | "tslint": "^3.15.1", 65 | "typings": "^1.4.0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular samples 3 | * Adjust as necessary for your application needs. 4 | */ 5 | (function () { 6 | var config = { 7 | paths: { 8 | // paths serve as alias 9 | 'npm:': 'node_modules/' 10 | }, 11 | // map tells the System loader where to look for things 12 | map: { 13 | // our app is within the app folder 14 | // app: 'app', 15 | app: 'build', 16 | 17 | // angular bundles 18 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 19 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 20 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 21 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 22 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 23 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 24 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 25 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 26 | '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', 27 | 28 | // other libraries 29 | 'rxjs': 'npm:rxjs', 30 | 'lodash': 'npm:lodash/lodash.js' 31 | }, 32 | 33 | // packages tells the System loader how to load when no filename and/or no extension 34 | packages: { 35 | app: {main: './main.js', defaultExtension: 'js'}, 36 | rxjs: {defaultExtension: 'js'} 37 | } 38 | }; 39 | // noinspection ES6ModulesDependencies, NodeModulesDependencies 40 | System.config(config); 41 | })(); 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": true, 11 | "suppressImplicitAnyIndexErrors": true, 12 | "outDir": "compiler" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "curly": true, 9 | "eofline": true, 10 | "forin": true, 11 | "indent": [ 12 | true, 13 | "spaces" 14 | ], 15 | "label-position": true, 16 | "label-undefined": true, 17 | "max-line-length": [ 18 | true, 19 | 140 20 | ], 21 | "member-access": false, 22 | "member-ordering": [ 23 | true, 24 | "static-before-instance", 25 | "variables-before-functions" 26 | ], 27 | "no-arg": true, 28 | "no-bitwise": true, 29 | "no-console": [ 30 | true, 31 | "debug", 32 | "info", 33 | "time", 34 | "timeEnd", 35 | "trace" 36 | ], 37 | "no-construct": true, 38 | "no-debugger": true, 39 | "no-duplicate-key": true, 40 | "no-duplicate-variable": true, 41 | "no-empty": false, 42 | "no-eval": true, 43 | "no-inferrable-types": true, 44 | "no-shadowed-variable": true, 45 | "no-string-literal": false, 46 | "no-switch-case-fall-through": true, 47 | "no-trailing-whitespace": false, 48 | "no-unused-expression": true, 49 | "no-unused-variable": true, 50 | "no-unreachable": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": false, 54 | "one-line": [ 55 | true, 56 | "check-open-brace", 57 | "check-catch", 58 | "check-else", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [ 62 | true, 63 | "single" 64 | ], 65 | "radix": true, 66 | "semicolon": [ 67 | true, 68 | "always" 69 | ], 70 | "triple-equals": [ 71 | true, 72 | "allow-null-check" 73 | ], 74 | "typedef-whitespace": [ 75 | true, 76 | { 77 | "call-signature": "nospace", 78 | "index-signature": "nospace", 79 | "parameter": "nospace", 80 | "property-declaration": "nospace", 81 | "variable-declaration": "nospace" 82 | } 83 | ], 84 | "variable-name": false, 85 | "whitespace": [ 86 | true, 87 | "check-branch", 88 | "check-decl", 89 | "check-operator", 90 | "check-separator" 91 | ] 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160914114559", 4 | "jasmine": "registry:dt/jasmine#2.5.0+20161003201800", 5 | "lodash": "registry:dt/lodash#4.14.0+20161004174455", 6 | "node": "registry:dt/node#6.0.0+20161010101523" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script updates typings and removes the following warning 4 | # typings WARN deprecated 6/2/2016: "registry:dt/core-js#0.0.0+20160317120654" is deprecated (updated, replaced or removed) 5 | # An entry should exist here for each entry in typings.json 6 | # This script assumes that the NodeJS module 'typings' is installed locally 7 | # I do not know how to revert changes so this script backs up typings.json 8 | 9 | echo "Backing up typings.json"; 10 | cp typings.json typings.json.bak &>/dev/null; 11 | 12 | echo "Updating typings.json"; 13 | npm run typings -- install dt~core-js --global --save 14 | npm run typings -- install dt~jasmine --global --save 15 | npm run typings -- install dt~lodash --global --save 16 | npm run typings -- install dt~node --global --save 17 | 18 | echo "Update complete"; 19 | -------------------------------------------------------------------------------- /update.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const cmd = require('node-cmd'); 3 | 4 | fs.readFile('./package.json', 'utf8', (err, data) => { 5 | let pkg = JSON.parse(data); 6 | for (let dep in pkg.dependencies) { 7 | console.log(`Updating dev package ${dep}`); 8 | cmd.run(`npm i -S ${dep}@latest`); // You may need sudo here 9 | } 10 | for (let devDep in pkg.devDependencies) { 11 | console.log(`Updating devDep package ${devDep}`); 12 | cmd.run(`npm i -SD ${devDep}@latest`); // You may need sudo here 13 | } 14 | console.log('Please wait, updates in progress'); 15 | }); 16 | --------------------------------------------------------------------------------