├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── index.html
├── karma-test-shim.js
├── karma.conf.js
├── package.json
├── src
├── comps
│ ├── my-list.spec.ts
│ └── my-list.ts
├── my-app.ts
├── pipes
│ ├── my-pipe.spec.ts
│ └── my-pipe.ts
├── services
│ ├── github-user.ts
│ ├── my-service.spec.ts
│ └── my-service.ts
└── tsconfig.json
└── typings.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | coverage
4 | dist
5 | typings
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | coverage
4 | src
5 | typings
6 | typings.json
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Raúl Jiménez
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular2-testing
2 |
3 | Install:
4 |
5 | ```
6 | npm install
7 | ```
8 |
9 | Run the project:
10 |
11 | ```
12 | npm start
13 | ```
14 |
15 | Check code coverage:
16 |
17 | ```
18 | npm run coverage
19 | ```
20 |
21 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Angular 2 Testing
6 |
7 |
8 |
9 |
10 |
11 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/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: 'karma-test-shim.js', included: true, watched: true},
17 |
18 | // paths loaded via module imports
19 | {pattern: 'dist/**/*.js', included: false, watched: true},
20 |
21 | // paths to support debugging with source maps in dev tools
22 | {pattern: 'src/**/*.ts', included: false, watched: false},
23 | {pattern: 'dist/**/*.js.map', included: false, watched: false}
24 | ],
25 |
26 | // proxied base paths
27 | proxies: {
28 | // required for component assests fetched by Angular's compiler
29 | '/src/': '/base/src/'
30 | },
31 |
32 | port: 9876,
33 |
34 | logLevel: config.LOG_INFO,
35 |
36 | colors: true,
37 |
38 | autoWatch: true,
39 |
40 | browsers: ['Chrome'],
41 |
42 | // Karma plugins loaded
43 | plugins: [
44 | 'karma-jasmine',
45 | 'karma-coverage',
46 | 'karma-chrome-launcher'
47 | ],
48 |
49 | // Coverage reporter generates the coverage
50 | reporters: ['progress', 'dots', 'coverage'],
51 |
52 | // Source files that you wanna generate coverage for.
53 | // Do not include tests or libraries (these files will be instrumented by Istanbul)
54 | preprocessors: {
55 | 'dist/**/!(*spec).js': ['coverage']
56 | },
57 |
58 | coverageReporter: {
59 | reporters:[
60 | {type: 'json', subdir: '.', file: 'coverage-final.json'}
61 | ]
62 | },
63 |
64 | singleRun: true
65 | })
66 | };
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular2-testing",
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 | "start": "npm run test && http-server -c-1 -o -p 8875 .",
10 | "build": "rm -rf dist && tsc -p src",
11 | "pretest": "npm run build",
12 | "test": "karma start karma.conf.js",
13 | "posttest": "node_modules/.bin/remap-istanbul -i coverage/coverage-final.json -o coverage -t html",
14 | "coverage": "http-server -c-1 -o -p 9875 ./coverage"
15 | },
16 | "author": "Raul Jimenez (http://twofuckingdevelopers.com/)",
17 | "license": "MIT",
18 | "dependencies": {
19 | "angular2": "2.0.0-beta.13",
20 | "es6-promise": "3.0.2",
21 | "es6-shim": "0.35.0",
22 | "reflect-metadata": "0.1.2",
23 | "rxjs": "5.0.0-beta.2",
24 | "zone.js": "0.6.6"
25 | },
26 | "devDependencies": {
27 | "http-server": "0.8.5",
28 | "jasmine-core": "2.4.1",
29 | "karma": "0.13.19",
30 | "karma-chrome-launcher": "0.2.2",
31 | "karma-coverage": "0.5.3",
32 | "karma-jasmine": "0.3.6",
33 | "remap-istanbul": "0.5.1",
34 | "systemjs": "0.19.17",
35 | "typescript": "1.7.5",
36 | "typings": "0.6.8"
37 | },
38 | "repository": {
39 | "type": "git",
40 | "url": "git+https://github.com/Elecash/angular2-testing.git"
41 | },
42 | "keywords": [
43 | "angular2",
44 | "karma",
45 | "jasmine",
46 | "istanbul",
47 | "unit-testing",
48 | "typescript"
49 | ],
50 | "bugs": {
51 | "url": "https://github.com/Elecash/angular2-testing/issues"
52 | },
53 | "homepage": "https://github.com/Elecash/angular2-testing#readme"
54 | }
55 |
--------------------------------------------------------------------------------
/src/comps/my-list.spec.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {
4 | it,
5 | describe,
6 | expect,
7 | TestComponentBuilder,
8 | injectAsync,
9 | setBaseTestProviders,
10 | beforeEachProviders
11 | } from "angular2/testing";
12 | import {MyList} from "./my-list";
13 | import {Component, provide} from "angular2/core";
14 | import {TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS} from "angular2/platform/testing/browser";
15 | import {HTTP_PROVIDERS, XHRBackend, ResponseOptions, Response} from "angular2/http";
16 | import {MockBackend, MockConnection} from "angular2/src/http/backends/mock_backend";
17 | import {MyService} from "../services/my-service";
18 | import "rxjs/add/operator/map";
19 |
20 | @Component({
21 | template: '',
22 | directives: [MyList]
23 | })
24 | class TestMyList {}
25 |
26 | describe('MyList Tests', () => {
27 | setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);
28 |
29 | beforeEachProviders(() => {
30 | return [
31 | HTTP_PROVIDERS,
32 | provide(XHRBackend, {useClass: MockBackend}),
33 | MyService
34 | ]
35 | });
36 |
37 | it('Should create a component MyList',
38 | injectAsync([XHRBackend, MyService, TestComponentBuilder], (backend, service, tcb) => {
39 | backend.connections.subscribe(
40 | (connection:MockConnection) => {
41 | var options = new ResponseOptions({
42 | body: [
43 | {
44 | "login": "mojombo",
45 | "id": 1,
46 | "avatar_url": "https://avatars.githubusercontent.com/u/1?v=3",
47 | "gravatar_id": "",
48 | "url": "https://api.github.com/users/mojombo",
49 | "html_url": "https://github.com/mojombo",
50 | "followers_url": "https://api.github.com/users/mojombo/followers",
51 | "following_url": "https://api.github.com/users/mojombo/following{/other_user}",
52 | "gists_url": "https://api.github.com/users/mojombo/gists{/gist_id}",
53 | "starred_url": "https://api.github.com/users/mojombo/starred{/owner}{/repo}",
54 | "subscriptions_url": "https://api.github.com/users/mojombo/subscriptions",
55 | "organizations_url": "https://api.github.com/users/mojombo/orgs",
56 | "repos_url": "https://api.github.com/users/mojombo/repos",
57 | "events_url": "https://api.github.com/users/mojombo/events{/privacy}",
58 | "received_events_url": "https://api.github.com/users/mojombo/received_events",
59 | "type": "User",
60 | "site_admin": false
61 | }
62 | ]
63 | });
64 |
65 | var response = new Response(options);
66 |
67 | connection.mockRespond(response);
68 | }
69 | );
70 |
71 | return tcb
72 | .createAsync(TestMyList)
73 | .then((fixture) => {
74 | fixture.detectChanges();
75 | var compiled = fixture.debugElement.nativeElement;
76 |
77 | expect(compiled.innerHTML).toContain('Mojombo');
78 | });
79 | })
80 | );
81 | });
82 |
--------------------------------------------------------------------------------
/src/comps/my-list.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {Component, OnInit} from 'angular2/core';
4 | import {MyService} from '../services/my-service';
5 | import {MyPipe} from '../pipes/my-pipe';
6 | import {GithubUser} from '../services/github-user';
7 | import 'rxjs/add/operator/map';
8 |
9 | @Component({
10 | selector: 'my-list',
11 | bindings: [MyService],
12 | pipes: [MyPipe],
13 | template: `- {{ user.login | capitalizeWords }}
`,
14 | styles: [`
15 | :host {
16 | font-family: 'Arial';
17 | display: flex;
18 | width: 100%;
19 | height: 100%;
20 | }
21 | `]
22 | })
23 | export class MyList implements OnInit {
24 | users:Array;
25 | service:MyService;
26 |
27 | constructor(service:MyService) {
28 | this.service = service;
29 | }
30 |
31 | ngOnInit() {
32 | this.service
33 | .getUsers(5)
34 | .subscribe(
35 | users => this.users = users
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/my-app.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {bootstrap} from 'angular2/platform/browser';
3 | import {HTTP_PROVIDERS} from 'angular2/http';
4 | import {MyList} from "./comps/my-list";
5 |
6 | @Component({
7 | selector: 'my-app',
8 | template: '',
9 | directives: [MyList]
10 | })
11 | class VgDemo {
12 | constructor() {
13 |
14 | }
15 | }
16 |
17 | bootstrap(VgDemo, [
18 | HTTP_PROVIDERS
19 | ]);
20 |
--------------------------------------------------------------------------------
/src/pipes/my-pipe.spec.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {it, describe, expect, beforeEach, inject} from 'angular2/testing';
4 | import {MyPipe} from "./my-pipe";
5 |
6 | describe('MyPipe Tests', () => {
7 | let pipe:MyPipe;
8 |
9 | beforeEach(() => {
10 | pipe = new MyPipe();
11 | });
12 |
13 | it('Should capitalize all words in a string', () => {
14 | var result = pipe.transform('golden retriever', null);
15 |
16 | expect(result).toEqual('Golden Retriever');
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/src/pipes/my-pipe.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {PipeTransform, Pipe} from 'angular2/core';
4 |
5 | @Pipe({name: 'capitalizeWords'})
6 | export class MyPipe implements PipeTransform {
7 | constructor() {
8 | }
9 |
10 | transform(text:string, args:any[]):any {
11 | return text.split(' ').map((str) => {
12 | return str.charAt(0).toUpperCase() + str.slice(1);
13 | }).join(' ');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/services/github-user.ts:
--------------------------------------------------------------------------------
1 | export class GithubUser {
2 | login:string;
3 | id:number;
4 | avatar_url:string;
5 | gravatar_id:string;
6 | url:string;
7 | html_url:string;
8 | followers_url:string;
9 | following_url:string;
10 | gists_url:string;
11 | starred_url:string;
12 | subscriptions_url:string;
13 | organizations_url:string;
14 | repos_url:string;
15 | events_url:string;
16 | received_events_url:string;
17 | type:string;
18 | site_admin:boolean;
19 | }
20 |
--------------------------------------------------------------------------------
/src/services/my-service.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 {MyService} from "./my-service";
6 | import {MockConnection, MockBackend} from "angular2/src/http/backends/mock_backend";
7 | import {provide} from "angular2/core";
8 |
9 | describe('MyService Tests', () => {
10 | beforeEachProviders(() => {
11 | return [
12 | HTTP_PROVIDERS,
13 | provide(XHRBackend, {useClass: MockBackend}),
14 | MyService
15 | ]
16 | });
17 |
18 | it('Should create a component MyList',
19 | inject([XHRBackend, MyService], (backend, service) => {
20 | backend.connections.subscribe(
21 | (connection:MockConnection) => {
22 | var options = new ResponseOptions({
23 | body: [
24 | {
25 | "login": "mojombo",
26 | "id": 1,
27 | "avatar_url": "https://avatars.githubusercontent.com/u/1?v=3",
28 | "gravatar_id": "",
29 | "url": "https://api.github.com/users/mojombo",
30 | "html_url": "https://github.com/mojombo",
31 | "followers_url": "https://api.github.com/users/mojombo/followers",
32 | "following_url": "https://api.github.com/users/mojombo/following{/other_user}",
33 | "gists_url": "https://api.github.com/users/mojombo/gists{/gist_id}",
34 | "starred_url": "https://api.github.com/users/mojombo/starred{/owner}{/repo}",
35 | "subscriptions_url": "https://api.github.com/users/mojombo/subscriptions",
36 | "organizations_url": "https://api.github.com/users/mojombo/orgs",
37 | "repos_url": "https://api.github.com/users/mojombo/repos",
38 | "events_url": "https://api.github.com/users/mojombo/events{/privacy}",
39 | "received_events_url": "https://api.github.com/users/mojombo/received_events",
40 | "type": "User",
41 | "site_admin": false
42 | }
43 | ]
44 | });
45 |
46 | var response = new Response(options);
47 |
48 | connection.mockRespond(response);
49 | }
50 | );
51 |
52 | service.getUsers().subscribe(
53 | (users) => {
54 | expect(users[0].login).toBe('mojombo');
55 | }
56 | );
57 |
58 | service.getUsers(5).subscribe(
59 | (users) => {
60 | expect(users[0].login).toBe('mojombo');
61 | }
62 | );
63 | })
64 | );
65 | });
66 |
--------------------------------------------------------------------------------
/src/services/my-service.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {Http} from "angular2/http";
4 | import {Observable} from "rxjs/Observable";
5 | import {Inject} from "angular2/core";
6 |
7 | export class MyService {
8 | http:Http;
9 |
10 | constructor(@Inject(Http) http:Http) {
11 | this.http = http;
12 | }
13 |
14 | getUsers(since:number):Observable {
15 | var url:string = 'https://api.github.com/users';
16 |
17 | if (since) url = 'https://api.github.com/users?since=' + since;
18 |
19 | return this.http.get(url).map(response => response.json());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------