├── .dockerignore
├── .editorconfig
├── .gitignore
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── README.md
├── app
├── app.component.spec.ts.not.yet
├── app.component.ts
├── heroes.json
├── heroes
│ ├── hero.component.html
│ ├── hero.component.ts
│ ├── hero.model.ts
│ ├── hero.service.ts
│ ├── heroes.component.css
│ ├── heroes.component.html
│ └── heroes.component.ts
└── main.ts
├── e2e-spec.js
├── favicon.ico
├── index.html
├── karma-test-shim.js
├── karma.conf.js
├── package.json
├── protractor.config.js
├── styles.css
├── systemjs.config.js
├── tsconfig.json
├── tslint.json
├── typings.json
├── typings
└── typings.d.ts
└── wallaby.js
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 |
13 | [*.md]
14 | max_line_length = 0
15 | trim_trailing_whitespace = false
16 |
17 | # Indentation override
18 | #[lib/**.js]
19 | #[{package.json,.travis.yml}]
20 | #[**/**.js]
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | typings/**
3 | node_modules
4 | jspm_packages
5 | link-checker-results.txt
6 | **/*npm-debug.log.*
7 | *.js
8 | *.js.map
9 | _test-output
10 | _temp
11 |
12 | !**/*e2e-spec.js
13 | !karma*.js
14 | !protractor*.js
15 | !systemjs.config.js
16 | !typings/typings.d.ts
17 | !wallaby.js
18 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # 0.2.1 (2016-05-03)
3 | * Angular 2 RC01 version
4 |
5 |
6 | # 0.2.0 (2016-05-02)
7 | * Angular 2 RC0 version
8 |
9 |
10 | # 0.1.17 (2016-04-29)
11 | * update packages
12 | * Angular 2 beta 17
13 | * RxJS 5.0.0-beta.6
14 | * a2-in-memory-web-api 0.1.17
15 |
16 |
17 | # 0.1.16 (2016-04-26)
18 | * update packages
19 | * Angular 2 beta 16
20 | * a2-in-memory-web-api 0.1.6
21 | * protractor 3.3.0
22 | * typings 0.8.1
23 | * zone.js 0.6.12
24 |
25 | * added favicon.ico
26 |
27 | * testing
28 | - updated wallaby.js and karma.conf.js
29 | - updated app.component.spec.ts
30 |
31 |
32 |
33 | # 0.1.15 (2016-04-13)
34 | * Add testing support
35 | * npm scripts
36 | * karma/jasmine
37 | * protractor
38 |
39 | * update packages
40 | * Angular 2 beta 15
41 | * lite-server 2.2.0
42 | * systemjs 0.19.26
43 | * typescript 1.8.10
44 | * typings 0.7.12
45 |
46 | * add run packages
47 | * a2-in-memory-web-api
48 |
49 | * add testing dev-dependency packages
50 | * canonical-path: 0.0.2,
51 | * http-server: ^0.9.0,
52 | * jasmine-core: ~2.4.1,
53 | * karma: ^0.13.22,
54 | * karma-chrome-launcher: ^0.2.3,
55 | * karma-cli: ^0.1.2,
56 | * karma-htmlfile-reporter: ^0.2.2,
57 | * karma-jasmine: ^0.3.8,
58 | * protractor: ^3.2.2,
59 | * rimraf: ^2.5.2
60 |
61 |
62 | # 0.1.14 (2016-04-07)
63 | * update packages
64 | * Angular 2 beta 14
65 | * lite-server 2.2.0
66 | * typings 0.7.12
67 |
68 |
69 | # 0.1.13 (2016-03-31)
70 | * update packages
71 | * Angular 2 beta 13
72 |
73 |
74 | # 0.1.12 (2016-03-23)
75 | * update packages
76 | * Angular 2 beta 12
77 | * zones 0.6.6
78 | * remove es6-promise because no longer needed.
79 |
80 |
81 | # 0.1.11 (2016-03-18)
82 | * update packages
83 | * Angular 2 beta 11
84 | * zones 0.6.4
85 | * typescript 1.8.9
86 | * typings 0.7.9
87 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # To build and run with Docker:
2 | #
3 | # $ docker build -t ng2-quickstart .
4 | # $ docker run -it --rm -p 3000:3000 -p 3001:3001 ng2-quickstart
5 | #
6 | FROM node:latest
7 |
8 | RUN mkdir -p /quickstart /home/nodejs && \
9 | groupadd -r nodejs && \
10 | useradd -r -g nodejs -d /home/nodejs -s /sbin/nologin nodejs && \
11 | chown -R nodejs:nodejs /home/nodejs
12 |
13 | WORKDIR /quickstart
14 | COPY package.json typings.json /quickstart/
15 | RUN npm install --unsafe-perm=true
16 |
17 | COPY . /quickstart
18 | RUN chown -R nodejs:nodejs /quickstart
19 | USER nodejs
20 |
21 | CMD npm start
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2014-2016 Google, Inc.
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular 2 Demo from ngConf 2016
2 |
3 | [View the presentation here](https://www.youtube.com/watch?v=WAPQF_GA7Qg&index=2&list=PLOETEcp3DkCq788xapkP_OU-78jhTf68j)
4 |
5 | Clone it and run it!
6 |
7 | ```bash
8 | npm install
9 | npm start
10 | ```
11 |
12 |
13 | [View the slides here](https://docs.google.com/presentation/d/1-WxJ-gncWVBOyXWJvh4vjhXPns_Ohy6iCzhZ0OL2jes/edit?usp=sharing)
14 |
15 |
16 | Other links:
17 |
18 | - [John's Angular 2 Pluralight Course](http://jpapa.me/a2ps1stlook)
19 | - [Angular 2 App in 17 Minutes Live Coding Demo](https://johnpapa.net/17-minute-angular-2-app/)
20 | - Mobile
21 | - [Ionic 2](http://ionic.io/2)
22 | - [NativeScript](http://www.nativescript.org)
23 | - [React Native](http://facebook.github.io/react-native/)
24 | - [Electron](http://electron.atom.io/)
25 | - [Angular Material](https://material.angular.io/)
26 | - [Angular material demo](https://puppy-love.firebaseapp.com/)
27 | - [TypeScript](http://typescriptlang.org)
28 | - [Angular 2 Docs](https://angular.io/docs/ts/latest/)
29 | - [Angular 2 Tutorial](https://angular.io/docs/ts/latest/tutorial/)
30 | - [Angular 2 CLI](http://cli.angular.io)
31 | - [Angular 2 Codelyzer](https://github.com/mgechev/codelyzer)
32 | - [Code snippets in vs code](http://jpapa.me/a2vscode)
33 | - [Angular 2 Style Guide](http://jpapa.me/ng2styleguide)
34 | - [Angular 2 Workshop in Barcelona with Dan Wahlin](https://johnpapa.net/angular-2-workshop-in-barcelona/)
35 | - [Angular 2 ngFor syntax change](https://johnpapa.net/angular-2-ngfor/)
36 | - [Why TypeScript?](https://johnpapa.net/es5-es2015-typescript/)
37 |
--------------------------------------------------------------------------------
/app/app.component.spec.ts.not.yet:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { AppComponent } from './app.component';
3 |
4 | import {
5 | expect, it, iit, xit,
6 | describe, ddescribe, xdescribe,
7 | beforeEach, beforeEachProviders, withProviders,
8 | async, inject, TestComponentBuilder
9 | } from 'angular2/testing';
10 |
11 | import { By } from 'angular2/platform/browser';
12 | import { provide } from 'angular2/core';
13 | import { ViewMetadata } from 'angular2/core';
14 | import { PromiseWrapper } from 'angular2/src/facade/promise';
15 |
16 | //////// SPECS /////////////
17 |
18 | /// Delete this
19 | describe('Smoke test', () => {
20 | it('should run a passing test', () => {
21 | expect(true).toEqual(true, 'should pass');
22 | });
23 | });
24 |
25 | describe('AppComponent with new', function () {
26 | it('should instantiate component', () => {
27 | expect(new AppComponent()).toBeDefined('Whoopie!');
28 | });
29 | });
30 |
31 | describe('AppComponent with TCB', function () {
32 |
33 | it('should instantiate component',
34 | async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
35 |
36 | tcb.createAsync(AppComponent).then(fixture => {
37 | expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent');
38 | });
39 | })));
40 |
41 | it('should have expected
text',
42 | async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
43 |
44 | tcb.createAsync(AppComponent).then(fixture => {
45 | // fixture.detectChanges(); // would need to resolve a binding but we don't have a binding
46 |
47 | let h1 = fixture.debugElement.query(el => el.name === 'h1').nativeElement; // it works
48 |
49 | h1 = fixture.debugElement.query(By.css('h1')).nativeElement; // preferred
50 |
51 | expect(h1.innerText).toMatch(/angular 2 app/i, ' should say something about "Angular 2 App"');
52 | });
53 |
54 | })));
55 | });
56 |
--------------------------------------------------------------------------------
/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | import { HeroesComponent } from './heroes/heroes.component';
4 |
5 | @Component({
6 | selector: 'my-app',
7 | template: `
8 | {{title}}
9 |
10 | `,
11 | directives: [HeroesComponent]
12 | })
13 | export class AppComponent {
14 | title = 'An Angular 2 Force Awakens';
15 | }
16 |
--------------------------------------------------------------------------------
/app/heroes.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 11,
4 | "name": "Chewbacca",
5 | "twitter": "@im_chewy"
6 | },
7 | {
8 | "id": 12,
9 | "name": "Rey",
10 | "twitter": "@rey"
11 | },
12 | {
13 | "id": 13,
14 | "name": "Finn (FN2187)",
15 | "twitter": "@finn"
16 | },
17 | {
18 | "id": 14,
19 | "name": "Han Solo",
20 | "twitter": "@i_know"
21 | },
22 | {
23 | "id": 15,
24 | "name": "Leia Organa",
25 | "twitter": "@organa"
26 | },
27 | {
28 | "id": 16,
29 | "name": "Luke Skywalker",
30 | "twitter": "@chosen_one_son"
31 | },
32 | {
33 | "id": 17,
34 | "name": "Poe Dameron",
35 | "twitter": "@i_am_poe"
36 | },
37 | {
38 | "id": 18,
39 | "name": "Kylo Ren",
40 | "twitter": "@daddy_issues"
41 | },
42 | {
43 | "id": 19,
44 | "name": "Supreme Commander Snoke",
45 | "twitter": "@snoker"
46 | },
47 | {
48 | "id": 20,
49 | "name": "R2-D2",
50 | "twitter": "@r2d2"
51 | },
52 | {
53 | "id": 21,
54 | "name": "BB8",
55 | "twitter": "@bb_eight"
56 | }
57 | ]
58 |
--------------------------------------------------------------------------------
/app/heroes/hero.component.html:
--------------------------------------------------------------------------------
1 |
2 | We selected
3 |
4 |
--------------------------------------------------------------------------------
/app/heroes/hero.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 |
3 | import { Hero } from './hero.model';
4 |
5 | @Component({
6 | moduleId: module.id,
7 | selector: 'toh-hero',
8 | templateUrl: 'hero.component.html'
9 | })
10 | export class HeroComponent {
11 | @Input() hero: Hero;
12 | }
13 |
--------------------------------------------------------------------------------
/app/heroes/hero.model.ts:
--------------------------------------------------------------------------------
1 | export class Hero {
2 | id: number;
3 | name: string;
4 | }
5 |
--------------------------------------------------------------------------------
/app/heroes/hero.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { Http, Response } from '@angular/http';
4 | import 'rxjs/add/operator/map';
5 |
6 | @Injectable()
7 | export class HeroService {
8 | constructor(private http: Http) { }
9 |
10 | getHeroes() {
11 | return this.http.get('app/heroes.json')
12 | .map((res: Response) => res.json());
13 |
14 | // return [
15 | // { 'id': 11, 'name': 'Chewbacca' },
16 | // { 'id': 12, 'name': 'Rey' },
17 | // { 'id': 13, 'name': 'Finn (FN2187)' },
18 | // { 'id': 14, 'name': 'Han Solo' },
19 | // { 'id': 15, 'name': 'Leia Organa' }
20 | // ];
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/heroes/heroes.component.css:
--------------------------------------------------------------------------------
1 | .selected {
2 | background-color: #a62e5c !important;
3 | color: white;
4 | }
5 | .heroes {
6 | margin: 0 0 2em 0;
7 | list-style-type: none;
8 | padding: 0;
9 | width: 15em;
10 | }
11 | .heroes li {
12 | cursor: pointer;
13 | position: relative;
14 | left: 0;
15 | background-color: #EEE;
16 | margin: .5em;
17 | padding: 0.3em 0.3em 0.3em 0;
18 | height: 1.6em;
19 | border-radius: 4px;
20 | text-overflow: ellipsis;
21 | overflow: hidden;
22 | white-space: nowrap;
23 | }
24 | .heroes li.selected:hover {
25 | background-color: #792e5c !important;
26 | color: white;
27 | }
28 | .heroes li:hover {
29 | color: #a62e5c;
30 | background-color: #DDD;
31 | left: .1em;
32 | }
33 | .heroes .text {
34 | position: relative;
35 | top: -3px;
36 | }
37 | .heroes .badge {
38 | display: inline-block;
39 | font-size: small;
40 | color: white;
41 | padding: 0.8em 0.7em 0 0.7em;
42 | background-color: #a62e5c;
43 | line-height: 1em;
44 | position: relative;
45 | left: -1px;
46 | top: -4px;
47 | height: 1.8em;
48 | margin-right: .8em;
49 | border-radius: 4px 0 0 4px;
50 | }
51 |
--------------------------------------------------------------------------------
/app/heroes/heroes.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 | {{hero.id}} {{hero.name}}
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/heroes/heroes.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | import { Hero } from './hero.model';
4 | import { HeroComponent } from './hero.component';
5 | import { HeroService } from './hero.service';
6 |
7 | @Component({
8 | moduleId: module.id,
9 | selector: 'toh-heroes',
10 | templateUrl: 'heroes.component.html',
11 | styleUrls: ['heroes.component.css'],
12 | directives: [HeroComponent],
13 | providers: [HeroService]
14 | })
15 | export class HeroesComponent implements OnInit {
16 | heroes: Hero[];
17 | selectedHero: Hero;
18 |
19 | constructor(private heroService: HeroService) { }
20 |
21 | ngOnInit() {
22 | this.heroService.getHeroes()
23 | .subscribe(heroes => this.heroes = heroes);
24 |
25 | // this.heroes = this.heroService.getHeroes();
26 |
27 | // this.heroes = [
28 | // { 'id': 11, 'name': 'Chewbacca' },
29 | // { 'id': 12, 'name': 'Rey' },
30 | // { 'id': 13, 'name': 'Finn (FN2187)' },
31 | // { 'id': 14, 'name': 'Han Solo' },
32 | // { 'id': 15, 'name': 'Leia Organa' }
33 | // ];
34 | }
35 |
36 | onSelect(hero: Hero){
37 | this.selectedHero = hero;
38 | }
39 |
40 | }
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/main.ts:
--------------------------------------------------------------------------------
1 | import {bootstrap} from '@angular/platform-browser-dynamic';
2 | import { HTTP_PROVIDERS } from '@angular/http';
3 |
4 | import {AppComponent} from './app.component';
5 |
6 | bootstrap(AppComponent, [HTTP_PROVIDERS]);
7 |
--------------------------------------------------------------------------------
/e2e-spec.js:
--------------------------------------------------------------------------------
1 |
2 | describe('QuickStart E2E Tests', function () {
3 |
4 | var expectedMsg = 'My First Angular 2 App';
5 |
6 |
7 | beforeEach(function () {
8 | browser.get('');
9 | });
10 |
11 | it('should display: ' + expectedMsg, function () {
12 | expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
13 | });
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/angular2-force/54d3e87c8efa9e1672af76d703650dfb488133ba/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Angular 2 QuickStart
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 | Loading...
23 |
24 |
25 |
--------------------------------------------------------------------------------
/karma-test-shim.js:
--------------------------------------------------------------------------------
1 | /*global jasmine, __karma__, window*/
2 | (function () {
3 |
4 | // Error.stackTraceLimit = Infinity;
5 |
6 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
7 |
8 | // Cancel Karma's synchronous start,
9 | // we call `__karma__.start()` later, once all the specs are loaded.
10 | __karma__.loaded = function () { };
11 |
12 | // SET THE RUNTIME APPLICATION ROOT HERE
13 | var appRoot ='app'; // no trailing slash!
14 |
15 | // RegExp for client application base path within karma (which always starts 'base\')
16 | var karmaBase = '^\/base\/'; // RegEx string for base of karma folders
17 | var appPackage = 'base/' + appRoot; //e.g., base/app
18 | var appRootRe = new RegExp(karmaBase + appRoot + '\/');
19 | var onlyAppFilesRe = new RegExp(karmaBase + appRoot + '\/(?!.*\.spec\.js$)([a-z0-9-_\.\/]+)\.js$');
20 |
21 | var moduleNames = [];
22 |
23 | // Configure systemjs packages to use the .js extension for imports from the app folder
24 | var packages = {};
25 | packages[appPackage] = {
26 | defaultExtension: false,
27 | format: 'register',
28 | map: Object.keys(window.__karma__.files)
29 | .filter(onlyAppFiles)
30 | // Create local module name mapping to karma file path for app files
31 | // with karma's fingerprint in query string, e.g.:
32 | // './hero.service': '/base/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
33 | .reduce(function (pathsMapping, appPath) {
34 | var moduleName = appPath.replace(appRootRe, './').replace(/\.js$/, '');
35 | pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath];
36 | return pathsMapping;
37 | }, {})
38 | }
39 |
40 | System.config({ packages: packages });
41 |
42 | // Configure Angular for the browser and
43 | // with test versions of the platform providers
44 | Promise.all([
45 | System.import('angular2/testing'),
46 | System.import('angular2/platform/testing/browser')
47 | ])
48 | .then(function (results) {
49 | var testing = results[0];
50 | var browser = results[1];
51 | testing.setBaseTestProviders(
52 | browser.TEST_BROWSER_PLATFORM_PROVIDERS,
53 | browser.TEST_BROWSER_APPLICATION_PROVIDERS);
54 |
55 | // Load all spec files
56 | // (e.g. 'base/app/hero.service.spec.js')
57 | return Promise.all(
58 | Object.keys(window.__karma__.files)
59 | .filter(onlySpecFiles)
60 | .map(function (moduleName) {
61 | moduleNames.push(moduleName);
62 | return System.import(moduleName);
63 | }));
64 | })
65 |
66 | .then(success, fail);
67 |
68 | ////// Helpers //////
69 |
70 | function onlyAppFiles(filePath) {
71 | return onlyAppFilesRe.test(filePath);
72 | }
73 |
74 | function onlySpecFiles(filePath) {
75 | return /\.spec\.js$/.test(filePath);
76 | }
77 |
78 | function success () {
79 | console.log(
80 | 'Spec files loaded:\n ' +
81 | moduleNames.join('\n ') +
82 | '\nStarting Jasmine testrunner');
83 | __karma__.start();
84 | }
85 |
86 | function fail(error) {
87 | __karma__.error(error.stack || error);
88 | }
89 |
90 | })();
91 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 |
3 | var appBase = 'app/'; // transpiled app JS files
4 | var appAssets ='/base/app/'; // component assets fetched by Angular's compiler
5 |
6 | config.set({
7 | basePath: '',
8 | frameworks: ['jasmine'],
9 | plugins: [
10 | require('karma-jasmine'),
11 | require('karma-chrome-launcher'),
12 | require('karma-htmlfile-reporter')
13 | ],
14 |
15 | customLaunchers: {
16 | // From the CLI. Not used here but interesting
17 | // chrome setup for travis CI using chromium
18 | Chrome_travis_ci: {
19 | base: 'Chrome',
20 | flags: ['--no-sandbox']
21 | }
22 | },
23 | files: [
24 | // System.js for module loading
25 | 'node_modules/systemjs/dist/system-polyfills.js',
26 | 'node_modules/systemjs/dist/system.src.js',
27 |
28 | // Polyfills
29 | 'node_modules/es6-shim/es6-shim.js',
30 | 'node_modules/angular2/bundles/angular2-polyfills.js',
31 |
32 | // Zone.js dependencies
33 | // Note - do not include zone.js itself or long-stack-trace-zone.js` here as
34 | // they are included already in angular2-polyfills
35 | 'node_modules/zone.js/dist/jasmine-patch.js',
36 | 'node_modules/zone.js/dist/async-test.js',
37 | 'node_modules/zone.js/dist/fake-async-test.js',
38 |
39 | // RxJs
40 | 'node_modules/rxjs/bundles/Rx.js',
41 |
42 | // Angular 2 itself and the testing library
43 | 'node_modules/angular2/bundles/angular2.js',
44 | 'node_modules/angular2/bundles/router.dev.js',
45 | 'node_modules/angular2/bundles/http.dev.js',
46 | 'node_modules/angular2/bundles/testing.dev.js',
47 |
48 | 'karma-test-shim.js',
49 |
50 | // transpiled application & spec code paths loaded via module imports
51 | {pattern: appBase + '**/*.js', included: false, watched: true},
52 |
53 | // asset (HTML & CSS) paths loaded via Angular's component compiler
54 | // (these paths need to be rewritten, see proxies section)
55 | {pattern: appBase + '**/*.html', included: false, watched: true},
56 | {pattern: appBase + '**/*.css', included: false, watched: true},
57 |
58 | // paths for debugging with source maps in dev tools
59 | {pattern: appBase + '**/*.ts', included: false, watched: false},
60 | {pattern: appBase + '**/*.js.map', included: false, watched: false}
61 | ],
62 |
63 | // proxied base paths for loading assets
64 | proxies: {
65 | // required for component assets fetched by Angular's compiler
66 | "/app/": appAssets
67 | },
68 |
69 | exclude: [],
70 | preprocessors: {},
71 | reporters: ['progress', 'html'],
72 |
73 | // HtmlReporter configuration
74 | htmlReporter: {
75 | // Open this file to see results in browser
76 | outputFile: '_test-output/tests.html',
77 |
78 | // Optional
79 | pageTitle: 'Unit Tests',
80 | subPageTitle: __dirname
81 | },
82 |
83 | port: 9876,
84 | colors: true,
85 | logLevel: config.LOG_INFO,
86 | autoWatch: true,
87 | browsers: ['Chrome'],
88 | singleRun: false
89 | })
90 | }
91 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular2-quickstart",
3 | "version": "1.0.0",
4 | "description": "QuickStart package.json from the documentation, supplemented with testing support",
5 | "scripts": {
6 | "start": "tsc && concurrently \"tsc -w\" \"lite-server\" ",
7 | "docker-build": "docker build -t ng2-quickstart .",
8 | "docker": "npm run docker-build && docker run -it --rm -p 3000:3000 -p 3001:3001 ng2-quickstart",
9 | "e2e": "tsc && concurrently \"http-server\" \"protractor protractor.config.js\"",
10 | "lint": "tslint ./app/**/*.ts -t verbose",
11 | "lite": "lite-server",
12 | "postinstall": "typings install",
13 | "test": "tsc && concurrently \"tsc -w\" \"karma start karma.conf.js\"",
14 | "tsc": "tsc",
15 | "tsc:w": "tsc -w",
16 | "typings": "typings",
17 | "webdriver:update": "webdriver-manager update"
18 | },
19 | "keywords": [],
20 | "author": "",
21 | "license": "ISC",
22 | "dependencies": {
23 | "@angular/common": "2.0.0-rc.1",
24 | "@angular/compiler": "2.0.0-rc.1",
25 | "@angular/core": "2.0.0-rc.1",
26 | "@angular/http": "2.0.0-rc.1",
27 | "@angular/platform-browser": "2.0.0-rc.1",
28 | "@angular/platform-browser-dynamic": "2.0.0-rc.1",
29 | "@angular/router": "2.0.0-rc.1",
30 | "@angular/router-deprecated": "2.0.0-rc.1",
31 | "@angular/upgrade": "2.0.0-rc.1",
32 |
33 | "systemjs": "0.19.27",
34 | "es6-shim": "^0.35.0",
35 | "reflect-metadata": "^0.1.3",
36 | "rxjs": "5.0.0-beta.6",
37 | "zone.js": "^0.6.12",
38 |
39 | "angular2-in-memory-web-api": "0.0.7",
40 | "bootstrap": "^3.3.6"
41 | },
42 | "devDependencies": {
43 | "concurrently": "^2.0.0",
44 | "lite-server": "^2.2.0",
45 | "typescript": "^1.8.10",
46 | "typings": "^0.8.1",
47 |
48 | "canonical-path": "0.0.2",
49 | "http-server": "^0.9.0",
50 | "tslint": "^3.7.4",
51 | "lodash": "^4.11.1",
52 | "jasmine-core": "~2.4.1",
53 | "karma": "^0.13.22",
54 | "karma-chrome-launcher": "^0.2.3",
55 | "karma-cli": "^0.1.2",
56 | "karma-htmlfile-reporter": "^0.2.2",
57 | "karma-jasmine": "^0.3.8",
58 | "protractor": "^3.3.0",
59 | "rimraf": "^2.5.2"
60 | },
61 | "repository": {}
62 | }
63 |
--------------------------------------------------------------------------------
/protractor.config.js:
--------------------------------------------------------------------------------
1 | // FIRST TIME ONLY- run:
2 | // ./node_modules/.bin/webdriver-manager update
3 | //
4 | // Try: `npm run webdriver:update`
5 | //
6 | // AND THEN EVERYTIME ...
7 | // 1. Compile with `tsc`
8 | // 2. Make sure the test server (e.g., http-server: localhost:8080) is running.
9 | // 3. ./node_modules/.bin/protractor protractor.config.js
10 | //
11 | // To do all steps, try: `npm run e2e`
12 |
13 | var fs = require('fs');
14 | var path = require('canonical-path');
15 | var _ = require('lodash');
16 |
17 |
18 | exports.config = {
19 | directConnect: true,
20 |
21 | // Capabilities to be passed to the webdriver instance.
22 | capabilities: {
23 | 'browserName': 'chrome'
24 | },
25 |
26 | // Framework to use. Jasmine is recommended.
27 | framework: 'jasmine',
28 |
29 | // Spec patterns are relative to this config file
30 | specs: ['**/*e2e-spec.js' ],
31 |
32 |
33 | // For angular2 tests
34 | useAllAngular2AppRoots: true,
35 |
36 | // Base URL for application server
37 | baseUrl: 'http://localhost:8080',
38 |
39 | // doesn't seem to work.
40 | // resultJsonOutputFile: "foo.json",
41 |
42 | onPrepare: function() {
43 | //// SpecReporter
44 | //var SpecReporter = require('jasmine-spec-reporter');
45 | //jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'none'}));
46 | //// jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'}));
47 |
48 | // debugging
49 | // console.log('browser.params:' + JSON.stringify(browser.params));
50 | jasmine.getEnv().addReporter(new Reporter( browser.params )) ;
51 |
52 | global.sendKeys = sendKeys;
53 |
54 | // Allow changing bootstrap mode to NG1 for upgrade tests
55 | global.setProtractorToNg1Mode = function() {
56 | browser.useAllAngular2AppRoots = false;
57 | browser.rootEl = 'body';
58 | };
59 | },
60 |
61 | jasmineNodeOpts: {
62 | // defaultTimeoutInterval: 60000,
63 | defaultTimeoutInterval: 10000,
64 | showTiming: true,
65 | print: function() {}
66 | }
67 | };
68 |
69 | // Hack - because of bug with protractor send keys
70 | function sendKeys(element, str) {
71 | return str.split('').reduce(function (promise, char) {
72 | return promise.then(function () {
73 | return element.sendKeys(char);
74 | });
75 | }, element.getAttribute('value'));
76 | // better to create a resolved promise here but ... don't know how with protractor;
77 | }
78 |
79 | // Custom reporter
80 | function Reporter(options) {
81 | var _defaultOutputFile = path.resolve(process.cwd(), './_test-output', 'protractor-results.txt');
82 | options.outputFile = options.outputFile || _defaultOutputFile;
83 |
84 | initOutputFile(options.outputFile);
85 | options.appDir = options.appDir || './';
86 | var _root = { appDir: options.appDir, suites: [] };
87 | log('AppDir: ' + options.appDir, +1);
88 | var _currentSuite;
89 |
90 | this.suiteStarted = function(suite) {
91 | _currentSuite = { description: suite.description, status: null, specs: [] };
92 | _root.suites.push(_currentSuite);
93 | log('Suite: ' + suite.description, +1);
94 | };
95 |
96 | this.suiteDone = function(suite) {
97 | var statuses = _currentSuite.specs.map(function(spec) {
98 | return spec.status;
99 | });
100 | statuses = _.uniq(statuses);
101 | var status = statuses.indexOf('failed') >= 0 ? 'failed' : statuses.join(', ');
102 | _currentSuite.status = status;
103 | log('Suite ' + _currentSuite.status + ': ' + suite.description, -1);
104 | };
105 |
106 | this.specStarted = function(spec) {
107 |
108 | };
109 |
110 | this.specDone = function(spec) {
111 | var currentSpec = {
112 | description: spec.description,
113 | status: spec.status
114 | };
115 | if (spec.failedExpectations.length > 0) {
116 | currentSpec.failedExpectations = spec.failedExpectations;
117 | }
118 |
119 | _currentSuite.specs.push(currentSpec);
120 | log(spec.status + ' - ' + spec.description);
121 | };
122 |
123 | this.jasmineDone = function() {
124 | outputFile = options.outputFile;
125 | //// Alternate approach - just stringify the _root - not as pretty
126 | //// but might be more useful for automation.
127 | // var output = JSON.stringify(_root, null, 2);
128 | var output = formatOutput(_root);
129 | fs.appendFileSync(outputFile, output);
130 | };
131 |
132 | function initOutputFile(outputFile) {
133 | var header = "Protractor results for: " + (new Date()).toLocaleString() + "\n\n";
134 | fs.writeFileSync(outputFile, header);
135 | }
136 |
137 | // for output file output
138 | function formatOutput(output) {
139 | var indent = ' ';
140 | var pad = ' ';
141 | var results = [];
142 | results.push('AppDir:' + output.appDir);
143 | output.suites.forEach(function(suite) {
144 | results.push(pad + 'Suite: ' + suite.description + ' -- ' + suite.status);
145 | pad+=indent;
146 | suite.specs.forEach(function(spec) {
147 | results.push(pad + spec.status + ' - ' + spec.description);
148 | if (spec.failedExpectations) {
149 | pad+=indent;
150 | spec.failedExpectations.forEach(function (fe) {
151 | results.push(pad + 'message: ' + fe.message);
152 | });
153 | pad=pad.substr(2);
154 | }
155 | });
156 | pad = pad.substr(2);
157 | results.push('');
158 | });
159 | results.push('');
160 | return results.join('\n');
161 | }
162 |
163 | // for console output
164 | var _pad;
165 | function log(str, indent) {
166 | _pad = _pad || '';
167 | if (indent == -1) {
168 | _pad = _pad.substr(2);
169 | }
170 | console.log(_pad + str);
171 | if (indent == 1) {
172 | _pad = _pad + ' ';
173 | }
174 | }
175 |
176 | }
177 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | /* Master Styles */
2 | h1 {
3 | color: #444;
4 | font-family: Arial, Helvetica, sans-serif;
5 | font-size: 250%;
6 | }
7 | h2, h3 {
8 | color: #369;
9 | font-family: Arial, Helvetica, sans-serif;
10 | font-weight: lighter;
11 | }
12 | body {
13 | margin: 2em;
14 | }
15 | body, input[text], button {
16 | color: #888;
17 | font-family: Cambria, Georgia;
18 | }
19 | a {
20 | cursor: pointer;
21 | cursor: hand;
22 | }
23 | button {
24 | font-family: Arial;
25 | background-color: #eee;
26 | border: none;
27 | padding: 5px 10px;
28 | border-radius: 4px;
29 | cursor: pointer;
30 | cursor: hand;
31 | }
32 | button:hover {
33 | background-color: #cfd8dc;
34 | }
35 | button:disabled {
36 | background-color: #eee;
37 | color: #aaa;
38 | cursor: auto;
39 | }
40 |
41 | /* Navigation link styles */
42 | nav a {
43 | padding: 5px 10px;
44 | text-decoration: none;
45 | margin-top: 10px;
46 | display: inline-block;
47 | background-color: #eee;
48 | border-radius: 4px;
49 | }
50 | nav a:visited, a:link {
51 | color: #607D8B;
52 | }
53 | nav a:hover {
54 | color: #039be5;
55 | background-color: #CFD8DC;
56 | }
57 | nav a.router-link-active {
58 | color: #039be5;
59 | }
60 |
61 | /* items class */
62 | .items {
63 | margin: 0 0 2em 0;
64 | list-style-type: none;
65 | padding: 0;
66 | width: 24em;
67 | }
68 | .items li {
69 | cursor: pointer;
70 | position: relative;
71 | left: 0;
72 | background-color: #EEE;
73 | margin: .5em;
74 | padding: .3em 0;
75 | height: 1.6em;
76 | border-radius: 4px;
77 | }
78 | .items li:hover {
79 | color: #607D8B;
80 | background-color: #DDD;
81 | left: .1em;
82 | }
83 | .items li.selected:hover {
84 | background-color: #BBD8DC;
85 | color: white;
86 | }
87 | .items .text {
88 | position: relative;
89 | top: -3px;
90 | }
91 | .items {
92 | margin: 0 0 2em 0;
93 | list-style-type: none;
94 | padding: 0;
95 | width: 24em;
96 | }
97 | .items li {
98 | cursor: pointer;
99 | position: relative;
100 | left: 0;
101 | background-color: #EEE;
102 | margin: .5em;
103 | padding: .3em 0;
104 | height: 1.6em;
105 | border-radius: 4px;
106 | }
107 | .items li:hover {
108 | color: #607D8B;
109 | background-color: #DDD;
110 | left: .1em;
111 | }
112 | .items li.selected {
113 | background-color: #CFD8DC;
114 | color: white;
115 | }
116 |
117 | .items li.selected:hover {
118 | background-color: #BBD8DC;
119 | }
120 | .items .text {
121 | position: relative;
122 | top: -3px;
123 | }
124 | .items .badge {
125 | display: inline-block;
126 | font-size: small;
127 | color: white;
128 | padding: 0.8em 0.7em 0 0.7em;
129 | background-color: #607D8B;
130 | line-height: 1em;
131 | position: relative;
132 | left: -1px;
133 | top: -4px;
134 | height: 1.8em;
135 | margin-right: .8em;
136 | border-radius: 4px 0 0 4px;
137 | }
138 |
139 | /* everywhere else */
140 | * {
141 | font-family: Arial, Helvetica, sans-serif;
142 | }
143 |
144 | input {
145 | line-height: 24px;
146 | font-size: 18px;
147 | border: 1px solid lightgray;
148 | border-left: rgba(35,115,23,0.64) 4px solid;
149 | padding: 6px;
150 | width: 280px;
151 | }
152 |
--------------------------------------------------------------------------------
/systemjs.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * System configuration for Angular 2 samples
3 | * Adjust as necessary for your application needs.
4 | * Override at the last minute with global.filterSystemConfig (as plunkers do)
5 | */
6 | (function(global) {
7 |
8 | // map tells the System loader where to look for things
9 | var map = {
10 | 'app': 'app', // 'dist',
11 | 'rxjs': 'node_modules/rxjs',
12 | 'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
13 | '@angular': 'node_modules/@angular'
14 | };
15 |
16 | // packages tells the System loader how to load when no filename and/or no extension
17 | var packages = {
18 | 'app': { main: 'main.js', defaultExtension: 'js' },
19 | 'rxjs': { defaultExtension: 'js' },
20 | 'angular2-in-memory-web-api': { defaultExtension: 'js' },
21 | };
22 |
23 | var packageNames = [
24 | '@angular/common',
25 | '@angular/compiler',
26 | '@angular/core',
27 | '@angular/http',
28 | '@angular/platform-browser',
29 | '@angular/platform-browser-dynamic',
30 | '@angular/router-deprecated',
31 | '@angular/testing',
32 | '@angular/upgrade',
33 | ];
34 |
35 | // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
36 | packageNames.forEach(function(pkgName) {
37 | packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
38 | });
39 |
40 | var config = {
41 | map: map,
42 | packages: packages
43 | }
44 |
45 | System.config(config);
46 |
47 | })(this);
48 |
--------------------------------------------------------------------------------
/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 | },
13 | "exclude": [
14 | "node_modules",
15 | "typings/main",
16 | "typings/main.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/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": true,
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 | "always"
68 | ],
69 | "triple-equals": [
70 | true,
71 | "allow-null-check"
72 | ],
73 | "typedef-whitespace": [
74 | true,
75 | {
76 | "call-signature": "nospace",
77 | "index-signature": "nospace",
78 | "parameter": "nospace",
79 | "property-declaration": "nospace",
80 | "variable-declaration": "nospace"
81 | }
82 | ],
83 | "variable-name": false,
84 | "whitespace": [
85 | true,
86 | "check-branch",
87 | "check-decl",
88 | "check-operator",
89 | "check-separator",
90 | "check-type"
91 | ]
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ambientDependencies": {
3 | "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
4 | "jasmine": "registry:dt/jasmine#2.2.0+20160412134438"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/typings/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare var module: {id: string};
2 |
--------------------------------------------------------------------------------
/wallaby.js:
--------------------------------------------------------------------------------
1 | // Configuration for the Wallaby Visual Studio Code testing extension
2 | // https://marketplace.visualstudio.com/items?itemName=WallabyJs.wallaby-vscode
3 | // Note: Wallaby is not open source and costs money
4 | module.exports = function () {
5 |
6 | return {
7 | files: [
8 | // System.js for module loading
9 | {pattern: 'node_modules/systemjs/dist/system-polyfills.js', instrument: false},
10 | {pattern: 'node_modules/systemjs/dist/system.js', instrument: false},
11 |
12 | // Polyfills
13 | {pattern: 'node_modules/es6-shim/es6-shim.js', instrument: false},
14 | {pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', instrument: false},
15 |
16 | // Zone.js dependencies
17 | // Note - do not include zone.js itself or long-stack-trace-zone.js` here as
18 | // they are included already in angular2-polyfills
19 | {pattern: 'node_modules/zone.js/dist/jasmine-patch.js', instrument: false},
20 | {pattern: 'node_modules/zone.js/dist/async-test.js', instrument: false},
21 | {pattern: 'node_modules/zone.js/dist/fake-async-test.js', instrument: false},
22 |
23 | // Rx.js, Angular 2 itself, and the testing library not here because loaded by systemjs
24 |
25 | {pattern: 'app/**/*+(ts|html|css)', load: false},
26 | {pattern: 'app/**/*.spec.ts', ignore: true}
27 | ],
28 |
29 | tests: [
30 | {pattern: 'app/**/*.spec.ts', load: false}
31 | ],
32 |
33 | middleware: function (app, express) {
34 | app.use('/node_modules', express.static(require('path').join(__dirname, 'node_modules')));
35 | },
36 |
37 | testFramework: 'jasmine',
38 |
39 | bootstrap: function (wallaby) {
40 | wallaby.delayStart();
41 |
42 | System.config({
43 | defaultJSExtensions: true,
44 | packages: {
45 | app: {
46 | meta: {
47 | '*': {
48 | scriptLoad: true
49 | }
50 | }
51 | }
52 | },
53 | paths: {
54 | 'npm:*': 'node_modules/*'
55 | },
56 | map: {
57 | 'angular2': 'npm:angular2',
58 | 'rxjs': 'npm:rxjs'
59 | }
60 | });
61 |
62 | // Configure Angular for the browser and
63 | // with test versions of the platform providers
64 | Promise.all([
65 | System.import('angular2/testing'),
66 | System.import('angular2/platform/testing/browser')
67 | ])
68 | .then(function (results) {
69 | var testing = results[0];
70 | var browser = results[1];
71 | testing.setBaseTestProviders(
72 | browser.TEST_BROWSER_PLATFORM_PROVIDERS,
73 | browser.TEST_BROWSER_APPLICATION_PROVIDERS);
74 |
75 | // Load all spec files
76 | return Promise.all(wallaby.tests.map(function (specFile) {
77 | return System.import(specFile);
78 | }));
79 | })
80 | .then(function () {
81 | wallaby.start();
82 | })
83 | .catch(function (e) {
84 | setTimeout(function () {
85 | throw e;
86 | }, 0);
87 | });
88 | },
89 |
90 | debug: true
91 | };
92 | };
93 |
--------------------------------------------------------------------------------