Merge remote-tracking branch 'remotes/angular.io/master'
# Conflicts: # README.md # public/contribute.jade # public/docs/_includes/_side-nav.jade # public/docs/_includes/_ts-temp.jade # public/docs/index.jade # public/docs/js/latest/cookbook/ts-to-js.jade # public/docs/ts/latest/_data.json # public/docs/ts/latest/cookbook/component-relative-paths.jade # public/docs/ts/latest/cookbook/index.jade # public/docs/ts/latest/cookbook/set-document-title.jade # public/docs/ts/latest/cookbook/visual-studio-2015.jade # public/docs/ts/latest/glossary.jade # public/docs/ts/latest/guide/animations.jade # public/docs/ts/latest/guide/architecture.jade # public/docs/ts/latest/guide/browser-support.jade # public/docs/ts/latest/guide/component-styles.jade # public/docs/ts/latest/guide/forms.jade # public/docs/ts/latest/guide/index.jade # public/docs/ts/latest/guide/pipes.jade # public/docs/ts/latest/guide/router.jade # public/docs/ts/latest/guide/style-guide.jade # public/docs/ts/latest/guide/template-syntax.jade # public/docs/ts/latest/guide/testing.jade # public/docs/ts/latest/guide/typescript-configuration.jade # public/docs/ts/latest/guide/upgrade.jade # public/docs/ts/latest/guide/webpack.jade # public/docs/ts/latest/index.jade # public/docs/ts/latest/quickstart.jade # public/docs/ts/latest/tutorial/index.jade # public/support.jade
This commit is contained in:
commit
d9af771f8d
|
@ -461,7 +461,7 @@ gulp.task('_copy-example-boilerplate', function (done) {
|
||||||
return argv.fast ? done() : buildStyles(copyExampleBoilerplate, done);
|
return argv.fast ? done() : buildStyles(copyExampleBoilerplate, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
//Builds Angular 2 Docs CSS file from Bootstrap npm LESS source
|
//Builds Angular Docs CSS file from Bootstrap npm LESS source
|
||||||
//and copies the result to the _examples folder to be included as
|
//and copies the result to the _examples folder to be included as
|
||||||
//part of the example boilerplate.
|
//part of the example boilerplate.
|
||||||
function buildStyles(cb, done){
|
function buildStyles(cb, done){
|
||||||
|
|
14
harp.json
14
harp.json
|
@ -85,7 +85,7 @@
|
||||||
"picture": "/resources/images/bios/tobias.jpg",
|
"picture": "/resources/images/bios/tobias.jpg",
|
||||||
"twitter": "tbosch1009",
|
"twitter": "tbosch1009",
|
||||||
"website": "https://plus.google.com/+TobiasBosch",
|
"website": "https://plus.google.com/+TobiasBosch",
|
||||||
"bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular 2.",
|
"bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular.",
|
||||||
"type": "Google"
|
"type": "Google"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
"picture": "/resources/images/bios/hansl.jpg",
|
"picture": "/resources/images/bios/hansl.jpg",
|
||||||
"twitter": "hanslatwork",
|
"twitter": "hanslatwork",
|
||||||
"website": "http://www.codingatwork.com/",
|
"website": "http://www.codingatwork.com/",
|
||||||
"bio": "Hans is a software engineer at Google on the Angular team and was previously at Slack. He works everyday to help make it easier for everyone to create beautiful, consistent web applications using Angular2, using Material Design components and the CLI tool.",
|
"bio": "Hans is a software engineer at Google on the Angular team and was previously at Slack. He works everyday to help make it easier for everyone to create beautiful, consistent web applications using Angular, using Material Design components and the CLI tool.",
|
||||||
"type": "Google"
|
"type": "Google"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -316,6 +316,12 @@
|
||||||
"bio": "Max Sills is Angular's Open Source lawyer.",
|
"bio": "Max Sills is Angular's Open Source lawyer.",
|
||||||
"type": "Google"
|
"type": "Google"
|
||||||
},
|
},
|
||||||
|
"shannon": {
|
||||||
|
"name": "Shannon Ayres",
|
||||||
|
"picture": "/resources/images/bios/shannon.jpg",
|
||||||
|
"bio": "Shannon is a technical editor in Developer Relations at Google. She loves movies, especially Sunset Boulevard, and her favorite TV show is The Walking Dead. Her mission: Righting wrong writing!",
|
||||||
|
"type": "Google"
|
||||||
|
},
|
||||||
|
|
||||||
"pawel": {
|
"pawel": {
|
||||||
"name": "Pawel Kozlowski",
|
"name": "Pawel Kozlowski",
|
||||||
|
@ -354,7 +360,7 @@
|
||||||
"picture": "/resources/images/bios/marclaval.jpg",
|
"picture": "/resources/images/bios/marclaval.jpg",
|
||||||
"twitter": "marclaval",
|
"twitter": "marclaval",
|
||||||
"website": "https://github.com/mlaval",
|
"website": "https://github.com/mlaval",
|
||||||
"bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular 2.",
|
"bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular.",
|
||||||
"type": "Community"
|
"type": "Community"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -372,7 +378,7 @@
|
||||||
"picture": "/resources/images/bios/patrick-stapleton.jpg",
|
"picture": "/resources/images/bios/patrick-stapleton.jpg",
|
||||||
"twitter": "gdi2290",
|
"twitter": "gdi2290",
|
||||||
"website": "https://angularclass.com",
|
"website": "https://angularclass.com",
|
||||||
"bio": "Also know as PatrickJS where JS stands for his middle and last names. Patrick is very active in Open-Source with over 4,300+ contributions in the last year alone on projects such as Angular2, AngularJS, FalcorJS, Docker, Bootstrap, gulp, and redis to name a few. He is also working on the development of Angular 2 server-side rendering as Universal Angular 2 and teaching Modern Web Development at AngularClass. He was previously the CTO of Keychain Logistics, a HackReactor Instructor and Alum.",
|
"bio": "Also know as PatrickJS where JS stands for his middle and last names. Patrick is very active in Open-Source with over 4,300+ contributions in the last year alone on projects such as Angular2, AngularJS, FalcorJS, Docker, Bootstrap, gulp, and redis to name a few. He is also working on the development of Angular server-side rendering as Universal Angular and teaching Modern Web Development at AngularClass. He was previously the CTO of Keychain Logistics, a HackReactor Instructor and Alum.",
|
||||||
"type": "Community"
|
"type": "Community"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "angular.io",
|
"name": "angular.io",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Angular 2 documentation",
|
"description": "Angular documentation",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
"gulp-tslint": "^5.0.0",
|
"gulp-tslint": "^5.0.0",
|
||||||
"gulp-util": "^3.0.6",
|
"gulp-util": "^3.0.6",
|
||||||
"gulp-watch": "^4.3.4",
|
"gulp-watch": "^4.3.4",
|
||||||
"harp": "git://github.com/filipesilva/harp.git#8da8d3497ddbfcbcbadd8be63e0fd731d7310cc4",
|
"harp": "0.21.0-pre.1",
|
||||||
"html2jade": "^0.8.4",
|
"html2jade": "^0.8.4",
|
||||||
"indent-string": "^2.1.0",
|
"indent-string": "^2.1.0",
|
||||||
"jasmine-core": "^2.3.4",
|
"jasmine-core": "^2.3.4",
|
||||||
|
@ -77,4 +77,4 @@
|
||||||
"jstransformer-marked": "^1.0.1"
|
"jstransformer-marked": "^1.0.1"
|
||||||
},
|
},
|
||||||
"homepage": "http://angular.io/"
|
"homepage": "http://angular.io/"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ else
|
||||||
h3.text-headline 资源库
|
h3.text-headline 资源库
|
||||||
|
|
||||||
ul.text-body
|
ul.text-body
|
||||||
// TODO: (ericjim) make a libraries page to showcase all angular 2 libraries
|
// TODO: (ericjim) make a libraries page to showcase all angular libraries
|
||||||
//li <a href="/libraries.html">Libraries</a>
|
//li <a href="/libraries.html">Libraries</a>
|
||||||
li <a href="/about/">About</a>
|
li <a href="/about/">About</a>
|
||||||
li <a href="/about/">关于</a>
|
li <a href="/about/">关于</a>
|
||||||
|
|
|
@ -12,7 +12,7 @@ if title == "Angular"
|
||||||
else if language
|
else if language
|
||||||
title #{title} - #{language}
|
title #{title} - #{language}
|
||||||
else
|
else
|
||||||
title #{title} - Angular 2
|
title #{title} - Angular
|
||||||
|
|
||||||
meta(charset="utf-8")
|
meta(charset="utf-8")
|
||||||
meta(http-equiv="X-UA-Compatible" content="IE=edge")
|
meta(http-equiv="X-UA-Compatible" content="IE=edge")
|
||||||
|
@ -22,14 +22,14 @@ meta(name="robots" content="all")
|
||||||
meta(name="referrer" content="origin")
|
meta(name="referrer" content="origin")
|
||||||
meta(name="viewport" id="viewport" content="width=device-width, initial-scale=1")
|
meta(name="viewport" id="viewport" content="width=device-width, initial-scale=1")
|
||||||
|
|
||||||
meta(property="og:title" content="Angular 2")
|
meta(property="og:title" content="Angular")
|
||||||
meta(property="og:image" content="/resources/images/logos/standard/shield-large.png")
|
meta(property="og:image" content="/resources/images/logos/standard/shield-large.png")
|
||||||
meta(property="og:image:type" content="image/png")
|
meta(property="og:image:type" content="image/png")
|
||||||
meta(property="og:image:width" content="184")
|
meta(property="og:image:width" content="184")
|
||||||
meta(property="og:image:height" content="200")
|
meta(property="og:image:height" content="200")
|
||||||
meta(property="og:description" content="#{description}")
|
meta(property="og:description" content="#{description}")
|
||||||
|
|
||||||
meta(itemprop="name" content="Angular 2")
|
meta(itemprop="name" content="Angular")
|
||||||
meta(itemprop="description" content="#{description}")
|
meta(itemprop="description" content="#{description}")
|
||||||
meta(itemprop="image" content="/resources/images/logos/standard/shield-large.png")
|
meta(itemprop="image" content="/resources/images/logos/standard/shield-large.png")
|
||||||
|
|
||||||
|
|
|
@ -44,20 +44,20 @@ mixin tree(directory, urlPrefix, name, latest)
|
||||||
//- BUTTON TITLE GENERATION
|
//- BUTTON TITLE GENERATION
|
||||||
if language == 'ts'
|
if language == 'ts'
|
||||||
if version == "latest"
|
if version == "latest"
|
||||||
- var title = 'Angular 2 for TypeScript'
|
- var title = 'Angular for TypeScript'
|
||||||
else
|
else
|
||||||
- var title = 'Angular ' + version + ' for TypeScript'
|
- var title = 'Angular ' + version + ' for TypeScript'
|
||||||
|
|
||||||
if language == 'js'
|
if language == 'js'
|
||||||
if version == "latest"
|
if version == "latest"
|
||||||
- var title = 'Angular 2 for JavaScript'
|
- var title = 'Angular for JavaScript'
|
||||||
else
|
else
|
||||||
- var title = 'Angular ' + version + ' for JavaScript'
|
- var title = 'Angular ' + version + ' for JavaScript'
|
||||||
|
|
||||||
|
|
||||||
if language == 'dart'
|
if language == 'dart'
|
||||||
if version == "latest"
|
if version == "latest"
|
||||||
- var title = 'Angular 2 for Dart'
|
- var title = 'Angular for Dart'
|
||||||
else
|
else
|
||||||
- var title = 'Angular ' + version + ' for Dart'
|
- var title = 'Angular ' + version + ' for Dart'
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ nav.dropdown
|
||||||
|
|
||||||
<!-- DROPDOWN MENU -->
|
<!-- DROPDOWN MENU -->
|
||||||
ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''")
|
ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''")
|
||||||
mixin tree(public.docs.ts, "/docs/ts", "Angular 2 for TypeScript")
|
mixin tree(public.docs.ts, "/docs/ts", "Angular for TypeScript")
|
||||||
mixin tree(public.docs.js, "/docs/js", "Angular 2 for JavaScript")
|
mixin tree(public.docs.js, "/docs/js", "Angular for JavaScript")
|
||||||
//- Disable cross-language link for API entry pages (but keep for top API search page):
|
//- Disable cross-language link for API entry pages (but keep for top API search page):
|
||||||
if ! (current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]])
|
if ! (current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]])
|
||||||
mixin tree(public.docs.dart, "/docs/dart", "Angular 2 for Dart")
|
mixin tree(public.docs.dart, "/docs/dart", "Angular for Dart")
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
p 我们希望你能给我们的源代码做出贡献,让Angular项目变得更好。
|
p 我们希望你能给我们的源代码做出贡献,让Angular项目变得更好。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
h3 Angular 2
|
h3 Angular
|
||||||
|
|
||||||
p Angular 2 is a next generation mobile and desktop application development platform.
|
p Angular is a next generation mobile and desktop application development platform.
|
||||||
|
|
||||||
p Angular 2是下一代移动与桌面应用开发平台。
|
p Angular是下一代移动与桌面应用开发平台。
|
||||||
|
|
||||||
a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) Contribute to Angular 2
|
a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) Contribute to Angular
|
||||||
a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) 为Angular 2做贡献
|
a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) 为Angular做贡献
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
h3 Angular for JavaScript or Dart
|
h3 Angular for JavaScript or Dart
|
||||||
|
|
|
@ -26,7 +26,7 @@ exports.config = {
|
||||||
// Framework to use. Jasmine is recommended.
|
// Framework to use. Jasmine is recommended.
|
||||||
framework: 'jasmine',
|
framework: 'jasmine',
|
||||||
|
|
||||||
// For angular2 tests
|
// For angular tests
|
||||||
useAllAngular2AppRoots: true,
|
useAllAngular2AppRoots: true,
|
||||||
|
|
||||||
baseUrl: 'http://localhost:8080',
|
baseUrl: 'http://localhost:8080',
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* The tests here basically just checking that the end styles
|
* The tests here basically just checking that the end styles
|
||||||
* of each animation are in effect.
|
* of each animation are in effect.
|
||||||
*
|
*
|
||||||
* Relies on the Angular 2 testability only becoming stable once
|
* Relies on the Angular testability only becoming stable once
|
||||||
* animation(s) have finished.
|
* animation(s) have finished.
|
||||||
*
|
*
|
||||||
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
|
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"description": "Angular 2 Animations",
|
"description": "Angular Animations",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js"
|
"!**/*.js"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Architecture of Angular 2</title>
|
<title>Architecture of Angular</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Hero {
|
||||||
|
|
||||||
describe('Architecture', () => {
|
describe('Architecture', () => {
|
||||||
|
|
||||||
const expectedTitle = 'Architecture of Angular 2';
|
const expectedTitle = 'Architecture of Angular';
|
||||||
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
|
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
|
||||||
|
|
||||||
beforeAll(() => browser.get(''));
|
beforeAll(() => browser.get(''));
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: 'Welcome to Angular 2'
|
template: 'Welcome to Angular'
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
constructor(logger: Logger) {
|
constructor(logger: Logger) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Architecture of Angular 2</title>
|
<title>Architecture of Angular</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Architecture of Angular 2</title>
|
<title>Architecture of Angular</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"description": "Intro to Angular2",
|
"description": "Intro to Angular",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js",
|
"!**/*.js",
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('AOT Compilation', function () {
|
||||||
|
|
||||||
it('should load page and click button', function (done) {
|
it('should load page and click button', function (done) {
|
||||||
let headingSelector = element.all(by.css('h1')).get(0);
|
let headingSelector = element.all(by.css('h1')).get(0);
|
||||||
expect(headingSelector.getText()).toEqual('My First Angular 2 App');
|
expect(headingSelector.getText()).toEqual('My First Angular App');
|
||||||
|
|
||||||
expect(element.all(by.xpath('//div[text()="Magneta"]')).get(0).isPresent()).toBe(true);
|
expect(element.all(by.xpath('//div[text()="Magneta"]')).get(0).isPresent()).toBe(true);
|
||||||
expect(element.all(by.xpath('//div[text()="Bombasto"]')).get(0).isPresent()).toBe(true);
|
expect(element.all(by.xpath('//div[text()="Bombasto"]')).get(0).isPresent()).toBe(true);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<button (click)="toggleHeading()">Toggle Heading</button>
|
<button (click)="toggleHeading()">Toggle Heading</button>
|
||||||
<h1 *ngIf="showHeading">My First Angular 2 App</h1>
|
<h1 *ngIf="showHeading">My First Angular App</h1>
|
||||||
|
|
||||||
<h3>List of Heroes</h3>
|
<h3>List of Heroes</h3>
|
||||||
<div *ngFor="let hero of heroes">{{hero}}</div>
|
<div *ngFor="let hero of heroes">{{hero}}</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"description": "Set The Document Title In Angular 2",
|
"description": "Set The Document Title In Angular",
|
||||||
"files": [
|
"files": [
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js",
|
"!**/*.js",
|
||||||
|
|
|
@ -7,6 +7,6 @@ describe('cli-quickstart App', () => {
|
||||||
|
|
||||||
it('should display message saying app works', () => {
|
it('should display message saying app works', () => {
|
||||||
let pageTitle = element(by.css('cli-quickstart-app h1')).getText();
|
let pageTitle = element(by.css('cli-quickstart-app h1')).getText();
|
||||||
expect(pageTitle).toEqual('My First Angular 2 App');
|
expect(pageTitle).toEqual('My First Angular App');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,6 @@ import { Component } from '@angular/core';
|
||||||
// #enddocregion metadata
|
// #enddocregion metadata
|
||||||
// #docregion title, class
|
// #docregion title, class
|
||||||
export class CliQuickstartAppComponent {
|
export class CliQuickstartAppComponent {
|
||||||
title = 'My First Angular 2 App';
|
title = 'My First Angular App';
|
||||||
}
|
}
|
||||||
// #enddocregion title, class
|
// #enddocregion title, class
|
||||||
|
|
|
@ -48,5 +48,5 @@
|
||||||
|
|
||||||
// #docregion first, final
|
// #docregion first, final
|
||||||
});
|
});
|
||||||
// #enddocregion first, final
|
|
||||||
})(window.app || (window.app = {}));
|
})(window.app || (window.app = {}));
|
||||||
|
// #enddocregion first, final
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Hello World</title>
|
<title>Angular Hello World</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Hello World</title>
|
<title>Angular Hello World</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Tabs</title>
|
<title>Angular Tabs</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Tabs</title>
|
<title>Angular Tabs</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Todos</title>
|
<title>Angular Todos</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Todos</title>
|
<title>Angular Todos</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Lifecycle Hooks</title>
|
<title>Angular Lifecycle Hooks</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
### Angular 2 Documentation Example
|
### Angular Documentation Example
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
describe('QuickStart E2E Tests', function () {
|
describe('QuickStart E2E Tests', function () {
|
||||||
|
|
||||||
let expectedMsg = 'My First Angular 2 App';
|
let expectedMsg = 'My First Angular App';
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
ng.core.Component({
|
ng.core.Component({
|
||||||
// #enddocregion ng-namespace-funcs
|
// #enddocregion ng-namespace-funcs
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: '<h1>My First Angular 2 App</h1>'
|
template: '<h1>My First Angular App</h1>'
|
||||||
// #docregion ng-namespace-funcs
|
// #docregion ng-namespace-funcs
|
||||||
})
|
})
|
||||||
// #enddocregion component
|
// #enddocregion component
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 QuickStart JS</title>
|
<title>Angular QuickStart JS</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Component } from '@angular/core';
|
||||||
// #docregion metadata
|
// #docregion metadata
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: '<h1>My First Angular 2 App</h1>'
|
template: '<h1>My First Angular App</h1>'
|
||||||
})
|
})
|
||||||
// #enddocregion metadata
|
// #enddocregion metadata
|
||||||
// #docregion class
|
// #docregion class
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 QuickStart</title>
|
<title>Angular QuickStart</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "angular2-quickstart",
|
"name": "angular-quickstart",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
|
"start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// #docregion
|
// #docregion
|
||||||
/**
|
/**
|
||||||
* System configuration for Angular 2 samples
|
* System configuration for Angular samples
|
||||||
* Adjust as necessary for your application needs.
|
* Adjust as necessary for your application needs.
|
||||||
*/
|
*/
|
||||||
(function (global) {
|
(function (global) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Http Demo</title>
|
<title>Angular Http Demo</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Structural Directives</title>
|
<title>Angular Structural Directives</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
describe('Documentation StyleGuide E2E Tests', function() {
|
describe('Documentation StyleGuide E2E Tests', function() {
|
||||||
|
|
||||||
let expectedMsg = 'My First Angular 2 App';
|
let expectedMsg = 'My First Angular App';
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
|
|
|
@ -8,7 +8,7 @@ app.AppComponent =
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
// #docregion view
|
// #docregion view
|
||||||
template: '<h1 id="output">My First Angular 2 App</h1>'
|
template: '<h1 id="output">My First Angular App</h1>'
|
||||||
})
|
})
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
// #docregion class
|
// #docregion class
|
||||||
|
@ -48,7 +48,7 @@ app.AppComponent = function AppComponent () {}
|
||||||
app.AppComponent.annotations = [
|
app.AppComponent.annotations = [
|
||||||
new ng.core.Component({
|
new ng.core.Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: '<h1 id="output">My First Angular 2 App</h1>'
|
template: '<h1 id="output">My First Angular App</h1>'
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: '<h1 id="output">My First Angular 2 App</h1>'
|
template: '<h1 id="output">My First Angular App</h1>'
|
||||||
})
|
})
|
||||||
export class AppComponent { }
|
export class AppComponent { }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* System configuration for Angular 2 samples
|
* System configuration for Angular samples
|
||||||
* Adjust as necessary for your application needs.
|
* Adjust as necessary for your application needs.
|
||||||
*/
|
*/
|
||||||
(function (global) {
|
(function (global) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* PLUNKER VERSION FOR CURRENT ANGULAR BUILD
|
* PLUNKER VERSION FOR CURRENT ANGULAR BUILD
|
||||||
* (based on systemjs.config.js in angular.io)
|
* (based on systemjs.config.js in angular.io)
|
||||||
* System configuration for Angular 2 samples
|
* System configuration for Angular samples
|
||||||
* Adjust as necessary for your application needs.
|
* Adjust as necessary for your application needs.
|
||||||
*
|
*
|
||||||
* UNTESTED !
|
* UNTESTED !
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* PLUNKER VERSION
|
* PLUNKER VERSION
|
||||||
* (based on systemjs.config.js in angular.io)
|
* (based on systemjs.config.js in angular.io)
|
||||||
* System configuration for Angular 2 samples
|
* System configuration for Angular samples
|
||||||
* Adjust as necessary for your application needs.
|
* Adjust as necessary for your application needs.
|
||||||
*/
|
*/
|
||||||
(function (global) {
|
(function (global) {
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var __spec_files__ = [
|
var __spec_files__ = [
|
||||||
|
'app/about.component.spec',
|
||||||
'app/app.component.spec',
|
'app/app.component.spec',
|
||||||
'app/app.component.router.spec',
|
'app/app.component.router.spec',
|
||||||
'app/banner.component.spec',
|
'app/banner.component.spec',
|
||||||
|
@ -42,7 +43,7 @@
|
||||||
'app/model/hero.spec',
|
'app/model/hero.spec',
|
||||||
'app/model/http-hero.service.spec',
|
'app/model/http-hero.service.spec',
|
||||||
'app/shared/title-case.pipe.spec',
|
'app/shared/title-case.pipe.spec',
|
||||||
'app/twain.component.spec',
|
'app/shared/twain.component.spec',
|
||||||
'app/welcome.component.spec'
|
'app/welcome.component.spec'
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { AboutComponent } from './about.component';
|
||||||
|
import { HighlightDirective } from './shared/highlight.directive';
|
||||||
|
|
||||||
|
let fixture: ComponentFixture<AboutComponent>;
|
||||||
|
|
||||||
|
describe('AboutComponent (highlightDirective)', () => {
|
||||||
|
// #docregion tests
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.configureTestingModule({
|
||||||
|
declarations: [ AboutComponent, HighlightDirective],
|
||||||
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
|
})
|
||||||
|
.createComponent(AboutComponent);
|
||||||
|
fixture.detectChanges(); // initial binding
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have skyblue <h2>', () => {
|
||||||
|
const de = fixture.debugElement.query(By.css('h2'));
|
||||||
|
expect(de.styles['backgroundColor']).toBe('skyblue');
|
||||||
|
});
|
||||||
|
// #enddocregion tests
|
||||||
|
});
|
|
@ -1,12 +1,9 @@
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<h2 highlight="skyblue">About</h2>
|
<h2 highlight="skyblue">About</h2>
|
||||||
<twain-quote></twain-quote>
|
<twain-quote></twain-quote>
|
||||||
<p>All about this sample</p>
|
<p>All about this sample</p>`
|
||||||
`,
|
|
||||||
styleUrls: ['app/shared/styles.css']
|
|
||||||
})
|
})
|
||||||
export class AboutComponent { }
|
export class AboutComponent { }
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { AboutComponent } from './about.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forRoot([
|
||||||
|
{ path: '', redirectTo: 'dashboard', pathMatch: 'full'},
|
||||||
|
{ path: 'about', component: AboutComponent },
|
||||||
|
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule'}
|
||||||
|
])
|
||||||
|
],
|
||||||
|
exports: [ RouterModule ] // re-export the module declarations
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { };
|
|
@ -1,3 +1,4 @@
|
||||||
|
<!-- #docregion -->
|
||||||
<app-banner></app-banner>
|
<app-banner></app-banner>
|
||||||
<app-welcome></app-welcome>
|
<app-welcome></app-welcome>
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,7 @@ import { async, ComponentFixture, fakeAsync, TestBed, tick,
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { SpyLocation } from '@angular/common/testing';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
// tslint:disable:no-unused-variable
|
import { click } from '../testing';
|
||||||
import { newEvent } from '../testing';
|
|
||||||
// tslint:enable:no-unused-variable
|
|
||||||
|
|
||||||
// r - for relatively obscure router symbols
|
// r - for relatively obscure router symbols
|
||||||
import * as r from '@angular/router';
|
import * as r from '@angular/router';
|
||||||
|
@ -48,9 +46,8 @@ describe('AppComponent & RouterTestingModule', () => {
|
||||||
|
|
||||||
it('should navigate to "About" on click', fakeAsync(() => {
|
it('should navigate to "About" on click', fakeAsync(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
// page.aboutLinkDe.triggerEventHandler('click', null); // fails
|
click(page.aboutLinkDe);
|
||||||
// page.aboutLinkDe.nativeElement.dispatchEvent(newEvent('click')); // fails
|
// page.aboutLinkDe.nativeElement.click(); // ok but fails in phantom
|
||||||
page.aboutLinkDe.nativeElement.click(); // fails in phantom
|
|
||||||
|
|
||||||
advance();
|
advance();
|
||||||
expectPathToBe('/about');
|
expectPathToBe('/about');
|
||||||
|
|
|
@ -1,108 +1,94 @@
|
||||||
|
// #docplaster
|
||||||
import { async, ComponentFixture, TestBed
|
import { async, ComponentFixture, TestBed
|
||||||
} from '@angular/core/testing';
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
// #docregion setup-schemas
|
||||||
import { BannerComponent } from './banner.component';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { SharedModule } from './shared/shared.module';
|
// #enddocregion setup-schemas
|
||||||
|
// #docregion setup-stubs-w-imports
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
// #docregion setup-schemas
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
// #enddocregion setup-schemas
|
||||||
|
import { BannerComponent } from './banner.component';
|
||||||
|
import { RouterLinkStubDirective } from '../testing';
|
||||||
|
// #docregion setup-schemas
|
||||||
|
import { RouterOutletStubComponent } from '../testing';
|
||||||
|
|
||||||
import { Router, FakeRouter, FakeRouterLinkDirective, FakeRouterOutletComponent
|
// #enddocregion setup-schemas
|
||||||
} from '../testing';
|
@Component({selector: 'app-welcome', template: ''})
|
||||||
|
class WelcomeStubComponent {}
|
||||||
|
|
||||||
|
// #enddocregion setup-stubs-w-imports
|
||||||
|
|
||||||
let comp: AppComponent;
|
let comp: AppComponent;
|
||||||
let fixture: ComponentFixture<AppComponent>;
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
|
|
||||||
describe('AppComponent & TestModule', () => {
|
describe('AppComponent & TestModule', () => {
|
||||||
|
// #docregion setup-stubs, setup-stubs-w-imports
|
||||||
beforeEach( async(() => {
|
beforeEach( async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent, BannerComponent,
|
AppComponent,
|
||||||
FakeRouterLinkDirective, FakeRouterOutletComponent
|
BannerComponent, WelcomeStubComponent,
|
||||||
],
|
RouterLinkStubDirective, RouterOutletStubComponent
|
||||||
providers: [{ provide: Router, useClass: FakeRouter }],
|
]
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
.compileComponents()
|
.compileComponents()
|
||||||
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
});
|
});
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
// #enddocregion setup-stubs, setup-stubs-w-imports
|
||||||
tests();
|
tests();
|
||||||
});
|
});
|
||||||
|
|
||||||
function tests() {
|
//////// Testing w/ NO_ERRORS_SCHEMA //////
|
||||||
|
describe('AppComponent & NO_ERRORS_SCHEMA', () => {
|
||||||
|
// #docregion setup-schemas
|
||||||
|
beforeEach( async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ AppComponent, RouterLinkStubDirective ],
|
||||||
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
|
})
|
||||||
|
|
||||||
it('can instantiate it', () => {
|
.compileComponents()
|
||||||
expect(comp).not.toBeNull();
|
.then(() => {
|
||||||
});
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
it('can get RouterLinks from template', () => {
|
});
|
||||||
fixture.detectChanges();
|
}));
|
||||||
|
// #enddocregion setup-schemas
|
||||||
const links = fixture.debugElement
|
tests();
|
||||||
// find all elements with an attached FakeRouterLink directive
|
});
|
||||||
.queryAll(By.directive(FakeRouterLinkDirective))
|
|
||||||
// use injector to get the RouterLink directive instance attached to each element
|
|
||||||
.map(de => de.injector.get(FakeRouterLinkDirective) as FakeRouterLinkDirective);
|
|
||||||
|
|
||||||
expect(links.length).toBe(3, 'should have 3 links');
|
|
||||||
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
|
|
||||||
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can click Heroes link in template', () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
// Heroes RouterLink DebugElement
|
|
||||||
const heroesLinkDe = fixture.debugElement
|
|
||||||
.queryAll(By.directive(FakeRouterLinkDirective))[1];
|
|
||||||
|
|
||||||
expect(heroesLinkDe).toBeDefined('should have a 2nd RouterLink');
|
|
||||||
|
|
||||||
const link = heroesLinkDe.injector.get(FakeRouterLinkDirective) as FakeRouterLinkDirective;
|
|
||||||
|
|
||||||
expect(link.navigatedTo).toBeNull('link should not have navigate yet');
|
|
||||||
|
|
||||||
heroesLinkDe.triggerEventHandler('click', null);
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(link.navigatedTo).toBe('/heroes');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//////// Testing w/ real root module //////
|
//////// Testing w/ real root module //////
|
||||||
// Best to avoid
|
|
||||||
// Tricky because we are disabling the router and its configuration
|
// Tricky because we are disabling the router and its configuration
|
||||||
|
// Better to use RouterTestingModule
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
|
||||||
describe('AppComponent & AppModule', () => {
|
describe('AppComponent & AppModule', () => {
|
||||||
|
|
||||||
beforeEach( async(() => {
|
beforeEach( async(() => {
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [ AppModule ],
|
imports: [ AppModule ]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Get rid of app's Router configuration otherwise many failures.
|
||||||
|
// Doing so removes Router declarations; add the Router stubs
|
||||||
.overrideModule(AppModule, {
|
.overrideModule(AppModule, {
|
||||||
// Must get rid of `RouterModule.forRoot` to prevent attempt to configure a router
|
remove: {
|
||||||
// Can't remove it because it doesn't have a known type (`forRoot` returns an object)
|
imports: [ AppRoutingModule ]
|
||||||
// therefore, must reset the entire `imports` with just the necessary stuff
|
},
|
||||||
set: { imports: [ SharedModule ]}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Separate override because cannot both `set` and `add/remove` in same override
|
|
||||||
.overrideModule(AppModule, {
|
|
||||||
add: {
|
add: {
|
||||||
declarations: [ FakeRouterLinkDirective, FakeRouterOutletComponent ],
|
declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ]
|
||||||
providers: [{ provide: Router, useClass: FakeRouter }]
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -117,3 +103,46 @@ describe('AppComponent & AppModule', () => {
|
||||||
tests();
|
tests();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function tests() {
|
||||||
|
let links: RouterLinkStubDirective[];
|
||||||
|
let linkDes: DebugElement[];
|
||||||
|
|
||||||
|
// #docregion test-setup
|
||||||
|
beforeEach(() => {
|
||||||
|
// trigger initial data binding
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
// find DebugElements with an attached RouterLinkStubDirective
|
||||||
|
linkDes = fixture.debugElement
|
||||||
|
.queryAll(By.directive(RouterLinkStubDirective));
|
||||||
|
|
||||||
|
// get the attached link directive instances using the DebugElement injectors
|
||||||
|
links = linkDes
|
||||||
|
.map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective);
|
||||||
|
});
|
||||||
|
// #enddocregion test-setup
|
||||||
|
|
||||||
|
it('can instantiate it', () => {
|
||||||
|
expect(comp).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
// #docregion tests
|
||||||
|
it('can get RouterLinks from template', () => {
|
||||||
|
expect(links.length).toBe(3, 'should have 3 links');
|
||||||
|
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
|
||||||
|
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can click Heroes link in template', () => {
|
||||||
|
const heroesLinkDe = linkDes[1];
|
||||||
|
const heroesLink = links[1];
|
||||||
|
|
||||||
|
expect(heroesLink.navigatedTo).toBeNull('link should not have navigated yet');
|
||||||
|
|
||||||
|
heroesLinkDe.triggerEventHandler('click', null);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(heroesLink.navigatedTo).toBe('/heroes');
|
||||||
|
});
|
||||||
|
// #docregion tests
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
templateUrl: 'app/app.component.html'
|
templateUrl: 'app/app.component.html'
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
|
||||||
import { AboutComponent } from './about.component';
|
import { AboutComponent } from './about.component';
|
||||||
import { BannerComponent } from './banner.component';
|
import { BannerComponent } from './banner.component';
|
||||||
import { HeroService,
|
import { HeroService,
|
||||||
|
@ -19,11 +19,7 @@ import { SharedModule } from './shared/shared.module';
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
DashboardModule,
|
DashboardModule,
|
||||||
RouterModule.forRoot([
|
AppRoutingModule,
|
||||||
{ path: '', redirectTo: 'dashboard', pathMatch: 'full'},
|
|
||||||
{ path: 'about', component: AboutComponent },
|
|
||||||
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule'}
|
|
||||||
]),
|
|
||||||
SharedModule
|
SharedModule
|
||||||
],
|
],
|
||||||
providers: [ HeroService, TwainService, UserService ],
|
providers: [ HeroService, TwainService, UserService ],
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { NgModel, NgControl } from '@angular/forms';
|
||||||
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick
|
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick
|
||||||
} from '@angular/core/testing';
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { addMatchers, newEvent } from '../../testing';
|
import { addMatchers, newEvent, click } from '../../testing';
|
||||||
|
|
||||||
beforeEach( addMatchers );
|
beforeEach( addMatchers );
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ describe('TestBed Component Tests', () => {
|
||||||
const comp = fixture.componentInstance;
|
const comp = fixture.componentInstance;
|
||||||
const hero = comp.heroes[0];
|
const hero = comp.heroes[0];
|
||||||
|
|
||||||
heroes[0].triggerEventHandler('click', null);
|
click(heroes[0]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const selected = fixture.debugElement.query(By.css('p'));
|
const selected = fixture.debugElement.query(By.css('p'));
|
||||||
|
@ -213,7 +213,7 @@ describe('TestBed Component Tests', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(span.textContent).toMatch(/is off/i, 'before click');
|
expect(span.textContent).toMatch(/is off/i, 'before click');
|
||||||
|
|
||||||
btn.triggerEventHandler('click', null);
|
click(btn);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(span.textContent).toMatch(/is on/i, 'after click');
|
expect(span.textContent).toMatch(/is on/i, 'after click');
|
||||||
});
|
});
|
||||||
|
@ -610,7 +610,7 @@ describe('Lifecycle hooks w/ MyIfParentComp', () => {
|
||||||
getChild();
|
getChild();
|
||||||
|
|
||||||
const btn = fixture.debugElement.query(By.css('button'));
|
const btn = fixture.debugElement.query(By.css('button'));
|
||||||
btn.triggerEventHandler('click', null);
|
click(btn);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(child.ngOnDestroyCalled).toBe(true);
|
expect(child.ngOnDestroyCalled).toBe(true);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { async, ComponentFixture, TestBed
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
import { addMatchers } from '../../testing';
|
import { addMatchers, click } from '../../testing';
|
||||||
|
|
||||||
import { Hero } from '../model/hero';
|
import { Hero } from '../model/hero';
|
||||||
import { DashboardHeroComponent } from './dashboard-hero.component';
|
import { DashboardHeroComponent } from './dashboard-hero.component';
|
||||||
|
@ -53,10 +53,22 @@ describe('DashboardHeroComponent when tested directly', () => {
|
||||||
let selectedHero: Hero;
|
let selectedHero: Hero;
|
||||||
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
|
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
|
||||||
|
|
||||||
|
// #docregion trigger-event-handler
|
||||||
heroEl.triggerEventHandler('click', null);
|
heroEl.triggerEventHandler('click', null);
|
||||||
|
// #enddocregion trigger-event-handler
|
||||||
expect(selectedHero).toBe(expectedHero);
|
expect(selectedHero).toBe(expectedHero);
|
||||||
});
|
});
|
||||||
// #enddocregion click-test
|
// #enddocregion click-test
|
||||||
|
|
||||||
|
// #docregion click-test-2
|
||||||
|
it('should raise selected event when clicked', () => {
|
||||||
|
let selectedHero: Hero;
|
||||||
|
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
|
||||||
|
|
||||||
|
click(heroEl); // triggerEventHandler helper
|
||||||
|
expect(selectedHero).toBe(expectedHero);
|
||||||
|
});
|
||||||
|
// #enddocregion click-test-2
|
||||||
});
|
});
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
|
@ -89,7 +101,7 @@ describe('DashboardHeroComponent when inside a test host', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should raise selected event when clicked', () => {
|
it('should raise selected event when clicked', () => {
|
||||||
heroEl.triggerEventHandler('click', null);
|
click(heroEl);
|
||||||
// selected hero should be the same data bound hero
|
// selected hero should be the same data bound hero
|
||||||
expect(testHost.selectedHero).toBe(testHost.hero);
|
expect(testHost.selectedHero).toBe(testHost.hero);
|
||||||
});
|
});
|
||||||
|
@ -102,8 +114,7 @@ import { Component } from '@angular/core';
|
||||||
// #docregion test-host
|
// #docregion test-host
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<dashboard-hero [hero]="hero" (selected)="onSelected($event)">
|
<dashboard-hero [hero]="hero" (selected)="onSelected($event)"></dashboard-hero>`
|
||||||
</dashboard-hero>`
|
|
||||||
})
|
})
|
||||||
class TestHostComponent {
|
class TestHostComponent {
|
||||||
hero = new Hero(42, 'Test Name');
|
hero = new Hero(42, 'Test Name');
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
import { async, inject, ComponentFixture, TestBed
|
import { async, inject, ComponentFixture, TestBed
|
||||||
} from '@angular/core/testing';
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { addMatchers } from '../../testing';
|
import { addMatchers, click } from '../../testing';
|
||||||
import { HeroService } from '../model';
|
import { HeroService } from '../model';
|
||||||
import { FakeHeroService } from '../model/testing';
|
import { FakeHeroService } from '../model/testing';
|
||||||
|
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
@ -12,11 +12,11 @@ import { Router } from '@angular/router';
|
||||||
import { DashboardComponent } from './dashboard.component';
|
import { DashboardComponent } from './dashboard.component';
|
||||||
import { DashboardModule } from './dashboard.module';
|
import { DashboardModule } from './dashboard.module';
|
||||||
|
|
||||||
// #docregion fake-router
|
// #docregion router-stub
|
||||||
class FakeRouter {
|
class RouterStub {
|
||||||
navigateByUrl(url: string) { return url; }
|
navigateByUrl(url: string) { return url; }
|
||||||
}
|
}
|
||||||
// #enddocregion fake-router
|
// #enddocregion router-stub
|
||||||
|
|
||||||
beforeEach ( addMatchers );
|
beforeEach ( addMatchers );
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ describe('DashboardComponent (deep)', () => {
|
||||||
function clickForDeep() {
|
function clickForDeep() {
|
||||||
// get first <div class="hero"> DebugElement
|
// get first <div class="hero"> DebugElement
|
||||||
const heroEl = fixture.debugElement.query(By.css('.hero'));
|
const heroEl = fixture.debugElement.query(By.css('.hero'));
|
||||||
heroEl.triggerEventHandler('click', null);
|
click(heroEl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ function compileAndCreate() {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: HeroService, useClass: FakeHeroService },
|
{ provide: HeroService, useClass: FakeHeroService },
|
||||||
{ provide: Router, useClass: FakeRouter }
|
{ provide: Router, useClass: RouterStub }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents().then(() => {
|
.compileComponents().then(() => {
|
||||||
|
|
|
@ -7,10 +7,7 @@ import { Hero, HeroService } from '../model';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
templateUrl: 'app/dashboard/dashboard.component.html',
|
templateUrl: 'app/dashboard/dashboard.component.html',
|
||||||
styleUrls: [
|
styleUrls: ['app/dashboard/dashboard.component.css']
|
||||||
'app/shared/styles.css',
|
|
||||||
'app/dashboard/dashboard.component.css'
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class DashboardComponent implements OnInit {
|
export class DashboardComponent implements OnInit {
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
<!-- #docregion -->
|
||||||
<div *ngIf="hero">
|
<div *ngIf="hero">
|
||||||
<h2><span>{{hero.name | titlecase}}</span> Details</h2>
|
<h2><span>{{hero.name | titlecase}}</span> Details</h2>
|
||||||
<div>
|
<div>
|
||||||
<label>id: </label>{{hero.id}}</div>
|
<label>id: </label>{{hero.id}}</div>
|
||||||
<div>
|
<div>
|
||||||
<label>name: </label>
|
<label for="name">name: </label>
|
||||||
<input [(ngModel)]="hero.name" placeholder="name" />
|
<input id="name" [(ngModel)]="hero.name" placeholder="name" />
|
||||||
</div>
|
</div>
|
||||||
<button (click)="save()">Save</button>
|
<button (click)="save()">Save</button>
|
||||||
<button (click)="cancel()">Cancel</button>
|
<button (click)="cancel()">Cancel</button>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { HeroDetailComponent } from './hero-detail.component';
|
import { HeroDetailComponent } from './hero-detail.component';
|
||||||
import { Hero } from '../model';
|
import { Hero } from '../model';
|
||||||
|
|
||||||
import { FakeActivatedRoute } from '../../testing';
|
import { ActivatedRouteStub } from '../../testing';
|
||||||
|
|
||||||
////////// Tests ////////////////////
|
////////// Tests ////////////////////
|
||||||
|
|
||||||
describe('HeroDetailComponent - no TestBed', () => {
|
describe('HeroDetailComponent - no TestBed', () => {
|
||||||
let activatedRoute: FakeActivatedRoute;
|
let activatedRoute: ActivatedRouteStub;
|
||||||
let comp: HeroDetailComponent;
|
let comp: HeroDetailComponent;
|
||||||
let expectedHero: Hero;
|
let expectedHero: Hero;
|
||||||
let hds: any;
|
let hds: any;
|
||||||
|
@ -14,7 +14,7 @@ describe('HeroDetailComponent - no TestBed', () => {
|
||||||
|
|
||||||
beforeEach( done => {
|
beforeEach( done => {
|
||||||
expectedHero = new Hero(42, 'Bubba');
|
expectedHero = new Hero(42, 'Bubba');
|
||||||
activatedRoute = new FakeActivatedRoute();
|
activatedRoute = new ActivatedRouteStub();
|
||||||
activatedRoute.testParams = { id: expectedHero.id };
|
activatedRoute.testParams = { id: expectedHero.id };
|
||||||
|
|
||||||
router = jasmine.createSpyObj('router', ['navigate']);
|
router = jasmine.createSpyObj('router', ['navigate']);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// #docplaster
|
||||||
import {
|
import {
|
||||||
async, ComponentFixture, fakeAsync, inject, TestBed, tick
|
async, ComponentFixture, fakeAsync, inject, TestBed, tick
|
||||||
} from '@angular/core/testing';
|
} from '@angular/core/testing';
|
||||||
|
@ -6,100 +7,197 @@ import { By } from '@angular/platform-browser';
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addMatchers, newEvent,
|
ActivatedRoute, ActivatedRouteStub, click, newEvent, Router, RouterStub
|
||||||
ActivatedRoute, FakeActivatedRoute, Router, FakeRouter
|
|
||||||
} from '../../testing';
|
} from '../../testing';
|
||||||
|
|
||||||
import { HEROES, FakeHeroService } from '../model/testing';
|
import { Hero } from '../model';
|
||||||
|
|
||||||
import { HeroModule } from './hero.module';
|
|
||||||
import { HeroDetailComponent } from './hero-detail.component';
|
import { HeroDetailComponent } from './hero-detail.component';
|
||||||
import { HeroDetailService } from './hero-detail.service';
|
import { HeroDetailService } from './hero-detail.service';
|
||||||
import { Hero, HeroService } from '../model';
|
import { HeroModule } from './hero.module';
|
||||||
|
|
||||||
////// Testing Vars //////
|
////// Testing Vars //////
|
||||||
let activatedRoute: FakeActivatedRoute;
|
let activatedRoute: ActivatedRouteStub;
|
||||||
let comp: HeroDetailComponent;
|
let comp: HeroDetailComponent;
|
||||||
let fixture: ComponentFixture<HeroDetailComponent>;
|
let fixture: ComponentFixture<HeroDetailComponent>;
|
||||||
let page: Page;
|
let page: Page;
|
||||||
|
|
||||||
////////// Tests ////////////////////
|
////// Tests //////
|
||||||
|
|
||||||
describe('HeroDetailComponent', () => {
|
describe('HeroDetailComponent', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
activatedRoute = new ActivatedRouteStub();
|
||||||
|
});
|
||||||
|
describe('with HeroModule setup', heroModuleSetup);
|
||||||
|
describe('when override its provided HeroDetailService', overrideSetup);
|
||||||
|
describe('with FormsModule setup', formsModuleSetup);
|
||||||
|
describe('with SharedModule setup', sharedModuleSetup);
|
||||||
|
});
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
function overrideSetup() {
|
||||||
|
// #docregion stub-hds
|
||||||
|
class StubHeroDetailService {
|
||||||
|
testHero = new Hero(42, 'Test Hero');
|
||||||
|
|
||||||
|
getHero(id: number | string): Promise<Hero> {
|
||||||
|
return Promise.resolve(true).then(() => Object.assign({}, this.testHero) );
|
||||||
|
}
|
||||||
|
|
||||||
|
saveHero(hero: Hero): Promise<Hero> {
|
||||||
|
return Promise.resolve(true).then(() => Object.assign(this.testHero, hero) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion stub-hds
|
||||||
|
|
||||||
|
// the `id` value is irrelevant because ignored by service stub
|
||||||
|
beforeEach(() => activatedRoute.testParams = { id: 99999 } );
|
||||||
|
|
||||||
|
// #docregion setup-override
|
||||||
|
beforeEach( async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ HeroModule ],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: Router, useClass: RouterStub},
|
||||||
|
// #enddocregion setup-override
|
||||||
|
// HeroDetailService at this level is IRRELEVANT!
|
||||||
|
{ provide: HeroDetailService, useValue: {} }
|
||||||
|
// #docregion setup-override
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Override component's own provider
|
||||||
|
// #docregion override-component-method
|
||||||
|
.overrideComponent(HeroDetailComponent, {
|
||||||
|
set: {
|
||||||
|
providers: [
|
||||||
|
{ provide: HeroDetailService, useClass: StubHeroDetailService }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #enddocregion override-component-method
|
||||||
|
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
// #enddocregion setup-override
|
||||||
|
|
||||||
|
// #docregion override-tests
|
||||||
|
let hds: StubHeroDetailService;
|
||||||
|
|
||||||
beforeEach( async(() => {
|
beforeEach( async(() => {
|
||||||
addMatchers();
|
createComponent();
|
||||||
activatedRoute = new FakeActivatedRoute();
|
// get the component's injected StubHeroDetailService
|
||||||
|
hds = fixture.debugElement.injector.get(HeroDetailService);
|
||||||
|
}));
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
it('should display stub hero\'s name', () => {
|
||||||
imports: [ HeroModule ],
|
expect(page.nameDisplay.textContent).toBe(hds.testHero.name);
|
||||||
|
});
|
||||||
|
|
||||||
// DON'T RE-DECLARE because already declared in HeroModule
|
it('should save stub hero change', fakeAsync(() => {
|
||||||
// declarations: [HeroDetailComponent, TitleCasePipe], // No!
|
const origName = hds.testHero.name;
|
||||||
|
const newName = 'New Name';
|
||||||
|
|
||||||
|
page.nameInput.value = newName;
|
||||||
|
page.nameInput.dispatchEvent(newEvent('input')); // tell Angular
|
||||||
|
|
||||||
|
expect(comp.hero.name).toBe(newName, 'component hero has new name');
|
||||||
|
expect(hds.testHero.name).toBe(origName, 'service hero unchanged before save');
|
||||||
|
|
||||||
|
click(page.saveBtn);
|
||||||
|
tick(); // wait for async save to complete
|
||||||
|
expect(hds.testHero.name).toBe(newName, 'service hero has new name after save');
|
||||||
|
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
||||||
|
}));
|
||||||
|
// #enddocregion override-tests
|
||||||
|
|
||||||
|
it('fixture injected service is not the component injected service',
|
||||||
|
inject([HeroDetailService], (service: HeroDetailService) => {
|
||||||
|
|
||||||
|
expect(service).toEqual({}, 'service injected from fixture');
|
||||||
|
expect(hds).toBeTruthy('service injected into component');
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
import { HEROES, FakeHeroService } from '../model/testing';
|
||||||
|
import { HeroService } from '../model';
|
||||||
|
|
||||||
|
const firstHero = HEROES[0];
|
||||||
|
|
||||||
|
function heroModuleSetup() {
|
||||||
|
// #docregion setup-hero-module
|
||||||
|
beforeEach( async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ HeroModule ],
|
||||||
|
// #enddocregion setup-hero-module
|
||||||
|
// declarations: [ HeroDetailComponent ], // NO! DOUBLE DECLARATION
|
||||||
|
// #docregion setup-hero-module
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
{ provide: HeroService, useClass: FakeHeroService },
|
{ provide: HeroService, useClass: FakeHeroService },
|
||||||
{ provide: Router, useClass: FakeRouter},
|
{ provide: Router, useClass: RouterStub},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
// #enddocregion setup-hero-module
|
||||||
|
|
||||||
describe('when navigate to hero id=' + HEROES[0].id, () => {
|
// #docregion route-good-id
|
||||||
|
describe('when navigate to existing hero', () => {
|
||||||
let expectedHero: Hero;
|
let expectedHero: Hero;
|
||||||
|
|
||||||
beforeEach( async(() => {
|
beforeEach( async(() => {
|
||||||
expectedHero = HEROES[0];
|
expectedHero = firstHero;
|
||||||
activatedRoute.testParams = { id: expectedHero.id };
|
activatedRoute.testParams = { id: expectedHero.id };
|
||||||
createComponent();
|
createComponent();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// #docregion selected-tests
|
||||||
it('should display that hero\'s name', () => {
|
it('should display that hero\'s name', () => {
|
||||||
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
||||||
});
|
});
|
||||||
|
// #enddocregion route-good-id
|
||||||
|
|
||||||
it('should navigate when click cancel', () => {
|
it('should navigate when click cancel', () => {
|
||||||
page.cancelBtn.triggerEventHandler('click', null);
|
click(page.cancelBtn);
|
||||||
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should save when click save', () => {
|
it('should save when click save but not navigate immediately', () => {
|
||||||
page.saveBtn.triggerEventHandler('click', null);
|
click(page.saveBtn);
|
||||||
expect(page.saveSpy.calls.any()).toBe(true, 'HeroDetailService.save called');
|
expect(page.saveSpy.calls.any()).toBe(true, 'HeroDetailService.save called');
|
||||||
|
expect(page.navSpy.calls.any()).toBe(false, 'router.navigate not called');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate when click click save resolves', fakeAsync(() => {
|
it('should navigate when click save and save resolves', fakeAsync(() => {
|
||||||
page.saveBtn.triggerEventHandler('click', null);
|
click(page.saveBtn);
|
||||||
tick(); // waits for async save to "complete" before navigating
|
tick(); // wait for async save to complete
|
||||||
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
// #docregion title-case-pipe
|
// #docregion title-case-pipe
|
||||||
it('should convert original hero name to Title Case', () => {
|
|
||||||
expect(page.nameDisplay.textContent).toBe(comp.hero.name);
|
|
||||||
});
|
|
||||||
// #enddocregion title-case-pipe
|
|
||||||
|
|
||||||
it('should convert hero name to Title Case', fakeAsync(() => {
|
it('should convert hero name to Title Case', fakeAsync(() => {
|
||||||
const inputName = 'quick BROWN fox';
|
const inputName = 'quick BROWN fox';
|
||||||
const expectedName = 'Quick Brown Fox';
|
const titleCaseName = 'Quick Brown Fox';
|
||||||
|
|
||||||
// simulate user entering new name in input
|
// simulate user entering new name into the input box
|
||||||
page.nameInput.value = inputName;
|
page.nameInput.value = inputName;
|
||||||
|
|
||||||
// dispatch a DOM event so that Angular learns of input value change.
|
// dispatch a DOM event so that Angular learns of input value change.
|
||||||
// detectChanges() makes ngModel push input value to component property
|
|
||||||
// and Angular updates the output span
|
|
||||||
page.nameInput.dispatchEvent(newEvent('input'));
|
page.nameInput.dispatchEvent(newEvent('input'));
|
||||||
|
|
||||||
|
// Tell Angular to update the output span through the title pipe
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(page.nameDisplay.textContent).toBe(expectedName, 'hero name display');
|
|
||||||
expect(comp.hero.name).toBe(inputName, 'comp.hero.name');
|
expect(page.nameDisplay.textContent).toBe(titleCaseName);
|
||||||
}));
|
}));
|
||||||
|
// #enddocregion title-case-pipe
|
||||||
|
// #enddocregion selected-tests
|
||||||
|
// #docregion route-good-id
|
||||||
});
|
});
|
||||||
|
// #enddocregion route-good-id
|
||||||
|
|
||||||
|
// #docregion route-no-id
|
||||||
describe('when navigate with no hero id', () => {
|
describe('when navigate with no hero id', () => {
|
||||||
beforeEach( async( createComponent ));
|
beforeEach( async( createComponent ));
|
||||||
|
|
||||||
|
@ -111,7 +209,9 @@ describe('HeroDetailComponent', () => {
|
||||||
expect(page.nameDisplay.textContent).toBe('');
|
expect(page.nameDisplay.textContent).toBe('');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// #enddocregion route-no-id
|
||||||
|
|
||||||
|
// #docregion route-bad-id
|
||||||
describe('when navigate to non-existant hero id', () => {
|
describe('when navigate to non-existant hero id', () => {
|
||||||
beforeEach( async(() => {
|
beforeEach( async(() => {
|
||||||
activatedRoute.testParams = { id: 99999 };
|
activatedRoute.testParams = { id: 99999 };
|
||||||
|
@ -123,11 +223,10 @@ describe('HeroDetailComponent', () => {
|
||||||
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// #enddocregion route-bad-id
|
||||||
///////////////////////////
|
|
||||||
|
|
||||||
// Why we must use `fixture.debugElement.injector` in `Page()`
|
// Why we must use `fixture.debugElement.injector` in `Page()`
|
||||||
it('cannot use `inject` to get component\'s provided service', () => {
|
it('cannot use `inject` to get component\'s provided HeroDetailService', () => {
|
||||||
let service: HeroDetailService;
|
let service: HeroDetailService;
|
||||||
fixture = TestBed.createComponent(HeroDetailComponent);
|
fixture = TestBed.createComponent(HeroDetailComponent);
|
||||||
expect(
|
expect(
|
||||||
|
@ -141,26 +240,85 @@ describe('HeroDetailComponent', () => {
|
||||||
service = fixture.debugElement.injector.get(HeroDetailService);
|
service = fixture.debugElement.injector.get(HeroDetailService);
|
||||||
expect(service).toBeDefined('debugElement.injector');
|
expect(service).toBeDefined('debugElement.injector');
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { TitleCasePipe } from '../shared/title-case.pipe';
|
||||||
|
|
||||||
|
function formsModuleSetup() {
|
||||||
|
// #docregion setup-forms-module
|
||||||
|
beforeEach( async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ FormsModule ],
|
||||||
|
declarations: [ HeroDetailComponent, TitleCasePipe ],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: HeroService, useClass: FakeHeroService },
|
||||||
|
{ provide: Router, useClass: RouterStub},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
// #enddocregion setup-forms-module
|
||||||
|
|
||||||
|
it('should display 1st hero\'s name', fakeAsync(() => {
|
||||||
|
const expectedHero = firstHero;
|
||||||
|
activatedRoute.testParams = { id: expectedHero.id };
|
||||||
|
createComponent().then(() => {
|
||||||
|
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
|
||||||
|
function sharedModuleSetup() {
|
||||||
|
// #docregion setup-shared-module
|
||||||
|
beforeEach( async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ SharedModule ],
|
||||||
|
declarations: [ HeroDetailComponent ],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: HeroService, useClass: FakeHeroService },
|
||||||
|
{ provide: Router, useClass: RouterStub},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
// #enddocregion setup-shared-module
|
||||||
|
|
||||||
|
it('should display 1st hero\'s name', fakeAsync(() => {
|
||||||
|
const expectedHero = firstHero;
|
||||||
|
activatedRoute.testParams = { id: expectedHero.id };
|
||||||
|
createComponent().then(() => {
|
||||||
|
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
/////////// Helpers /////
|
/////////// Helpers /////
|
||||||
|
|
||||||
|
// #docregion create-component
|
||||||
/** Create the HeroDetailComponent, initialize it, set test variables */
|
/** Create the HeroDetailComponent, initialize it, set test variables */
|
||||||
function createComponent() {
|
function createComponent() {
|
||||||
fixture = TestBed.createComponent(HeroDetailComponent);
|
fixture = TestBed.createComponent(HeroDetailComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
page = new Page();
|
page = new Page();
|
||||||
|
|
||||||
// change detection triggers ngOnInit which gets a hero
|
// 1st change detection triggers ngOnInit which gets a hero
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
return fixture.whenStable().then(() => {
|
return fixture.whenStable().then(() => {
|
||||||
// got the hero and updated component
|
// 2nd change detection displays the async-fetched hero
|
||||||
// change detection updates the view
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
page.addPageElements();
|
page.addPageElements();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// #enddocregion create-component
|
||||||
|
|
||||||
|
// #docregion page
|
||||||
class Page {
|
class Page {
|
||||||
gotoSpy: jasmine.Spy;
|
gotoSpy: jasmine.Spy;
|
||||||
navSpy: jasmine.Spy;
|
navSpy: jasmine.Spy;
|
||||||
|
@ -173,19 +331,20 @@ class Page {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Use component's injector to see the services it injected.
|
// Use component's injector to see the services it injected.
|
||||||
let compInjector = fixture.debugElement.injector;
|
const compInjector = fixture.debugElement.injector;
|
||||||
let hds = compInjector.get(HeroDetailService);
|
const hds = compInjector.get(HeroDetailService);
|
||||||
let router = compInjector.get(Router);
|
const router = compInjector.get(Router);
|
||||||
this.gotoSpy = spyOn(comp, 'gotoList').and.callThrough();
|
|
||||||
this.saveSpy = spyOn(hds, 'saveHero').and.callThrough();
|
this.gotoSpy = spyOn(comp, 'gotoList').and.callThrough();
|
||||||
this.navSpy = spyOn(router, 'navigate').and.callThrough();
|
this.navSpy = spyOn(router, 'navigate');
|
||||||
|
this.saveSpy = spyOn(hds, 'saveHero').and.callThrough();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add page elements after page initializes */
|
/** Add page elements after hero arrives */
|
||||||
addPageElements() {
|
addPageElements() {
|
||||||
if (comp.hero) {
|
if (comp.hero) {
|
||||||
// have a hero so these DOM elements can be reached
|
// have a hero so these elements are now in the DOM
|
||||||
let buttons = fixture.debugElement.queryAll(By.css('button'));
|
const buttons = fixture.debugElement.queryAll(By.css('button'));
|
||||||
this.saveBtn = buttons[0];
|
this.saveBtn = buttons[0];
|
||||||
this.cancelBtn = buttons[1];
|
this.cancelBtn = buttons[1];
|
||||||
this.nameDisplay = fixture.debugElement.query(By.css('span')).nativeElement;
|
this.nameDisplay = fixture.debugElement.query(By.css('span')).nativeElement;
|
||||||
|
@ -193,4 +352,4 @@ class Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// #enddocregion page
|
||||||
|
|
|
@ -1,46 +1,51 @@
|
||||||
|
/* tslint:disable:member-ordering */
|
||||||
|
// #docplaster
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import 'rxjs/add/operator/pluck';
|
||||||
|
|
||||||
import { Hero } from '../model';
|
import { Hero } from '../model';
|
||||||
import { HeroDetailService } from './hero-detail.service';
|
import { HeroDetailService } from './hero-detail.service';
|
||||||
|
|
||||||
|
// #docregion prototype
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero-detail',
|
selector: 'app-hero-detail',
|
||||||
templateUrl: 'app/hero/hero-detail.component.html',
|
templateUrl: 'app/hero/hero-detail.component.html',
|
||||||
styleUrls: [
|
styleUrls: ['app/hero/hero-detail.component.css'],
|
||||||
'app/shared/styles.css',
|
|
||||||
'app/hero/hero-detail.component.css'
|
|
||||||
],
|
|
||||||
providers: [ HeroDetailService ]
|
providers: [ HeroDetailService ]
|
||||||
})
|
})
|
||||||
export class HeroDetailComponent implements OnInit {
|
export class HeroDetailComponent implements OnInit {
|
||||||
@Input() hero: Hero;
|
// #docregion ctor
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private heroDetailService: HeroDetailService,
|
private heroDetailService: HeroDetailService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router) {
|
private router: Router) {
|
||||||
}
|
}
|
||||||
|
// #enddocregion ctor
|
||||||
|
// #enddocregion prototype
|
||||||
|
|
||||||
ngOnInit() {
|
@Input() hero: Hero;
|
||||||
let id = this.route.snapshot.params['id'];
|
|
||||||
|
|
||||||
// tslint:disable-next-line:triple-equals
|
// #docregion ng-on-init
|
||||||
if (id == undefined) {
|
ngOnInit(): void {
|
||||||
// no id; act as if is new
|
// get hero when `id` param changes
|
||||||
this.hero = new Hero();
|
this.route.params.pluck<string>('id')
|
||||||
} else {
|
.forEach(id => this.getHero(id))
|
||||||
this.heroDetailService.getHero(id).then(hero => {
|
.catch(() => this.hero = new Hero()); // no id; should edit new hero
|
||||||
if (hero) {
|
}
|
||||||
this.hero = hero;
|
// #enddocregion ng-on-init
|
||||||
} else {
|
|
||||||
this.gotoList(); // id not found; navigate to list
|
private getHero(id: string): void {
|
||||||
}
|
this.heroDetailService.getHero(id).then(hero => {
|
||||||
});
|
if (hero) {
|
||||||
}
|
this.hero = hero;
|
||||||
|
} else {
|
||||||
|
this.gotoList(); // id not found; navigate to list
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save(): void {
|
||||||
this.heroDetailService.saveHero(this.hero).then(() => this.gotoList());
|
this.heroDetailService.saveHero(this.hero).then(() => this.gotoList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,4 +54,6 @@ export class HeroDetailComponent implements OnInit {
|
||||||
gotoList() {
|
gotoList() {
|
||||||
this.router.navigate(['../'], {relativeTo: this.route});
|
this.router.navigate(['../'], {relativeTo: this.route});
|
||||||
}
|
}
|
||||||
|
// #docregion prototype
|
||||||
}
|
}
|
||||||
|
// #enddocregion prototype
|
||||||
|
|
|
@ -2,10 +2,13 @@ import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { Hero, HeroService } from '../model';
|
import { Hero, HeroService } from '../model';
|
||||||
|
|
||||||
|
// #docregion prototype
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HeroDetailService {
|
export class HeroDetailService {
|
||||||
constructor(private heroService: HeroService) { }
|
constructor(private heroService: HeroService) { }
|
||||||
|
// #enddocregion prototype
|
||||||
|
|
||||||
|
// Returns a clone which caller may modify safely
|
||||||
getHero(id: number | string): Promise<Hero> {
|
getHero(id: number | string): Promise<Hero> {
|
||||||
if (typeof id === 'string') {
|
if (typeof id === 'string') {
|
||||||
id = parseInt(id as string, 10);
|
id = parseInt(id as string, 10);
|
||||||
|
@ -18,4 +21,6 @@ export class HeroDetailService {
|
||||||
saveHero(hero: Hero) {
|
saveHero(hero: Hero) {
|
||||||
return this.heroService.updateHero(hero);
|
return this.heroService.updateHero(hero);
|
||||||
}
|
}
|
||||||
|
// #docregion prototype
|
||||||
}
|
}
|
||||||
|
// #enddocregion prototype
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { async, ComponentFixture, fakeAsync, TestBed, tick
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
import { addMatchers, newEvent, Router, FakeRouter
|
import { addMatchers, newEvent, Router, RouterStub
|
||||||
} from '../../testing';
|
} from '../../testing';
|
||||||
|
|
||||||
import { HEROES, FakeHeroService } from '../model/testing';
|
import { HEROES, FakeHeroService } from '../model/testing';
|
||||||
|
@ -28,7 +28,7 @@ describe('HeroListComponent', () => {
|
||||||
imports: [HeroModule],
|
imports: [HeroModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: HeroService, useClass: FakeHeroService },
|
{ provide: HeroService, useClass: FakeHeroService },
|
||||||
{ provide: Router, useClass: FakeRouter}
|
{ provide: Router, useClass: RouterStub}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents()
|
.compileComponents()
|
||||||
|
@ -132,7 +132,7 @@ class Page {
|
||||||
|
|
||||||
// Get the component's injected router and spy on it
|
// Get the component's injected router and spy on it
|
||||||
const router = fixture.debugElement.injector.get(Router);
|
const router = fixture.debugElement.injector.get(Router);
|
||||||
this.navSpy = spyOn(router, 'navigate').and.callThrough();
|
this.navSpy = spyOn(router, 'navigate');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,7 @@ import { Hero, HeroService } from '../model';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-heroes',
|
selector: 'app-heroes',
|
||||||
templateUrl: 'app/hero/hero-list.component.html',
|
templateUrl: 'app/hero/hero-list.component.html',
|
||||||
styleUrls: [
|
styleUrls: ['app/hero/hero-list.component.css']
|
||||||
'app/shared/styles.css',
|
|
||||||
'app/hero/hero-list.component.css'
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class HeroListComponent implements OnInit {
|
export class HeroListComponent implements OnInit {
|
||||||
heroes: Promise<Hero[]>;
|
heroes: Promise<Hero[]>;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Hero } from './hero';
|
||||||
import { HEROES } from './test-heroes';
|
import { HEROES } from './test-heroes';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
/** Dummy HeroService that pretends to be real */
|
/** Dummy HeroService. Pretend it makes real http requests */
|
||||||
export class HeroService {
|
export class HeroService {
|
||||||
getHeroes() {
|
getHeroes() {
|
||||||
return Promise.resolve(HEROES);
|
return Promise.resolve(HEROES);
|
||||||
|
@ -21,9 +21,10 @@ export class HeroService {
|
||||||
|
|
||||||
updateHero(hero: Hero): Promise<Hero> {
|
updateHero(hero: Hero): Promise<Hero> {
|
||||||
return this.getHero(hero.id).then(h => {
|
return this.getHero(hero.id).then(h => {
|
||||||
return h ?
|
if (!h) {
|
||||||
Object.assign(h, hero) :
|
throw new Error(`Hero ${hero.id} not found`);
|
||||||
Promise.reject(`Hero ${hero.id} not found`) as any as Promise<Hero>;
|
}
|
||||||
|
return Object.assign(h, hero);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +1,100 @@
|
||||||
import { Component, DebugElement } from '@angular/core';
|
import { Component, DebugElement } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { HighlightDirective } from './highlight.directive';
|
import { HighlightDirective } from './highlight.directive';
|
||||||
|
import { newEvent } from '../../testing';
|
||||||
|
|
||||||
// Component to test directive
|
// #docregion test-component
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<h2 highlight="yellow">Something Yellow</h2>
|
<h2 highlight="yellow">Something Yellow</h2>
|
||||||
<h2 highlight>Something Gray</h2>
|
<h2 highlight>The Default (Gray)</h2>
|
||||||
<h2>Something White</h2>
|
<h2>No Highlight</h2>
|
||||||
`
|
<input #box [highlight]="box.value" value="cyan"/>`
|
||||||
|
|
||||||
})
|
})
|
||||||
class TestComponent { }
|
class TestComponent { }
|
||||||
|
// #enddocregion test-component
|
||||||
|
|
||||||
////// Tests //////////
|
|
||||||
describe('HighlightDirective', () => {
|
describe('HighlightDirective', () => {
|
||||||
|
|
||||||
let fixture: ComponentFixture<TestComponent>;
|
let fixture: ComponentFixture<TestComponent>;
|
||||||
let h2Des: DebugElement[];
|
let des: DebugElement[]; // the three elements w/ the directive
|
||||||
|
let bareH2: DebugElement; // the <h2> w/o the directive
|
||||||
|
|
||||||
|
// #docregion selected-tests
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.configureTestingModule({
|
fixture = TestBed.configureTestingModule({
|
||||||
declarations: [ HighlightDirective, TestComponent ]
|
declarations: [ HighlightDirective, TestComponent ]
|
||||||
})
|
})
|
||||||
.createComponent(TestComponent);
|
.createComponent(TestComponent);
|
||||||
|
|
||||||
h2Des = fixture.debugElement.queryAll(By.css('h2'));
|
fixture.detectChanges(); // initial binding
|
||||||
|
|
||||||
|
// all elements with an attached HighlightDirective
|
||||||
|
des = fixture.debugElement.queryAll(By.directive(HighlightDirective));
|
||||||
|
|
||||||
|
// the h2 without the HighlightDirective
|
||||||
|
bareH2 = fixture.debugElement.query(By.css('h2:not([highlight])'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have `HighlightDirective`', () => {
|
// color tests
|
||||||
// The HighlightDirective listed in <h2> tokens means it is attached
|
it('should have three highlighted elements', () => {
|
||||||
expect(h2Des[0].providerTokens).toContain(HighlightDirective, 'HighlightDirective');
|
expect(des.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should color first <h2> background "yellow"', () => {
|
it('should color 1st <h2> background "yellow"', () => {
|
||||||
fixture.detectChanges();
|
expect(des[0].styles['backgroundColor']).toBe('yellow');
|
||||||
const h2 = h2Des[0].nativeElement as HTMLElement;
|
|
||||||
expect(h2.style.backgroundColor).toBe('yellow');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should color second <h2> background w/ default color', () => {
|
it('should color 2nd <h2> background w/ default color', () => {
|
||||||
fixture.detectChanges();
|
const dir = des[1].injector.get(HighlightDirective) as HighlightDirective;
|
||||||
const h2 = h2Des[1].nativeElement as HTMLElement;
|
expect(des[1].styles['backgroundColor']).toBe(dir.defaultColor);
|
||||||
expect(h2.style.backgroundColor).toBe(HighlightDirective.defaultColor);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT color third <h2> (no directive)', () => {
|
it('should bind <input> background to value color', () => {
|
||||||
// no directive
|
// easier to work with nativeElement
|
||||||
expect(h2Des[2].providerTokens).not.toContain(HighlightDirective, 'HighlightDirective');
|
const input = des[2].nativeElement as HTMLInputElement;
|
||||||
|
expect(input.style.backgroundColor).toBe('cyan', 'initial backgroundColor');
|
||||||
|
|
||||||
|
// dispatch a DOM event so that Angular responds to the input value change.
|
||||||
|
input.value = 'green';
|
||||||
|
input.dispatchEvent(newEvent('input'));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const h2 = h2Des[2].nativeElement as HTMLElement;
|
expect(input.style.backgroundColor).toBe('green', 'changed backgroundColor');
|
||||||
expect(h2.style.backgroundColor).toBe('', 'backgroundColor');
|
});
|
||||||
|
|
||||||
|
// customProperty tests
|
||||||
|
it('all highlighted elements should have a true customProperty', () => {
|
||||||
|
const allTrue = des.map(de => !!de.properties['customProperty']).every(v => v === true);
|
||||||
|
expect(allTrue).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('bare <h2> should not have a customProperty', () => {
|
||||||
|
expect(bareH2.properties['customProperty']).toBeUndefined();
|
||||||
|
});
|
||||||
|
// #enddocregion selected-tests
|
||||||
|
|
||||||
|
// injected directive
|
||||||
|
// attached HighlightDirective can be injected
|
||||||
|
it('can inject `HighlightDirective` in 1st <h2>', () => {
|
||||||
|
const dir = des[0].injector.get(HighlightDirective);
|
||||||
|
expect(dir).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cannot inject `HighlightDirective` in 3rd <h2>', () => {
|
||||||
|
const dir = bareH2.injector.get(HighlightDirective, null);
|
||||||
|
expect(dir).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
// DebugElement.providerTokens
|
||||||
|
// attached HighlightDirective should be listed in the providerTokens
|
||||||
|
it('should have `HighlightDirective` in 1st <h2> providerTokens', () => {
|
||||||
|
expect(des[0].providerTokens).toContain(HighlightDirective);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not have `HighlightDirective` in 3rd <h2> providerTokens', () => {
|
||||||
|
expect(bareH2.providerTokens).not.toContain(HighlightDirective);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
|
// #docregion
|
||||||
import { Directive, ElementRef, Input, OnChanges, Renderer } from '@angular/core';
|
import { Directive, ElementRef, Input, OnChanges, Renderer } from '@angular/core';
|
||||||
|
|
||||||
@Directive({ selector: '[highlight]' })
|
@Directive({ selector: '[highlight]' })
|
||||||
/**
|
/** Set backgroundColor for the attached element to highlight color
|
||||||
* Set backgroundColor for the attached element ton highlight color and
|
* and set the element's customProperty to true */
|
||||||
* set element `customProperty` = true
|
|
||||||
*/
|
|
||||||
export class HighlightDirective implements OnChanges {
|
export class HighlightDirective implements OnChanges {
|
||||||
|
|
||||||
static defaultColor = 'rgb(211, 211, 211)'; // lightgray
|
defaultColor = 'rgb(211, 211, 211)'; // lightgray
|
||||||
|
|
||||||
@Input('highlight') bgColor: string;
|
@Input('highlight') bgColor: string;
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ export class HighlightDirective implements OnChanges {
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.renderer.setElementStyle(
|
this.renderer.setElementStyle(
|
||||||
this.el.nativeElement, 'backgroundColor',
|
this.el.nativeElement, 'backgroundColor',
|
||||||
this.bgColor || HighlightDirective.defaultColor );
|
this.bgColor || this.defaultColor );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
/* MISSING */
|
|
|
@ -13,15 +13,20 @@ describe('WelcomeComponent', () => {
|
||||||
let userService: UserService; // the actually injected service
|
let userService: UserService; // the actually injected service
|
||||||
let welcomeEl: DebugElement; // the element with the welcome message
|
let welcomeEl: DebugElement; // the element with the welcome message
|
||||||
|
|
||||||
|
let userServiceStub: {
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
user: { name: string}
|
||||||
|
};
|
||||||
|
|
||||||
// #docregion setup
|
// #docregion setup
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// fake UserService for test purposes
|
// stub UserService for test purposes
|
||||||
// #docregion fake-userservice
|
// #docregion user-service-stub
|
||||||
const fakeUserService = {
|
userServiceStub = {
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
user: { name: 'Test User'}
|
user: { name: 'Test User'}
|
||||||
};
|
};
|
||||||
// #enddocregion fake-userservice
|
// #enddocregion user-service-stub
|
||||||
|
|
||||||
// #docregion config-test-module
|
// #docregion config-test-module
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
@ -29,7 +34,7 @@ describe('WelcomeComponent', () => {
|
||||||
// #enddocregion setup
|
// #enddocregion setup
|
||||||
// providers: [ UserService ] // a real service would be a problem!
|
// providers: [ UserService ] // a real service would be a problem!
|
||||||
// #docregion setup
|
// #docregion setup
|
||||||
providers: [ {provide: UserService, useValue: fakeUserService } ]
|
providers: [ {provide: UserService, useValue: userServiceStub } ]
|
||||||
});
|
});
|
||||||
// #enddocregion config-test-module
|
// #enddocregion config-test-module
|
||||||
|
|
||||||
|
@ -80,4 +85,8 @@ describe('WelcomeComponent', () => {
|
||||||
expect(content).toMatch(/log in/i, '"log in"');
|
expect(content).toMatch(/log in/i, '"log in"');
|
||||||
});
|
});
|
||||||
// #enddocregion tests
|
// #enddocregion tests
|
||||||
|
|
||||||
|
it('orig stub and injected UserService are not the same object', () => {
|
||||||
|
expect(userServiceStub === userService).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.
|
||||||
// Uncomment to get full stacktrace output. Sometimes helpful, usually not.
|
// Uncomment to get full stacktrace output. Sometimes helpful, usually not.
|
||||||
// Error.stackTraceLimit = Infinity; //
|
// Error.stackTraceLimit = Infinity; //
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000;
|
||||||
|
|
||||||
var baseURL = document.baseURI;
|
var baseURL = document.baseURI;
|
||||||
baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/';
|
baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/';
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
// export for convenience.
|
|
||||||
export { ActivatedRoute, Router, RouterLink, RouterOutlet} from '@angular/router';
|
|
||||||
|
|
||||||
import { Component, Directive, Injectable, Input } from '@angular/core';
|
|
||||||
import { NavigationExtras } from '@angular/router';
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[routerLink]',
|
|
||||||
host: {
|
|
||||||
'(click)': 'onClick()',
|
|
||||||
'[attr.href]': 'visibleHref',
|
|
||||||
'[class.router-link-active]': 'isRouteActive'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
export class FakeRouterLinkDirective {
|
|
||||||
|
|
||||||
isRouteActive = false;
|
|
||||||
visibleHref: string; // the url displayed on the anchor element.
|
|
||||||
|
|
||||||
@Input('routerLink') linkParams: any;
|
|
||||||
navigatedTo: any = null;
|
|
||||||
|
|
||||||
onClick() {
|
|
||||||
this.navigatedTo = this.linkParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'router-outlet', template: ''})
|
|
||||||
export class FakeRouterOutletComponent { }
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class FakeRouter {
|
|
||||||
lastCommand: any[];
|
|
||||||
navigate(commands: any[], extras?: NavigationExtras) {
|
|
||||||
this.lastCommand = commands;
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class FakeActivatedRoute {
|
|
||||||
testParams: {} = {};
|
|
||||||
|
|
||||||
get snapshot() {
|
|
||||||
return {
|
|
||||||
params: this.testParams
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
import { tick, ComponentFixture } from '@angular/core/testing';
|
import { tick, ComponentFixture } from '@angular/core/testing';
|
||||||
|
|
||||||
export * from './jasmine-matchers';
|
export * from './jasmine-matchers';
|
||||||
export * from './fake-router';
|
export * from './router-stubs';
|
||||||
|
|
||||||
|
///// Short utilities /////
|
||||||
|
|
||||||
|
/** Wait a tick, then detect changes */
|
||||||
|
export function advance(f: ComponentFixture<any>): void {
|
||||||
|
tick();
|
||||||
|
f.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
// Short utilities
|
|
||||||
/**
|
/**
|
||||||
* Create custom DOM event the old fashioned way
|
* Create custom DOM event the old fashioned way
|
||||||
*
|
*
|
||||||
|
@ -16,8 +24,20 @@ export function newEvent(eventName: string, bubbles = false, cancelable = false)
|
||||||
return evt;
|
return evt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Wait a tick, then detect changes */
|
// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
||||||
export function advance(f: ComponentFixture<any>): void {
|
// #docregion click-event
|
||||||
tick();
|
/** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */
|
||||||
f.detectChanges();
|
export const ButtonClickEvents = {
|
||||||
|
left: { button: 0 },
|
||||||
|
right: { button: 2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Simulate element click. Defaults to mouse left-button click event. */
|
||||||
|
export function click(el: DebugElement | HTMLElement, eventObj: any = ButtonClickEvents.left): void {
|
||||||
|
if (el instanceof HTMLElement) {
|
||||||
|
el.click();
|
||||||
|
} else {
|
||||||
|
el.triggerEventHandler('click', eventObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// #enddocregion click-event
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
// export for convenience.
|
||||||
|
export { ActivatedRoute, Router, RouterLink, RouterOutlet} from '@angular/router';
|
||||||
|
|
||||||
|
import { Component, Directive, Injectable, Input } from '@angular/core';
|
||||||
|
import { NavigationExtras } from '@angular/router';
|
||||||
|
|
||||||
|
// #docregion router-link
|
||||||
|
@Directive({
|
||||||
|
selector: '[routerLink]',
|
||||||
|
host: {
|
||||||
|
'(click)': 'onClick()'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class RouterLinkStubDirective {
|
||||||
|
@Input('routerLink') linkParams: any;
|
||||||
|
navigatedTo: any = null;
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
this.navigatedTo = this.linkParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion router-link
|
||||||
|
|
||||||
|
@Component({selector: 'router-outlet', template: ''})
|
||||||
|
export class RouterOutletStubComponent { }
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RouterStub {
|
||||||
|
navigate(commands: any[], extras?: NavigationExtras) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Only implements params and part of snapshot.params
|
||||||
|
// #docregion activated-route-stub
|
||||||
|
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ActivatedRouteStub {
|
||||||
|
|
||||||
|
// ActivatedRoute.params is Observable
|
||||||
|
private subject = new BehaviorSubject(this.testParams);
|
||||||
|
params = this.subject.asObservable();
|
||||||
|
|
||||||
|
// Test parameters
|
||||||
|
private _testParams: {};
|
||||||
|
get testParams() { return this._testParams; }
|
||||||
|
set testParams(params: {}) {
|
||||||
|
this._testParams = params;
|
||||||
|
this.subject.next(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActivatedRoute.snapshot.params
|
||||||
|
get snapshot() {
|
||||||
|
return { params: this.testParams };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion activated-route-stub
|
|
@ -4,7 +4,7 @@
|
||||||
type WPromise<T> = webdriver.promise.Promise<T>;
|
type WPromise<T> = webdriver.promise.Promise<T>;
|
||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular 2 ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
|
|
||||||
class Hero {
|
class Hero {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Tour of Heroes</title>
|
<title>Angular Tour of Heroes</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular 2 ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
const expectedH2 = 'My Heroes';
|
const expectedH2 = 'My Heroes';
|
||||||
const targetHero = { id: 16, name: 'RubberMan' };
|
const targetHero = { id: 16, name: 'RubberMan' };
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Tour of Heroes</title>
|
<title>Angular Tour of Heroes</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular 2 ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
const expectedH2 = 'My Heroes';
|
const expectedH2 = 'My Heroes';
|
||||||
const targetHero = { id: 16, name: 'RubberMan' };
|
const targetHero = { id: 16, name: 'RubberMan' };
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Tour of Heroes</title>
|
<title>Angular Tour of Heroes</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular 2 ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
const expectedH2 = 'My Heroes';
|
const expectedH2 = 'My Heroes';
|
||||||
const targetHero = { id: 16, name: 'RubberMan' };
|
const targetHero = { id: 16, name: 'RubberMan' };
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Angular 2 Tour of Heroes</title>
|
<title>Angular Tour of Heroes</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular 2 ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
const targetHero = { id: 15, name: 'Magneta' };
|
const targetHero = { id: 15, name: 'Magneta' };
|
||||||
const targetHeroDashboardIndex = 3;
|
const targetHeroDashboardIndex = 3;
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<head>
|
<head>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<!-- #enddocregion base-href -->
|
<!-- #enddocregion base-href -->
|
||||||
<title>Angular 2 Tour of Heroes</title>
|
<title>Angular Tour of Heroes</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,6 @@ void main() {
|
||||||
bootstrap(AppComponent, [
|
bootstrap(AppComponent, [
|
||||||
provide(BrowserClient, useFactory: () => new BrowserClient(), deps: [])
|
provide(BrowserClient, useFactory: () => new BrowserClient(), deps: [])
|
||||||
]);
|
]);
|
||||||
// Simplify bootstrap provider list to [BrowserClient]
|
|
||||||
// once there is a fix for:
|
|
||||||
// https://github.com/dart-lang/angular2/issues/37
|
|
||||||
}
|
}
|
||||||
// #enddocregion v1
|
// #enddocregion v1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular 2 ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
const targetHero = { id: 15, name: 'Magneta' };
|
const targetHero = { id: 15, name: 'Magneta' };
|
||||||
const targetHeroDashboardIndex = 3;
|
const targetHeroDashboardIndex = 3;
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<title>Angular 2 Tour of Heroes</title>
|
<title>Angular Tour of Heroes</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
describe('QuickStart E2E Tests', function () {
|
describe('QuickStart E2E Tests', function () {
|
||||||
|
|
||||||
let expectedMsg = 'Hello from Angular 2 App with Webpack';
|
let expectedMsg = 'Hello from Angular App with Webpack';
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Error.stackTraceLimit = Infinity;
|
Error.stackTraceLimit = Infinity;
|
||||||
|
|
||||||
require('core-js/es6');
|
require('core-js/es6');
|
||||||
require('reflect-metadata');
|
require('core-js/es7/reflect');
|
||||||
|
|
||||||
require('zone.js/dist/zone');
|
require('zone.js/dist/zone');
|
||||||
require('zone.js/dist/long-stack-trace-zone');
|
require('zone.js/dist/long-stack-trace-zone');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "angular2-webpack",
|
"name": "angular2-webpack",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A webpack starter for angular 2",
|
"description": "A webpack starter for Angular",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --inline --progress --port 8080",
|
"start": "webpack-dev-server --inline --progress --port 8080",
|
||||||
"test": "karma start",
|
"test": "karma start",
|
||||||
|
@ -41,7 +41,6 @@
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"rimraf": "^2.5.2",
|
"rimraf": "^2.5.2",
|
||||||
"style-loader": "^0.13.1",
|
"style-loader": "^0.13.1",
|
||||||
"ts-loader": "^0.8.1",
|
|
||||||
"typescript": "^2.0.2",
|
"typescript": "^2.0.2",
|
||||||
"typings": "^1.3.2",
|
"typings": "^1.3.2",
|
||||||
"webpack": "^1.13.0",
|
"webpack": "^1.13.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<main>
|
<main>
|
||||||
<h1>Hello from Angular 2 App with Webpack</h1>
|
<h1>Hello from Angular App with Webpack</h1>
|
||||||
|
|
||||||
<img src="../../public/images/angular.png">
|
<img src="../../public/images/angular.png">
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// #docregion
|
// #docregion
|
||||||
// Angular 2
|
// Angular
|
||||||
import '@angular/platform-browser';
|
import '@angular/platform-browser';
|
||||||
import '@angular/platform-browser-dynamic';
|
import '@angular/platform-browser-dynamic';
|
||||||
import '@angular/core';
|
import '@angular/core';
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue