3378 lines
		
	
	
		
			105 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
		
		
			
		
	
	
			3378 lines
		
	
	
		
			105 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| 
								 | 
							
								<html lang="en"><head></head><body><form id="mainForm" method="post" action="http://plnkr.co/edit/?p=preview" target="_self"><input type="hidden" name="files[browser-test-shim.js]" value="// BROWSER TESTING SHIM
							 | 
						||
| 
								 | 
							
								// Keep it in-sync with what karma-test-shim does
							 | 
						||
| 
								 | 
							
								/*global jasmine, __karma__, window*/
							 | 
						||
| 
								 | 
							
								(function () {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Uncomment to get full stacktrace output. Sometimes helpful, usually not.
							 | 
						||
| 
								 | 
							
								// Error.stackTraceLimit = Infinity; //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var baseURL = document.baseURI;
							 | 
						||
| 
								 | 
							
								baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								System.config({
							 | 
						||
| 
								 | 
							
								  baseURL: baseURL,
							 | 
						||
| 
								 | 
							
								  // Extend usual application package list with test folder
							 | 
						||
| 
								 | 
							
								  packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Assume npm: is set in `paths` in systemjs.config
							 | 
						||
| 
								 | 
							
								  // Map the angular testing umd bundles
							 | 
						||
| 
								 | 
							
								  map: {
							 | 
						||
| 
								 | 
							
								    '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
							 | 
						||
| 
								 | 
							
								    '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								System.import('systemjs.config.js')
							 | 
						||
| 
								 | 
							
								  .then(importSystemJsExtras)
							 | 
						||
| 
								 | 
							
								  .then(initTestBed)
							 | 
						||
| 
								 | 
							
								  .then(initTesting);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Optional SystemJS configuration extras. Keep going w/o it */
							 | 
						||
| 
								 | 
							
								function importSystemJsExtras(){
							 | 
						||
| 
								 | 
							
								  return System.import('systemjs.config.extras.js')
							 | 
						||
| 
								 | 
							
								  .catch(function(reason) {
							 | 
						||
| 
								 | 
							
								    console.log(
							 | 
						||
| 
								 | 
							
								      'Note: System.import could not load "systemjs.config.extras.js" where you might have added more configuration. It is an optional file so we will continue without it.'
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    console.log(reason);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function initTestBed(){
							 | 
						||
| 
								 | 
							
								  return Promise.all([
							 | 
						||
| 
								 | 
							
								    System.import('@angular/core/testing'),
							 | 
						||
| 
								 | 
							
								    System.import('@angular/platform-browser-dynamic/testing')
							 | 
						||
| 
								 | 
							
								  ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  .then(function (providers) {
							 | 
						||
| 
								 | 
							
								    var coreTesting    = providers[0];
							 | 
						||
| 
								 | 
							
								    var browserTesting = providers[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    coreTesting.TestBed.initTestEnvironment(
							 | 
						||
| 
								 | 
							
								      browserTesting.BrowserDynamicTestingModule,
							 | 
						||
| 
								 | 
							
								      browserTesting.platformBrowserDynamicTesting());
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Import all spec files defined in the html (__spec_files__)
							 | 
						||
| 
								 | 
							
								// and start Jasmine testrunner
							 | 
						||
| 
								 | 
							
								function initTesting () {
							 | 
						||
| 
								 | 
							
								  console.log('loading spec files: '+__spec_files__.join(', '));
							 | 
						||
| 
								 | 
							
								  return Promise.all(
							 | 
						||
| 
								 | 
							
								    __spec_files__.map(function(spec) {
							 | 
						||
| 
								 | 
							
								      return System.import(spec);
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  )
							 | 
						||
| 
								 | 
							
								  //  After all imports load,  re-execute `window.onload` which
							 | 
						||
| 
								 | 
							
								  //  triggers the Jasmine test-runner start or explain what went wrong
							 | 
						||
| 
								 | 
							
								  .then(success, console.error.bind(console));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function success () {
							 | 
						||
| 
								 | 
							
								    console.log('Spec files loaded; starting Jasmine testrunner');
							 | 
						||
| 
								 | 
							
								    window.onload();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								})();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[systemjs.config.extras.js]" value="/** App specific SystemJS configuration */
							 | 
						||
| 
								 | 
							
								System.config({
							 | 
						||
| 
								 | 
							
								  packages: {
							 | 
						||
| 
								 | 
							
								    // barrels
							 | 
						||
| 
								 | 
							
								    'app/model': {main:'index.js', defaultExtension:'js'},
							 | 
						||
| 
								 | 
							
								    'app/model/testing': {main:'index.js', defaultExtension:'js'}
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[styles.css]" value="/* Master Styles */
							 | 
						||
| 
								 | 
							
								h1 {
							 | 
						||
| 
								 | 
							
								  color: #369;
							 | 
						||
| 
								 | 
							
								  font-family: Arial, Helvetica, sans-serif;
							 | 
						||
| 
								 | 
							
								  font-size: 250%;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								h2, h3 {
							 | 
						||
| 
								 | 
							
								  color: #444;
							 | 
						||
| 
								 | 
							
								  font-family: Arial, Helvetica, sans-serif;
							 | 
						||
| 
								 | 
							
								  font-weight: lighter;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								body {
							 | 
						||
| 
								 | 
							
								  margin: 2em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								body, input[text], button {
							 | 
						||
| 
								 | 
							
								  color: #888;
							 | 
						||
| 
								 | 
							
								  font-family: Cambria, Georgia;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								a {
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  cursor: hand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button {
							 | 
						||
| 
								 | 
							
								  font-family: Arial;
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  border: none;
							 | 
						||
| 
								 | 
							
								  padding: 5px 10px;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  cursor: hand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #cfd8dc;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:disabled {
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  color: #aaa;
							 | 
						||
| 
								 | 
							
								  cursor: auto;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Navigation link styles */
							 | 
						||
| 
								 | 
							
								nav a {
							 | 
						||
| 
								 | 
							
								  padding: 5px 10px;
							 | 
						||
| 
								 | 
							
								  text-decoration: none;
							 | 
						||
| 
								 | 
							
								  margin-right: 10px;
							 | 
						||
| 
								 | 
							
								  margin-top: 10px;
							 | 
						||
| 
								 | 
							
								  display: inline-block;
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								nav a:visited, a:link {
							 | 
						||
| 
								 | 
							
								  color: #607D8B;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								nav a:hover {
							 | 
						||
| 
								 | 
							
								  color: #039be5;
							 | 
						||
| 
								 | 
							
								  background-color: #CFD8DC;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								nav a.active {
							 | 
						||
| 
								 | 
							
								  color: #039be5;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* items class */
							 | 
						||
| 
								 | 
							
								.items {
							 | 
						||
| 
								 | 
							
								  margin: 0 0 2em 0;
							 | 
						||
| 
								 | 
							
								  list-style-type: none;
							 | 
						||
| 
								 | 
							
								  padding: 0;
							 | 
						||
| 
								 | 
							
								  width: 24em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li {
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  left: 0;
							 | 
						||
| 
								 | 
							
								  background-color: #EEE;
							 | 
						||
| 
								 | 
							
								  margin: .5em;
							 | 
						||
| 
								 | 
							
								  padding: .3em 0;
							 | 
						||
| 
								 | 
							
								  height: 1.6em;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li:hover {
							 | 
						||
| 
								 | 
							
								  color: #607D8B;
							 | 
						||
| 
								 | 
							
								  background-color: #DDD;
							 | 
						||
| 
								 | 
							
								  left: .1em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li.selected {
							 | 
						||
| 
								 | 
							
								  background-color: #CFD8DC;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li.selected:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #BBD8DC;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items .text {
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  top: -3px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items .badge {
							 | 
						||
| 
								 | 
							
								  display: inline-block;
							 | 
						||
| 
								 | 
							
								  font-size: small;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								  padding: 0.8em 0.7em 0 0.7em;
							 | 
						||
| 
								 | 
							
								  background-color: #607D8B;
							 | 
						||
| 
								 | 
							
								  line-height: 1em;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  left: -1px;
							 | 
						||
| 
								 | 
							
								  top: -4px;
							 | 
						||
| 
								 | 
							
								  height: 1.8em;
							 | 
						||
| 
								 | 
							
								  margin-right: .8em;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px 0 0 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/* everywhere else */
							 | 
						||
| 
								 | 
							
								* {
							 | 
						||
| 
								 | 
							
								  font-family: Arial, Helvetica, sans-serif;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/banner.component.css]" value="h1 { color: green; font-size: 350%}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard-hero.component.css]" value=".hero {
							 | 
						||
| 
								 | 
							
									padding: 20px;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
									text-align: center;
							 | 
						||
| 
								 | 
							
									color: #eee;
							 | 
						||
| 
								 | 
							
									max-height: 120px;
							 | 
						||
| 
								 | 
							
									min-width: 120px;
							 | 
						||
| 
								 | 
							
									background-color: #607D8B;
							 | 
						||
| 
								 | 
							
									border-radius: 2px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.hero:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #EEE;
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  color: #607d8b;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@media (max-width: 600px) {
							 | 
						||
| 
								 | 
							
									.hero {
							 | 
						||
| 
								 | 
							
									  font-size: 10px;
							 | 
						||
| 
								 | 
							
									  max-height: 75px; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@media (max-width: 1024px) {
							 | 
						||
| 
								 | 
							
									.hero {
							 | 
						||
| 
								 | 
							
									  min-width: 60px;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard.component.css]" value="[class*='col-'] {
							 | 
						||
| 
								 | 
							
								  float: left;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								*, *:after, *:before {
							 | 
						||
| 
								 | 
							
									-webkit-box-sizing: border-box;
							 | 
						||
| 
								 | 
							
									-moz-box-sizing: border-box;
							 | 
						||
| 
								 | 
							
									box-sizing: border-box;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								h3 {
							 | 
						||
| 
								 | 
							
								  text-align: center; margin-bottom: 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								[class*='col-'] {
							 | 
						||
| 
								 | 
							
								  padding-right: 20px;
							 | 
						||
| 
								 | 
							
								  padding-bottom: 20px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								[class*='col-']:last-of-type {
							 | 
						||
| 
								 | 
							
								  padding-right: 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.grid {
							 | 
						||
| 
								 | 
							
								  margin: 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.col-1-4 {
							 | 
						||
| 
								 | 
							
								  width: 25%;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.grid-pad {
							 | 
						||
| 
								 | 
							
								  padding: 10px 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.grid-pad > [class*='col-']:last-of-type {
							 | 
						||
| 
								 | 
							
								  padding-right: 20px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								@media (max-width: 1024px) {
							 | 
						||
| 
								 | 
							
									.grid {
							 | 
						||
| 
								 | 
							
									  margin: 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-detail.component.css]" value="label {
							 | 
						||
| 
								 | 
							
								  display: inline-block;
							 | 
						||
| 
								 | 
							
								  width: 3em;
							 | 
						||
| 
								 | 
							
								  margin: .5em 0;
							 | 
						||
| 
								 | 
							
								  color: #607D8B;
							 | 
						||
| 
								 | 
							
								  font-weight: bold;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								input {
							 | 
						||
| 
								 | 
							
								  height: 2em;
							 | 
						||
| 
								 | 
							
								  font-size: 1em;
							 | 
						||
| 
								 | 
							
								  padding-left: .4em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button {
							 | 
						||
| 
								 | 
							
								  margin-top: 20px;
							 | 
						||
| 
								 | 
							
								  font-family: Arial;
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  border: none;
							 | 
						||
| 
								 | 
							
								  padding: 5px 10px;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								  cursor: pointer; cursor: hand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #cfd8dc;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:disabled {
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  color: #ccc;
							 | 
						||
| 
								 | 
							
								  cursor: auto;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-list.component.css]" value=".selected {
							 | 
						||
| 
								 | 
							
								  background-color: #CFD8DC !important;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.heroes {
							 | 
						||
| 
								 | 
							
								  margin: 0 0 2em 0;
							 | 
						||
| 
								 | 
							
								  list-style-type: none;
							 | 
						||
| 
								 | 
							
								  padding: 0;
							 | 
						||
| 
								 | 
							
								  width: 10em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.heroes li {
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  left: 0;
							 | 
						||
| 
								 | 
							
								  background-color: #EEE;
							 | 
						||
| 
								 | 
							
								  margin: .5em;
							 | 
						||
| 
								 | 
							
								  padding: .3em 0;
							 | 
						||
| 
								 | 
							
								  height: 1.6em;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.heroes li:hover {
							 | 
						||
| 
								 | 
							
								  color: #607D8B;
							 | 
						||
| 
								 | 
							
								  background-color: #DDD;
							 | 
						||
| 
								 | 
							
								  left: .1em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.heroes li.selected:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #BBD8DC !important;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.heroes .text {
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  top: -3px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.heroes .badge {
							 | 
						||
| 
								 | 
							
								  display: inline-block;
							 | 
						||
| 
								 | 
							
								  font-size: small;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								  padding: 0.8em 0.7em 0 0.7em;
							 | 
						||
| 
								 | 
							
								  background-color: #607D8B;
							 | 
						||
| 
								 | 
							
								  line-height: 1em;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  left: -1px;
							 | 
						||
| 
								 | 
							
								  top: -4px;
							 | 
						||
| 
								 | 
							
								  height: 1.8em;
							 | 
						||
| 
								 | 
							
								  margin-right: .8em;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px 0 0 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button {
							 | 
						||
| 
								 | 
							
								  font-family: Arial;
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  border: none;
							 | 
						||
| 
								 | 
							
								  padding: 5px 10px;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  cursor: hand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #cfd8dc;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.component.html]" value="<app-banner></app-banner>
							 | 
						||
| 
								 | 
							
								<app-welcome></app-welcome>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<nav>
							 | 
						||
| 
								 | 
							
								  <a routerLink="/dashboard">Dashboard</a>
							 | 
						||
| 
								 | 
							
								  <a routerLink="/heroes">Heroes</a>
							 | 
						||
| 
								 | 
							
								  <a routerLink="/about">About</a>
							 | 
						||
| 
								 | 
							
								</nav>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<router-outlet></router-outlet>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/banner.component.html]" value="<h1>{{title}}</h1>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/dashboard/dashboard-hero.component.html]" value="<div (click)="click()" class="hero">
							 | 
						||
| 
								 | 
							
								  {{hero.name | uppercase}}
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/dashboard/dashboard.component.html]" value="<h2 highlight>{{title}}</h2>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<div class="grid grid-pad">
							 | 
						||
| 
								 | 
							
								  <dashboard-hero *ngFor="let hero of heroes"  class="col-1-4"
							 | 
						||
| 
								 | 
							
								    [hero]=hero  (selected)="gotoDetail($event)" >
							 | 
						||
| 
								 | 
							
								  </dashboard-hero>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/hero/hero-detail.component.html]" value="<div *ngIf="hero">
							 | 
						||
| 
								 | 
							
								  <h2><span>{{hero.name | titlecase}}</span> Details</h2>
							 | 
						||
| 
								 | 
							
								  <div>
							 | 
						||
| 
								 | 
							
								    <label>id: </label>{{hero.id}}</div>
							 | 
						||
| 
								 | 
							
								  <div>
							 | 
						||
| 
								 | 
							
								    <label for="name">name: </label>
							 | 
						||
| 
								 | 
							
								    <input id="name" [(ngModel)]="hero.name" placeholder="name" />
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								  <button (click)="save()">Save</button>
							 | 
						||
| 
								 | 
							
								  <button (click)="cancel()">Cancel</button>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/hero/hero-list.component.html]" value="<h2 highlight="gold">My Heroes</h2>
							 | 
						||
| 
								 | 
							
								<ul class="heroes">
							 | 
						||
| 
								 | 
							
								  <li *ngFor="let hero of heroes | async "
							 | 
						||
| 
								 | 
							
								    [class.selected]="hero === selectedHero"
							 | 
						||
| 
								 | 
							
								    (click)="onSelect(hero)">
							 | 
						||
| 
								 | 
							
								    <span class="badge">{{hero.id}}</span> {{hero.name}}
							 | 
						||
| 
								 | 
							
								  </li>
							 | 
						||
| 
								 | 
							
								</ul>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/about.component.spec.ts]" value="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)', () => {
							 | 
						||
| 
								 | 
							
								  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'));
							 | 
						||
| 
								 | 
							
								    const bgColor = de.nativeElement.style.backgroundColor;
							 | 
						||
| 
								 | 
							
								    expect(bgColor).toBe('skyblue');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/about.component.ts]" value="import { Component } from '@angular/core';
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  template: `
							 | 
						||
| 
								 | 
							
								  <h2 highlight="skyblue">About</h2>
							 | 
						||
| 
								 | 
							
								  <twain-quote></twain-quote>
							 | 
						||
| 
								 | 
							
								  <p>All about this sample</p>`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class AboutComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app-routing.module.ts]" value="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 { };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.component.router.spec.ts]" value="// For more examples:
							 | 
						||
| 
								 | 
							
								//   https://github.com/angular/angular/blob/master/modules/@angular/router/test/integration.spec.ts
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { async, ComponentFixture, fakeAsync, TestBed, tick,
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { RouterTestingModule } from '@angular/router/testing';
							 | 
						||
| 
								 | 
							
								import { SpyLocation }         from '@angular/common/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { click }               from '../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// r - for relatively obscure router symbols
							 | 
						||
| 
								 | 
							
								import * as r                         from  '@angular/router';
							 | 
						||
| 
								 | 
							
								import { Router, RouterLinkWithHref } from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { By }                 from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement, Type } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { Location }           from '@angular/common';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { AppModule }              from './app.module';
							 | 
						||
| 
								 | 
							
								import { AppComponent }           from './app.component';
							 | 
						||
| 
								 | 
							
								import { AboutComponent }         from './about.component';
							 | 
						||
| 
								 | 
							
								import { DashboardHeroComponent } from './dashboard/dashboard-hero.component';
							 | 
						||
| 
								 | 
							
								import { TwainService }           from './shared/twain.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let comp:     AppComponent;
							 | 
						||
| 
								 | 
							
								let fixture:  ComponentFixture<AppComponent>;
							 | 
						||
| 
								 | 
							
								let page:     Page;
							 | 
						||
| 
								 | 
							
								let router:   Router;
							 | 
						||
| 
								 | 
							
								let location: SpyLocation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('AppComponent & RouterTestingModule', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [ AppModule, RouterTestingModule ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate to "Dashboard" immediately', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    createComponent();
							 | 
						||
| 
								 | 
							
								    expect(location.path()).toEqual('/dashboard', 'after initialNavigation()');
							 | 
						||
| 
								 | 
							
								    expectElementOf(DashboardHeroComponent);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate to "About" on click', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    createComponent();
							 | 
						||
| 
								 | 
							
								    click(page.aboutLinkDe);
							 | 
						||
| 
								 | 
							
								    // page.aboutLinkDe.nativeElement.click(); // ok but fails in phantom
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    advance();
							 | 
						||
| 
								 | 
							
								    expectPathToBe('/about');
							 | 
						||
| 
								 | 
							
								    expectElementOf(AboutComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    page.expectEvents([
							 | 
						||
| 
								 | 
							
								      [r.NavigationStart, '/about'], [r.RoutesRecognized, '/about'],
							 | 
						||
| 
								 | 
							
								      [r.NavigationEnd, '/about']
							 | 
						||
| 
								 | 
							
								    ]);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate to "About" w/ browser location URL change', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    createComponent();
							 | 
						||
| 
								 | 
							
								    location.simulateHashChange('/about');
							 | 
						||
| 
								 | 
							
								    // location.go('/about'); // also works ... except in plunker
							 | 
						||
| 
								 | 
							
								    advance();
							 | 
						||
| 
								 | 
							
								    expectPathToBe('/about');
							 | 
						||
| 
								 | 
							
								    expectElementOf(AboutComponent);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Can't navigate to lazy loaded modules with this technique
							 | 
						||
| 
								 | 
							
								  xit('should navigate to "Heroes" on click', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    createComponent();
							 | 
						||
| 
								 | 
							
								    page.heroesLinkDe.nativeElement.click();
							 | 
						||
| 
								 | 
							
								    advance();
							 | 
						||
| 
								 | 
							
								    expectPathToBe('/heroes');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///////////////
							 | 
						||
| 
								 | 
							
								import { NgModuleFactoryLoader }    from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { SpyNgModuleFactoryLoader } from '@angular/router/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HeroModule }             from './hero/hero.module';  // should be lazy loaded
							 | 
						||
| 
								 | 
							
								import { HeroListComponent }      from './hero/hero-list.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let loader: SpyNgModuleFactoryLoader;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///////// Can't get lazy loaded Heroes to work yet
							 | 
						||
| 
								 | 
							
								xdescribe('AppComponent & Lazy Loading', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [ AppModule, RouterTestingModule ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    createComponent();
							 | 
						||
| 
								 | 
							
								    loader   = TestBed.get(NgModuleFactoryLoader);
							 | 
						||
| 
								 | 
							
								    loader.stubbedModules = {expected: HeroModule};
							 | 
						||
| 
								 | 
							
								    router.resetConfig([{path: 'heroes', loadChildren: 'expected'}]);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('dummy', () => expect(true).toBe(true) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate to "Heroes" on click', async(() => {
							 | 
						||
| 
								 | 
							
								    page.heroesLinkDe.nativeElement.click();
							 | 
						||
| 
								 | 
							
								    advance();
							 | 
						||
| 
								 | 
							
								    expectPathToBe('/heroes');
							 | 
						||
| 
								 | 
							
								    expectElementOf(HeroListComponent);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  xit('can navigate to "Heroes" w/ browser location URL change', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    location.go('/heroes');
							 | 
						||
| 
								 | 
							
								    advance();
							 | 
						||
| 
								 | 
							
								    expectPathToBe('/heroes');
							 | 
						||
| 
								 | 
							
								    expectElementOf(HeroListComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    page.expectEvents([
							 | 
						||
| 
								 | 
							
								      [r.NavigationStart, '/heroes'], [r.RoutesRecognized, '/heroes'],
							 | 
						||
| 
								 | 
							
								      [r.NavigationEnd, '/heroes']
							 | 
						||
| 
								 | 
							
								    ]);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////// Helpers /////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Wait a tick, then detect changes */
							 | 
						||
| 
								 | 
							
								function advance(): void {
							 | 
						||
| 
								 | 
							
								  tick();
							 | 
						||
| 
								 | 
							
								  fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function createComponent() {
							 | 
						||
| 
								 | 
							
								  fixture = TestBed.createComponent(AppComponent);
							 | 
						||
| 
								 | 
							
								  comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const injector = fixture.debugElement.injector;
							 | 
						||
| 
								 | 
							
								  location = injector.get(Location);
							 | 
						||
| 
								 | 
							
								  router = injector.get(Router);
							 | 
						||
| 
								 | 
							
								  router.initialNavigation();
							 | 
						||
| 
								 | 
							
								  spyOn(injector.get(TwainService), 'getQuote')
							 | 
						||
| 
								 | 
							
								    .and.returnValue(Promise.resolve('Test Quote')); // fakes it
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  advance();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  page = new Page();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Page {
							 | 
						||
| 
								 | 
							
								  aboutLinkDe:     DebugElement;
							 | 
						||
| 
								 | 
							
								  dashboardLinkDe: DebugElement;
							 | 
						||
| 
								 | 
							
								  heroesLinkDe:    DebugElement;
							 | 
						||
| 
								 | 
							
								  recordedEvents:  any[]  =  [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // for debugging
							 | 
						||
| 
								 | 
							
								  comp: AppComponent;
							 | 
						||
| 
								 | 
							
								  location: SpyLocation;
							 | 
						||
| 
								 | 
							
								  router: Router;
							 | 
						||
| 
								 | 
							
								  fixture: ComponentFixture<AppComponent>;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  expectEvents(pairs: any[]) {
							 | 
						||
| 
								 | 
							
								    const events = this.recordedEvents;
							 | 
						||
| 
								 | 
							
								    expect(events.length).toEqual(pairs.length, 'actual/expected events length mismatch');
							 | 
						||
| 
								 | 
							
								    for (let i = 0; i < events.length; ++i) {
							 | 
						||
| 
								 | 
							
								      expect((<any>events[i].constructor).name).toBe(pairs[i][0].name, 'unexpected event name');
							 | 
						||
| 
								 | 
							
								      expect((<any>events[i]).url).toBe(pairs[i][1], 'unexpected event url');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor() {
							 | 
						||
| 
								 | 
							
								    router.events.forEach(e => this.recordedEvents.push(e));
							 | 
						||
| 
								 | 
							
								    const links = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
							 | 
						||
| 
								 | 
							
								    this.aboutLinkDe     = links[2];
							 | 
						||
| 
								 | 
							
								    this.dashboardLinkDe = links[0];
							 | 
						||
| 
								 | 
							
								    this.heroesLinkDe    = links[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // for debugging
							 | 
						||
| 
								 | 
							
								    this.comp    = comp;
							 | 
						||
| 
								 | 
							
								    this.fixture = fixture;
							 | 
						||
| 
								 | 
							
								    this.router  = router;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function expectPathToBe(path: string, expectationFailOutput?: any) {
							 | 
						||
| 
								 | 
							
								  expect(location.path()).toEqual(path, expectationFailOutput || 'location.path()');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function expectElementOf(type: Type<any>): any {
							 | 
						||
| 
								 | 
							
								  const el = fixture.debugElement.query(By.directive(type));
							 | 
						||
| 
								 | 
							
								  expect(el).toBeTruthy('expected an element for ' + type.name);
							 | 
						||
| 
								 | 
							
								  return el;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.component.spec.ts]" value="import { async, ComponentFixture, TestBed
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { DebugElement } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { By } from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  import { NO_ERRORS_SCHEMA }          from '@angular/core';
							 | 
						||
| 
								 | 
							
								  import { Component }                 from '@angular/core';
							 | 
						||
| 
								 | 
							
								  import { AppComponent }              from './app.component';
							 | 
						||
| 
								 | 
							
								  import { BannerComponent }           from './banner.component';
							 | 
						||
| 
								 | 
							
								  import { RouterLinkStubDirective }   from '../testing';
							 | 
						||
| 
								 | 
							
								  import { RouterOutletStubComponent } from '../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @Component({selector: 'app-welcome', template: ''})
							 | 
						||
| 
								 | 
							
								  class WelcomeStubComponent {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let comp:    AppComponent;
							 | 
						||
| 
								 | 
							
								let fixture: ComponentFixture<AppComponent>;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('AppComponent & TestModule', () => {
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [
							 | 
						||
| 
								 | 
							
								        AppComponent,
							 | 
						||
| 
								 | 
							
								        BannerComponent, WelcomeStubComponent,
							 | 
						||
| 
								 | 
							
								        RouterLinkStubDirective, RouterOutletStubComponent
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .compileComponents()
							 | 
						||
| 
								 | 
							
								    .then(() => {
							 | 
						||
| 
								 | 
							
								      fixture = TestBed.createComponent(AppComponent);
							 | 
						||
| 
								 | 
							
								      comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								  tests();
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////// Testing w/ NO_ERRORS_SCHEMA //////
							 | 
						||
| 
								 | 
							
								describe('AppComponent & NO_ERRORS_SCHEMA', () => {
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ AppComponent, RouterLinkStubDirective ],
							 | 
						||
| 
								 | 
							
								      schemas:      [ NO_ERRORS_SCHEMA ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .compileComponents()
							 | 
						||
| 
								 | 
							
								    .then(() => {
							 | 
						||
| 
								 | 
							
								      fixture = TestBed.createComponent(AppComponent);
							 | 
						||
| 
								 | 
							
								      comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								  tests();
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////// Testing w/ real root module //////
							 | 
						||
| 
								 | 
							
								// Tricky because we are disabling the router and its configuration
							 | 
						||
| 
								 | 
							
								// Better to use RouterTestingModule
							 | 
						||
| 
								 | 
							
								import { AppModule }    from './app.module';
							 | 
						||
| 
								 | 
							
								import { AppRoutingModule } from './app-routing.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('AppComponent & AppModule', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [ AppModule ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Get rid of app's Router configuration otherwise many failures.
							 | 
						||
| 
								 | 
							
								    // Doing so removes Router declarations; add the Router stubs
							 | 
						||
| 
								 | 
							
								    .overrideModule(AppModule, {
							 | 
						||
| 
								 | 
							
								      remove: {
							 | 
						||
| 
								 | 
							
								        imports: [ AppRoutingModule ]
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      add: {
							 | 
						||
| 
								 | 
							
								        declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ]
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .compileComponents()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .then(() => {
							 | 
						||
| 
								 | 
							
								      fixture = TestBed.createComponent(AppComponent);
							 | 
						||
| 
								 | 
							
								      comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  tests();
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function tests() {
							 | 
						||
| 
								 | 
							
								  let links: RouterLinkStubDirective[];
							 | 
						||
| 
								 | 
							
								  let linkDes: DebugElement[];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can instantiate it', () => {
							 | 
						||
| 
								 | 
							
								    expect(comp).not.toBeNull();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.component.ts]" value="import { Component } from '@angular/core';
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'my-app',
							 | 
						||
| 
								 | 
							
								  templateUrl: './app.component.html'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class AppComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.module.ts]" value="import { NgModule }         from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { BrowserModule }    from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { AppComponent }     from './app.component';
							 | 
						||
| 
								 | 
							
								import { AppRoutingModule } from './app-routing.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { AboutComponent }   from './about.component';
							 | 
						||
| 
								 | 
							
								import { BannerComponent }  from './banner.component';
							 | 
						||
| 
								 | 
							
								import { HeroService,
							 | 
						||
| 
								 | 
							
								         UserService }      from './model';
							 | 
						||
| 
								 | 
							
								import { TwainService }     from './shared/twain.service';
							 | 
						||
| 
								 | 
							
								import { WelcomeComponent } from './welcome.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { DashboardModule }  from './dashboard/dashboard.module';
							 | 
						||
| 
								 | 
							
								import { SharedModule }     from './shared/shared.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@NgModule({
							 | 
						||
| 
								 | 
							
								  imports: [
							 | 
						||
| 
								 | 
							
								    BrowserModule,
							 | 
						||
| 
								 | 
							
								    DashboardModule,
							 | 
						||
| 
								 | 
							
								    AppRoutingModule,
							 | 
						||
| 
								 | 
							
								    SharedModule
							 | 
						||
| 
								 | 
							
								  ],
							 | 
						||
| 
								 | 
							
								  providers:    [ HeroService, TwainService, UserService ],
							 | 
						||
| 
								 | 
							
								  declarations: [ AppComponent, AboutComponent, BannerComponent, WelcomeComponent ],
							 | 
						||
| 
								 | 
							
								  bootstrap:    [ AppComponent ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class AppModule { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/banner-inline.component.spec.ts]" value="import { ComponentFixture, TestBed } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { By }              from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement }    from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { BannerComponent } from './banner-inline.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('BannerComponent (inline template)', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let comp:    BannerComponent;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<BannerComponent>;
							 | 
						||
| 
								 | 
							
								  let de:      DebugElement;
							 | 
						||
| 
								 | 
							
								  let el:      HTMLElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ BannerComponent ], // declare the test component
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(BannerComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    comp = fixture.componentInstance; // BannerComponent test instance
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // query for the title <h1> by CSS element selector
							 | 
						||
| 
								 | 
							
								    de = fixture.debugElement.query(By.css('h1'));
							 | 
						||
| 
								 | 
							
								    el = de.nativeElement;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('no title in the DOM until manually call `detectChanges`', () => {
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toEqual('');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display original title', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain(comp.title);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display a different test title', () => {
							 | 
						||
| 
								 | 
							
								    comp.title = 'Test Title';
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain('Test Title');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/banner-inline.component.ts]" value="import { Component } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  selector: 'app-banner',
							 | 
						||
| 
								 | 
							
								  template: '<h1>{{title}}</h1>'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class BannerComponent {
							 | 
						||
| 
								 | 
							
								  title = 'Test Tour of Heroes';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/banner.component.detect-changes.spec.ts]" value="import { async } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { ComponentFixtureAutoDetect } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { ComponentFixture, TestBed } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { By }              from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement }    from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { BannerComponent } from './banner.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('BannerComponent (AutoChangeDetect)', () => {
							 | 
						||
| 
								 | 
							
								  let comp:    BannerComponent;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<BannerComponent>;
							 | 
						||
| 
								 | 
							
								  let de:      DebugElement;
							 | 
						||
| 
								 | 
							
								  let el:      HTMLElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ BannerComponent ],
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: ComponentFixtureAutoDetect, useValue: true }
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(BannerComponent);
							 | 
						||
| 
								 | 
							
								    comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    de = fixture.debugElement.query(By.css('h1'));
							 | 
						||
| 
								 | 
							
								    el = de.nativeElement;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display original title', () => {
							 | 
						||
| 
								 | 
							
								    // Hooray! No `fixture.detectChanges()` needed
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain(comp.title);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should still see original title after comp.title change', () => {
							 | 
						||
| 
								 | 
							
								    const oldTitle = comp.title;
							 | 
						||
| 
								 | 
							
								    comp.title = 'Test Title';
							 | 
						||
| 
								 | 
							
								    // Displayed title is old because Angular didn't hear the change :(
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain(oldTitle);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display updated title after detectChanges', () => {
							 | 
						||
| 
								 | 
							
								    comp.title = 'Test Title';
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges(); // detect changes explicitly
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain(comp.title);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/banner.component.spec.ts]" value="import { async, ComponentFixture, TestBed } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { By }              from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement }    from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { BannerComponent } from './banner.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('BannerComponent (templateUrl)', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let comp:    BannerComponent;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<BannerComponent>;
							 | 
						||
| 
								 | 
							
								  let de:      DebugElement;
							 | 
						||
| 
								 | 
							
								  let el:      HTMLElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // async beforeEach
							 | 
						||
| 
								 | 
							
								  beforeEach(async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ BannerComponent ], // declare the test component
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();  // compile template and css
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // synchronous beforeEach
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(BannerComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    comp = fixture.componentInstance; // BannerComponent test instance
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // query for the title <h1> by CSS element selector
							 | 
						||
| 
								 | 
							
								    de = fixture.debugElement.query(By.css('h1'));
							 | 
						||
| 
								 | 
							
								    el = de.nativeElement;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('no title in the DOM until manually call `detectChanges`', () => {
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toEqual('');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display original title', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain(comp.title);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display a different test title', () => {
							 | 
						||
| 
								 | 
							
								    comp.title = 'Test Title';
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain('Test Title');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/banner.component.ts]" value="import { Component } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'app-banner',
							 | 
						||
| 
								 | 
							
								  templateUrl: './banner.component.html',
							 | 
						||
| 
								 | 
							
								  styleUrls:  ['./banner.component.css']
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class BannerComponent {
							 | 
						||
| 
								 | 
							
								  title = 'Test Tour of Heroes';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard-hero.component.spec.ts]" value="import { async, ComponentFixture, TestBed
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { By }           from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { addMatchers, click } from '../../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero } from '../model/hero';
							 | 
						||
| 
								 | 
							
								import { DashboardHeroComponent } from './dashboard-hero.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								beforeEach( addMatchers );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('DashboardHeroComponent when tested directly', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let comp: DashboardHeroComponent;
							 | 
						||
| 
								 | 
							
								  let expectedHero: Hero;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<DashboardHeroComponent>;
							 | 
						||
| 
								 | 
							
								  let heroEl: DebugElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // async beforeEach
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ DashboardHeroComponent ],
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents(); // compile template and css
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // synchronous beforeEach
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(DashboardHeroComponent);
							 | 
						||
| 
								 | 
							
								    comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    heroEl  = fixture.debugElement.query(By.css('.hero')); // find hero element
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // pretend that it was wired to something that supplied a hero
							 | 
						||
| 
								 | 
							
								    expectedHero = new Hero(42, 'Test Name');
							 | 
						||
| 
								 | 
							
								    comp.hero = expectedHero;
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges(); // trigger initial data binding
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display hero name', () => {
							 | 
						||
| 
								 | 
							
								    const expectedPipedName = expectedHero.name.toUpperCase();
							 | 
						||
| 
								 | 
							
								    expect(heroEl.nativeElement.textContent).toContain(expectedPipedName);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should raise selected event when clicked', () => {
							 | 
						||
| 
								 | 
							
								    let selectedHero: Hero;
							 | 
						||
| 
								 | 
							
								    comp.selected.subscribe((hero: Hero) => selectedHero = hero);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    heroEl.triggerEventHandler('click', null);
							 | 
						||
| 
								 | 
							
								    expect(selectedHero).toBe(expectedHero);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('DashboardHeroComponent when inside a test host', () => {
							 | 
						||
| 
								 | 
							
								  let testHost: TestHostComponent;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<TestHostComponent>;
							 | 
						||
| 
								 | 
							
								  let heroEl: DebugElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ DashboardHeroComponent, TestHostComponent ], // declare both
							 | 
						||
| 
								 | 
							
								    }).compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    // create TestHostComponent instead of DashboardHeroComponent
							 | 
						||
| 
								 | 
							
								    fixture  = TestBed.createComponent(TestHostComponent);
							 | 
						||
| 
								 | 
							
								    testHost = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    heroEl   = fixture.debugElement.query(By.css('.hero')); // find hero
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges(); // trigger initial data binding
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display hero name', () => {
							 | 
						||
| 
								 | 
							
								    const expectedPipedName = testHost.hero.name.toUpperCase();
							 | 
						||
| 
								 | 
							
								    expect(heroEl.nativeElement.textContent).toContain(expectedPipedName);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should raise selected event when clicked', () => {
							 | 
						||
| 
								 | 
							
								    click(heroEl);
							 | 
						||
| 
								 | 
							
								    // selected hero should be the same data bound hero
							 | 
						||
| 
								 | 
							
								    expect(testHost.selectedHero).toBe(testHost.hero);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////// Test Host Component //////
							 | 
						||
| 
								 | 
							
								import { Component } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  template: `
							 | 
						||
| 
								 | 
							
								    <dashboard-hero  [hero]="hero"  (selected)="onSelected($event)"></dashboard-hero>`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								class TestHostComponent {
							 | 
						||
| 
								 | 
							
								  hero = new Hero(42, 'Test Name');
							 | 
						||
| 
								 | 
							
								  selectedHero: Hero;
							 | 
						||
| 
								 | 
							
								  onSelected(hero: Hero) { this.selectedHero = hero; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard-hero.component.ts]" value="import { Component, EventEmitter, Input, Output } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero } from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector:    'dashboard-hero',
							 | 
						||
| 
								 | 
							
								  templateUrl: './dashboard-hero.component.html',
							 | 
						||
| 
								 | 
							
								  styleUrls: [ './dashboard-hero.component.css' ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class DashboardHeroComponent {
							 | 
						||
| 
								 | 
							
								  @Input() hero: Hero;
							 | 
						||
| 
								 | 
							
								  @Output() selected = new EventEmitter<Hero>();
							 | 
						||
| 
								 | 
							
								  click() { this.selected.emit(this.hero); }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard.component.no-testbed.spec.ts]" value="import { Router } from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { DashboardComponent } from './dashboard.component';
							 | 
						||
| 
								 | 
							
								import { Hero }               from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { addMatchers }     from '../../testing';
							 | 
						||
| 
								 | 
							
								import { FakeHeroService } from '../model/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class FakeRouter {
							 | 
						||
| 
								 | 
							
								  navigateByUrl(url: string) { return url;  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('DashboardComponent: w/o Angular TestBed', () => {
							 | 
						||
| 
								 | 
							
								  let comp: DashboardComponent;
							 | 
						||
| 
								 | 
							
								  let heroService: FakeHeroService;
							 | 
						||
| 
								 | 
							
								  let router: Router;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    addMatchers();
							 | 
						||
| 
								 | 
							
								    router = new FakeRouter() as any as Router;
							 | 
						||
| 
								 | 
							
								    heroService = new FakeHeroService();
							 | 
						||
| 
								 | 
							
								    comp = new DashboardComponent(router, heroService);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should NOT have heroes before calling OnInit', () => {
							 | 
						||
| 
								 | 
							
								    expect(comp.heroes.length).toBe(0,
							 | 
						||
| 
								 | 
							
								      'should not have heroes before OnInit');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should NOT have heroes immediately after OnInit', () => {
							 | 
						||
| 
								 | 
							
								    comp.ngOnInit(); // ngOnInit -> getHeroes
							 | 
						||
| 
								 | 
							
								    expect(comp.heroes.length).toBe(0,
							 | 
						||
| 
								 | 
							
								      'should not have heroes until service promise resolves');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should HAVE heroes after HeroService gets them', (done: DoneFn) => {
							 | 
						||
| 
								 | 
							
								    comp.ngOnInit(); // ngOnInit -> getHeroes
							 | 
						||
| 
								 | 
							
								    heroService.lastPromise // the one from getHeroes
							 | 
						||
| 
								 | 
							
								      .then(() => {
							 | 
						||
| 
								 | 
							
								        // throw new Error('deliberate error'); // see it fail gracefully
							 | 
						||
| 
								 | 
							
								        expect(comp.heroes.length).toBeGreaterThan(0,
							 | 
						||
| 
								 | 
							
								          'should have heroes after service promise resolves');
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      .then(done, done.fail);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should tell ROUTER to navigate by hero id', () => {
							 | 
						||
| 
								 | 
							
								    const hero = new Hero(42, 'Abbracadabra');
							 | 
						||
| 
								 | 
							
								    const spy = spyOn(router, 'navigateByUrl');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    comp.gotoDetail(hero);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const navArgs = spy.calls.mostRecent().args[0];
							 | 
						||
| 
								 | 
							
								    expect(navArgs).toBe('/heroes/42', 'should nav to HeroDetail for Hero 42');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard.component.spec.ts]" value="import { async, inject, ComponentFixture, TestBed
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { addMatchers, click } from '../../testing';
							 | 
						||
| 
								 | 
							
								import { HeroService }        from '../model';
							 | 
						||
| 
								 | 
							
								import { FakeHeroService }    from '../model/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { By }     from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { Router } from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { DashboardComponent } from './dashboard.component';
							 | 
						||
| 
								 | 
							
								import { DashboardModule }    from './dashboard.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class RouterStub {
							 | 
						||
| 
								 | 
							
								  navigateByUrl(url: string) { return url; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								beforeEach ( addMatchers );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let comp: DashboardComponent;
							 | 
						||
| 
								 | 
							
								let fixture: ComponentFixture<DashboardComponent>;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////////  Deep  ////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('DashboardComponent (deep)', () => {
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [ DashboardModule ]
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  compileAndCreate();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  tests(clickForDeep);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function clickForDeep() {
							 | 
						||
| 
								 | 
							
								    // get first <div class="hero"> DebugElement
							 | 
						||
| 
								 | 
							
								    const heroEl = fixture.debugElement.query(By.css('.hero'));
							 | 
						||
| 
								 | 
							
								    click(heroEl);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////////  Shallow ////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { NO_ERRORS_SCHEMA } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('DashboardComponent (shallow)', () => {
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ DashboardComponent ],
							 | 
						||
| 
								 | 
							
								      schemas:      [NO_ERRORS_SCHEMA]
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  compileAndCreate();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  tests(clickForShallow);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function clickForShallow() {
							 | 
						||
| 
								 | 
							
								    // get first <dashboard-hero> DebugElement
							 | 
						||
| 
								 | 
							
								    const heroEl = fixture.debugElement.query(By.css('dashboard-hero'));
							 | 
						||
| 
								 | 
							
								    heroEl.triggerEventHandler('selected', comp.heroes[0]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Add TestBed providers, compile, and create DashboardComponent */
							 | 
						||
| 
								 | 
							
								function compileAndCreate() {
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: HeroService, useClass: FakeHeroService },
							 | 
						||
| 
								 | 
							
								        { provide: Router,      useClass: RouterStub }
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents().then(() => {
							 | 
						||
| 
								 | 
							
								      fixture = TestBed.createComponent(DashboardComponent);
							 | 
						||
| 
								 | 
							
								      comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * The (almost) same tests for both.
							 | 
						||
| 
								 | 
							
								 * Only change: the way that the first hero is clicked
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function tests(heroClick: Function) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should NOT have heroes before ngOnInit', () => {
							 | 
						||
| 
								 | 
							
								    expect(comp.heroes.length).toBe(0,
							 | 
						||
| 
								 | 
							
								      'should not have heroes before ngOnInit');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should NOT have heroes immediately after ngOnInit', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges(); // runs initial lifecycle hooks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(comp.heroes.length).toBe(0,
							 | 
						||
| 
								 | 
							
								      'should not have heroes until service promise resolves');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  describe('after get dashboard heroes', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     // Trigger component so it gets heroes and binds to them
							 | 
						||
| 
								 | 
							
								     beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								        fixture.detectChanges(); // runs ngOnInit -> getHeroes
							 | 
						||
| 
								 | 
							
								        fixture.whenStable() // No need for the `lastPromise` hack!
							 | 
						||
| 
								 | 
							
								          .then(() => fixture.detectChanges()); // bind to heroes
							 | 
						||
| 
								 | 
							
								     }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should HAVE heroes', () => {
							 | 
						||
| 
								 | 
							
								      expect(comp.heroes.length).toBeGreaterThan(0,
							 | 
						||
| 
								 | 
							
								        'should have heroes after service promise resolves');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should DISPLAY heroes', () => {
							 | 
						||
| 
								 | 
							
								      // Find and examine the displayed heroes
							 | 
						||
| 
								 | 
							
								      // Look for them in the DOM by css class
							 | 
						||
| 
								 | 
							
								      const heroes = fixture.debugElement.queryAll(By.css('dashboard-hero'));
							 | 
						||
| 
								 | 
							
								      expect(heroes.length).toBe(4, 'should display 4 heroes');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should tell ROUTER to navigate when hero clicked',
							 | 
						||
| 
								 | 
							
								      inject([Router], (router: Router) => { // ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const spy = spyOn(router, 'navigateByUrl');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      heroClick(); // trigger click on first inner <div class="hero">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // args passed to router.navigateByUrl()
							 | 
						||
| 
								 | 
							
								      const navArgs = spy.calls.first().args[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // expecting to navigate to id of the component's first hero
							 | 
						||
| 
								 | 
							
								      const id = comp.heroes[0].id;
							 | 
						||
| 
								 | 
							
								      expect(navArgs).toBe('/heroes/' + id,
							 | 
						||
| 
								 | 
							
								        'should nav to HeroDetail for first hero');
							 | 
						||
| 
								 | 
							
								    }));
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard.component.ts]" value="import { Component, OnInit } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { Router }            from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero, HeroService } from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'app-dashboard',
							 | 
						||
| 
								 | 
							
								  templateUrl: './dashboard.component.html',
							 | 
						||
| 
								 | 
							
								  styleUrls: [ './dashboard.component.css' ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class DashboardComponent implements OnInit {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  heroes: Hero[] = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(
							 | 
						||
| 
								 | 
							
								    private router: Router,
							 | 
						||
| 
								 | 
							
								    private heroService: HeroService) {
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnInit() {
							 | 
						||
| 
								 | 
							
								    this.heroService.getHeroes()
							 | 
						||
| 
								 | 
							
								      .then(heroes => this.heroes = heroes.slice(1, 5));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  gotoDetail(hero: Hero) {
							 | 
						||
| 
								 | 
							
								    let url = `/heroes/${hero.id}`;
							 | 
						||
| 
								 | 
							
								    this.router.navigateByUrl(url);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get title() {
							 | 
						||
| 
								 | 
							
								    let cnt = this.heroes.length;
							 | 
						||
| 
								 | 
							
								    return cnt === 0 ? 'No Heroes' :
							 | 
						||
| 
								 | 
							
								      cnt === 1 ? 'Top Hero' :  `Top ${cnt} Heroes`;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/dashboard/dashboard.module.ts]" value="import { NgModule }               from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { RouterModule, Routes }   from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { SharedModule }           from '../shared/shared.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { DashboardComponent }     from './dashboard.component';
							 | 
						||
| 
								 | 
							
								import { DashboardHeroComponent } from './dashboard-hero.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const routes: Routes =  [
							 | 
						||
| 
								 | 
							
								  { path: 'dashboard',  component: DashboardComponent },
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@NgModule({
							 | 
						||
| 
								 | 
							
								  imports:      [
							 | 
						||
| 
								 | 
							
								    SharedModule,
							 | 
						||
| 
								 | 
							
								    RouterModule.forChild(routes)
							 | 
						||
| 
								 | 
							
								  ],
							 | 
						||
| 
								 | 
							
								  declarations: [ DashboardComponent, DashboardHeroComponent ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class DashboardModule { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-detail.component.no-testbed.spec.ts]" value="import { HeroDetailComponent } from './hero-detail.component';
							 | 
						||
| 
								 | 
							
								import { Hero }                from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { ActivatedRouteStub }  from '../../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////  Tests  ////////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('HeroDetailComponent - no TestBed', () => {
							 | 
						||
| 
								 | 
							
								  let activatedRoute: ActivatedRouteStub;
							 | 
						||
| 
								 | 
							
								  let comp: HeroDetailComponent;
							 | 
						||
| 
								 | 
							
								  let expectedHero: Hero;
							 | 
						||
| 
								 | 
							
								  let hds: any;
							 | 
						||
| 
								 | 
							
								  let router: any;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( done => {
							 | 
						||
| 
								 | 
							
								    expectedHero = new Hero(42, 'Bubba');
							 | 
						||
| 
								 | 
							
								    activatedRoute = new ActivatedRouteStub();
							 | 
						||
| 
								 | 
							
								    activatedRoute.testParams = { id: expectedHero.id };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    router = jasmine.createSpyObj('router', ['navigate']);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hds = jasmine.createSpyObj('HeroDetailService', ['getHero', 'saveHero']);
							 | 
						||
| 
								 | 
							
								    hds.getHero.and.returnValue(Promise.resolve(expectedHero));
							 | 
						||
| 
								 | 
							
								    hds.saveHero.and.returnValue(Promise.resolve(expectedHero));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    comp = new HeroDetailComponent(hds, <any> activatedRoute, router);
							 | 
						||
| 
								 | 
							
								    comp.ngOnInit();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // OnInit calls HDS.getHero; wait for it to get the fake hero
							 | 
						||
| 
								 | 
							
								    hds.getHero.calls.first().returnValue.then(done);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should expose the hero retrieved from the service', () => {
							 | 
						||
| 
								 | 
							
								    expect(comp.hero).toBe(expectedHero);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate when click cancel', () => {
							 | 
						||
| 
								 | 
							
								    comp.cancel();
							 | 
						||
| 
								 | 
							
								    expect(router.navigate.calls.any()).toBe(true, 'router.navigate called');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should save when click save', () => {
							 | 
						||
| 
								 | 
							
								    comp.save();
							 | 
						||
| 
								 | 
							
								    expect(hds.saveHero.calls.any()).toBe(true, 'HeroDetailService.save called');
							 | 
						||
| 
								 | 
							
								    expect(router.navigate.calls.any()).toBe(false, 'router.navigate not called yet');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate when click save resolves', done => {
							 | 
						||
| 
								 | 
							
								    comp.save();
							 | 
						||
| 
								 | 
							
								    // waits for async save to complete before navigating
							 | 
						||
| 
								 | 
							
								    hds.saveHero.calls.first().returnValue
							 | 
						||
| 
								 | 
							
								    .then(() => {
							 | 
						||
| 
								 | 
							
								      expect(router.navigate.calls.any()).toBe(true, 'router.navigate called');
							 | 
						||
| 
								 | 
							
								      done();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-detail.component.spec.ts]" value="import {
							 | 
						||
| 
								 | 
							
								  async, ComponentFixture, fakeAsync, inject, TestBed, tick
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { By }           from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  ActivatedRoute, ActivatedRouteStub, click, newEvent, Router, RouterStub
							 | 
						||
| 
								 | 
							
								} from '../../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero }                from '../model';
							 | 
						||
| 
								 | 
							
								import { HeroDetailComponent } from './hero-detail.component';
							 | 
						||
| 
								 | 
							
								import { HeroDetailService }   from './hero-detail.service';
							 | 
						||
| 
								 | 
							
								import { HeroModule }          from './hero.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////// Testing Vars //////
							 | 
						||
| 
								 | 
							
								let activatedRoute: ActivatedRouteStub;
							 | 
						||
| 
								 | 
							
								let comp: HeroDetailComponent;
							 | 
						||
| 
								 | 
							
								let fixture: ComponentFixture<HeroDetailComponent>;
							 | 
						||
| 
								 | 
							
								let page: Page;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////// Tests //////
							 | 
						||
| 
								 | 
							
								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() {
							 | 
						||
| 
								 | 
							
								  class HeroDetailServiceSpy {
							 | 
						||
| 
								 | 
							
								    testHero = new Hero(42, 'Test Hero');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    getHero = jasmine.createSpy('getHero').and.callFake(
							 | 
						||
| 
								 | 
							
								      () => Promise
							 | 
						||
| 
								 | 
							
								        .resolve(true)
							 | 
						||
| 
								 | 
							
								        .then(() => Object.assign({}, this.testHero))
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saveHero = jasmine.createSpy('saveHero').and.callFake(
							 | 
						||
| 
								 | 
							
								      (hero: Hero) => Promise
							 | 
						||
| 
								 | 
							
								        .resolve(true)
							 | 
						||
| 
								 | 
							
								        .then(() => Object.assign(this.testHero, hero))
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // the `id` value is irrelevant because ignored by service stub
							 | 
						||
| 
								 | 
							
								  beforeEach(() => activatedRoute.testParams = { id: 99999 } );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports:   [ HeroModule ],
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: ActivatedRoute, useValue: activatedRoute },
							 | 
						||
| 
								 | 
							
								        { provide: Router,         useClass: RouterStub},
							 | 
						||
| 
								 | 
							
								        // HeroDetailService at this level is IRRELEVANT!
							 | 
						||
| 
								 | 
							
								        { provide: HeroDetailService, useValue: {} }
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Override component's own provider
							 | 
						||
| 
								 | 
							
								    .overrideComponent(HeroDetailComponent, {
							 | 
						||
| 
								 | 
							
								      set: {
							 | 
						||
| 
								 | 
							
								        providers: [
							 | 
						||
| 
								 | 
							
								          { provide: HeroDetailService, useClass: HeroDetailServiceSpy }
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let hdsSpy: HeroDetailServiceSpy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    createComponent();
							 | 
						||
| 
								 | 
							
								    // get the component's injected HeroDetailServiceSpy
							 | 
						||
| 
								 | 
							
								    hdsSpy = fixture.debugElement.injector.get(HeroDetailService);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should have called `getHero`', () => {
							 | 
						||
| 
								 | 
							
								    expect(hdsSpy.getHero.calls.count()).toBe(1, 'getHero called once');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display stub hero\'s name', () => {
							 | 
						||
| 
								 | 
							
								    expect(page.nameDisplay.textContent).toBe(hdsSpy.testHero.name);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should save stub hero change', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    const origName = hdsSpy.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(hdsSpy.testHero.name).toBe(origName, 'service hero unchanged before save');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    click(page.saveBtn);
							 | 
						||
| 
								 | 
							
								    expect(hdsSpy.saveHero.calls.count()).toBe(1, 'saveHero called once');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    tick(); // wait for async save to complete
							 | 
						||
| 
								 | 
							
								    expect(hdsSpy.testHero.name).toBe(newName, 'service hero has new name after save');
							 | 
						||
| 
								 | 
							
								    expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('fixture injected service is not the component injected service',
							 | 
						||
| 
								 | 
							
								    inject([HeroDetailService], (service: HeroDetailService) => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(service).toEqual({}, 'service injected from fixture');
							 | 
						||
| 
								 | 
							
								    expect(hdsSpy).toBeTruthy('service injected into component');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////////////////////
							 | 
						||
| 
								 | 
							
								import { HEROES, FakeHeroService } from '../model/testing';
							 | 
						||
| 
								 | 
							
								import { HeroService }             from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const firstHero = HEROES[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function heroModuleSetup() {
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								     TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports:   [ HeroModule ],
							 | 
						||
| 
								 | 
							
								  //  declarations: [ HeroDetailComponent ], // NO!  DOUBLE DECLARATION
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: ActivatedRoute, useValue: activatedRoute },
							 | 
						||
| 
								 | 
							
								        { provide: HeroService,    useClass: FakeHeroService },
							 | 
						||
| 
								 | 
							
								        { provide: Router,         useClass: RouterStub},
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  describe('when navigate to existing hero', () => {
							 | 
						||
| 
								 | 
							
								    let expectedHero: Hero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								      expectedHero = firstHero;
							 | 
						||
| 
								 | 
							
								      activatedRoute.testParams = { id: expectedHero.id };
							 | 
						||
| 
								 | 
							
								      createComponent();
							 | 
						||
| 
								 | 
							
								    }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should display that hero\'s name', () => {
							 | 
						||
| 
								 | 
							
								      expect(page.nameDisplay.textContent).toBe(expectedHero.name);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should navigate when click cancel', () => {
							 | 
						||
| 
								 | 
							
								      click(page.cancelBtn);
							 | 
						||
| 
								 | 
							
								      expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should save when click save but not navigate immediately', () => {
							 | 
						||
| 
								 | 
							
								      // Get service injected into component and spy on its`saveHero` method.
							 | 
						||
| 
								 | 
							
								      // It delegates to fake `HeroService.updateHero` which delivers a safe test result.
							 | 
						||
| 
								 | 
							
								      const hds = fixture.debugElement.injector.get(HeroDetailService);
							 | 
						||
| 
								 | 
							
								      const saveSpy = spyOn(hds, 'saveHero').and.callThrough();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      click(page.saveBtn);
							 | 
						||
| 
								 | 
							
								      expect(saveSpy.calls.any()).toBe(true, 'HeroDetailService.save called');
							 | 
						||
| 
								 | 
							
								      expect(page.navSpy.calls.any()).toBe(false, 'router.navigate not called');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should navigate when click save and save resolves', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								      click(page.saveBtn);
							 | 
						||
| 
								 | 
							
								      tick(); // wait for async save to complete
							 | 
						||
| 
								 | 
							
								      expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
							 | 
						||
| 
								 | 
							
								    }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should convert hero name to Title Case', () => {
							 | 
						||
| 
								 | 
							
								      const inputName = 'quick BROWN  fox';
							 | 
						||
| 
								 | 
							
								      const titleCaseName = 'Quick Brown  Fox';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // simulate user entering new name into the input box
							 | 
						||
| 
								 | 
							
								      page.nameInput.value = inputName;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // dispatch a DOM event so that Angular learns of input value change.
							 | 
						||
| 
								 | 
							
								      page.nameInput.dispatchEvent(newEvent('input'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Tell Angular to update the output span through the title pipe
							 | 
						||
| 
								 | 
							
								      fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      expect(page.nameDisplay.textContent).toBe(titleCaseName);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  describe('when navigate with no hero id', () => {
							 | 
						||
| 
								 | 
							
								    beforeEach( async( createComponent ));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should have hero.id === 0', () => {
							 | 
						||
| 
								 | 
							
								      expect(comp.hero.id).toBe(0);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should display empty hero name', () => {
							 | 
						||
| 
								 | 
							
								      expect(page.nameDisplay.textContent).toBe('');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  describe('when navigate to non-existant hero id', () => {
							 | 
						||
| 
								 | 
							
								    beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								      activatedRoute.testParams = { id: 99999 };
							 | 
						||
| 
								 | 
							
								      createComponent();
							 | 
						||
| 
								 | 
							
								    }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should try to navigate back to hero list', () => {
							 | 
						||
| 
								 | 
							
								      expect(page.gotoSpy.calls.any()).toBe(true, 'comp.gotoList called');
							 | 
						||
| 
								 | 
							
								      expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Why we must use `fixture.debugElement.injector` in `Page()`
							 | 
						||
| 
								 | 
							
								  it('cannot use `inject` to get component\'s provided HeroDetailService', () => {
							 | 
						||
| 
								 | 
							
								    let service: HeroDetailService;
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(HeroDetailComponent);
							 | 
						||
| 
								 | 
							
								    expect(
							 | 
						||
| 
								 | 
							
								      // Throws because `inject` only has access to TestBed's injector
							 | 
						||
| 
								 | 
							
								      // which is an ancestor of the component's injector
							 | 
						||
| 
								 | 
							
								      inject([HeroDetailService], (hds: HeroDetailService) =>  service = hds )
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    .toThrowError(/No provider for HeroDetailService/);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // get `HeroDetailService` with component's own injector
							 | 
						||
| 
								 | 
							
								    service = fixture.debugElement.injector.get(HeroDetailService);
							 | 
						||
| 
								 | 
							
								    expect(service).toBeDefined('debugElement.injector');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/////////////////////
							 | 
						||
| 
								 | 
							
								import { FormsModule }         from '@angular/forms';
							 | 
						||
| 
								 | 
							
								import { TitleCasePipe }       from '../shared/title-case.pipe';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function formsModuleSetup() {
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								     TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports:      [ FormsModule ],
							 | 
						||
| 
								 | 
							
								      declarations: [ HeroDetailComponent, TitleCasePipe ],
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: ActivatedRoute, useValue: activatedRoute },
							 | 
						||
| 
								 | 
							
								        { provide: HeroService,    useClass: FakeHeroService },
							 | 
						||
| 
								 | 
							
								        { provide: Router,         useClass: RouterStub},
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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() {
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports:      [ SharedModule ],
							 | 
						||
| 
								 | 
							
								      declarations: [ HeroDetailComponent ],
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: ActivatedRoute, useValue: activatedRoute },
							 | 
						||
| 
								 | 
							
								        { provide: HeroService,    useClass: FakeHeroService },
							 | 
						||
| 
								 | 
							
								        { provide: Router,         useClass: RouterStub},
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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 /////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Create the HeroDetailComponent, initialize it, set test variables  */
							 | 
						||
| 
								 | 
							
								function createComponent() {
							 | 
						||
| 
								 | 
							
								  fixture = TestBed.createComponent(HeroDetailComponent);
							 | 
						||
| 
								 | 
							
								  comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								  page    = new Page();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // 1st change detection triggers ngOnInit which gets a hero
							 | 
						||
| 
								 | 
							
								  fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								  return fixture.whenStable().then(() => {
							 | 
						||
| 
								 | 
							
								    // 2nd change detection displays the async-fetched hero
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    page.addPageElements();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Page {
							 | 
						||
| 
								 | 
							
								  gotoSpy:      jasmine.Spy;
							 | 
						||
| 
								 | 
							
								  navSpy:       jasmine.Spy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  saveBtn:      DebugElement;
							 | 
						||
| 
								 | 
							
								  cancelBtn:    DebugElement;
							 | 
						||
| 
								 | 
							
								  nameDisplay:  HTMLElement;
							 | 
						||
| 
								 | 
							
								  nameInput:    HTMLInputElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor() {
							 | 
						||
| 
								 | 
							
								    const router = TestBed.get(Router); // get router from root injector
							 | 
						||
| 
								 | 
							
								    this.gotoSpy = spyOn(comp, 'gotoList').and.callThrough();
							 | 
						||
| 
								 | 
							
								    this.navSpy  = spyOn(router, 'navigate');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /** Add page elements after hero arrives */
							 | 
						||
| 
								 | 
							
								  addPageElements() {
							 | 
						||
| 
								 | 
							
								    if (comp.hero) {
							 | 
						||
| 
								 | 
							
								      // have a hero so these elements are now in the DOM
							 | 
						||
| 
								 | 
							
								      const buttons    = fixture.debugElement.queryAll(By.css('button'));
							 | 
						||
| 
								 | 
							
								      this.saveBtn     = buttons[0];
							 | 
						||
| 
								 | 
							
								      this.cancelBtn   = buttons[1];
							 | 
						||
| 
								 | 
							
								      this.nameDisplay = fixture.debugElement.query(By.css('span')).nativeElement;
							 | 
						||
| 
								 | 
							
								      this.nameInput   = fixture.debugElement.query(By.css('input')).nativeElement;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-detail.component.ts]" value="/* tslint:disable:member-ordering */
							 | 
						||
| 
								 | 
							
								import { Component, Input, OnInit } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { ActivatedRoute, Router }   from '@angular/router';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/map';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero }              from '../model';
							 | 
						||
| 
								 | 
							
								import { HeroDetailService } from './hero-detail.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector:    'app-hero-detail',
							 | 
						||
| 
								 | 
							
								  templateUrl: './hero-detail.component.html',
							 | 
						||
| 
								 | 
							
								  styleUrls:  ['./hero-detail.component.css' ],
							 | 
						||
| 
								 | 
							
								  providers:  [ HeroDetailService ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class HeroDetailComponent implements OnInit {
							 | 
						||
| 
								 | 
							
								  constructor(
							 | 
						||
| 
								 | 
							
								    private heroDetailService: HeroDetailService,
							 | 
						||
| 
								 | 
							
								    private route:  ActivatedRoute,
							 | 
						||
| 
								 | 
							
								    private router: Router) {
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @Input() hero: Hero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnInit(): void {
							 | 
						||
| 
								 | 
							
								    // get hero when `id` param changes
							 | 
						||
| 
								 | 
							
								    this.route.params.map(p => p['id'])
							 | 
						||
| 
								 | 
							
								      .forEach(id => this.getHero(id))
							 | 
						||
| 
								 | 
							
								      .catch(() => this.hero = new Hero()); // no id; should edit new hero
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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(): void {
							 | 
						||
| 
								 | 
							
								    this.heroDetailService.saveHero(this.hero).then(() => this.gotoList());
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cancel() { this.gotoList(); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  gotoList() {
							 | 
						||
| 
								 | 
							
								    this.router.navigate(['../'], {relativeTo: this.route});
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-detail.service.ts]" value="import { Injectable } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero, HeroService } from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								export class HeroDetailService {
							 | 
						||
| 
								 | 
							
								  constructor(private heroService: HeroService) {  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Returns a clone which caller may modify safely
							 | 
						||
| 
								 | 
							
								  getHero(id: number | string): Promise<Hero> {
							 | 
						||
| 
								 | 
							
								    if (typeof id === 'string') {
							 | 
						||
| 
								 | 
							
								      id = parseInt(id as string, 10);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return this.heroService.getHero(id).then(hero => {
							 | 
						||
| 
								 | 
							
								      return hero ? Object.assign({}, hero) : null; // clone or null
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  saveHero(hero: Hero) {
							 | 
						||
| 
								 | 
							
								    return this.heroService.updateHero(hero);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-list.component.spec.ts]" value="import { async, ComponentFixture, fakeAsync, TestBed, tick
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { By }           from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { addMatchers, newEvent, Router, RouterStub
							 | 
						||
| 
								 | 
							
								} from '../../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HEROES, FakeHeroService } from '../model/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HeroModule }         from './hero.module';
							 | 
						||
| 
								 | 
							
								import { HeroListComponent }  from './hero-list.component';
							 | 
						||
| 
								 | 
							
								import { HighlightDirective } from '../shared/highlight.directive';
							 | 
						||
| 
								 | 
							
								import { HeroService }        from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let comp: HeroListComponent;
							 | 
						||
| 
								 | 
							
								let fixture: ComponentFixture<HeroListComponent>;
							 | 
						||
| 
								 | 
							
								let page: Page;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/////// Tests //////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('HeroListComponent', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    addMatchers();
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [HeroModule],
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        { provide: HeroService, useClass: FakeHeroService },
							 | 
						||
| 
								 | 
							
								        { provide: Router,      useClass: RouterStub}
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents()
							 | 
						||
| 
								 | 
							
								    .then(createComponent);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should display heroes', () => {
							 | 
						||
| 
								 | 
							
								    expect(page.heroRows.length).toBeGreaterThan(0);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('1st hero should match 1st test hero', () => {
							 | 
						||
| 
								 | 
							
								    const expectedHero = HEROES[0];
							 | 
						||
| 
								 | 
							
								    const actualHero = page.heroRows[0].textContent;
							 | 
						||
| 
								 | 
							
								    expect(actualHero).toContain(expectedHero.id, 'hero.id');
							 | 
						||
| 
								 | 
							
								    expect(actualHero).toContain(expectedHero.name, 'hero.name');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should select hero on click', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    const expectedHero = HEROES[1];
							 | 
						||
| 
								 | 
							
								    const li = page.heroRows[1];
							 | 
						||
| 
								 | 
							
								    li.dispatchEvent(newEvent('click'));
							 | 
						||
| 
								 | 
							
								    tick();
							 | 
						||
| 
								 | 
							
								    // `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService
							 | 
						||
| 
								 | 
							
								    expect(comp.selectedHero).toEqual(expectedHero);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should navigate to selected hero detail on click', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    const expectedHero = HEROES[1];
							 | 
						||
| 
								 | 
							
								    const li = page.heroRows[1];
							 | 
						||
| 
								 | 
							
								    li.dispatchEvent(newEvent('click'));
							 | 
						||
| 
								 | 
							
								    tick();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // should have navigated
							 | 
						||
| 
								 | 
							
								    expect(page.navSpy.calls.any()).toBe(true, 'navigate called');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // composed hero detail will be URL like 'heroes/42'
							 | 
						||
| 
								 | 
							
								    // expect link array with the route path and hero id
							 | 
						||
| 
								 | 
							
								    // first argument to router.navigate is link array
							 | 
						||
| 
								 | 
							
								    const navArgs = page.navSpy.calls.first().args[0];
							 | 
						||
| 
								 | 
							
								    expect(navArgs[0]).toContain('heroes', 'nav to heroes detail URL');
							 | 
						||
| 
								 | 
							
								    expect(navArgs[1]).toBe(expectedHero.id, 'expected hero.id');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should find `HighlightDirective` with `By.directive', () => {
							 | 
						||
| 
								 | 
							
								    // Can find DebugElement either by css selector or by directive
							 | 
						||
| 
								 | 
							
								    const h2        = fixture.debugElement.query(By.css('h2'));
							 | 
						||
| 
								 | 
							
								    const directive = fixture.debugElement.query(By.directive(HighlightDirective));
							 | 
						||
| 
								 | 
							
								    expect(h2).toBe(directive);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should color header with `HighlightDirective`', () => {
							 | 
						||
| 
								 | 
							
								    const h2 = page.highlightDe.nativeElement as HTMLElement;
							 | 
						||
| 
								 | 
							
								    const bgColor = h2.style.backgroundColor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // different browsers report color values differently
							 | 
						||
| 
								 | 
							
								    const isExpectedColor = bgColor === 'gold' || bgColor === 'rgb(255, 215, 0)';
							 | 
						||
| 
								 | 
							
								    expect(isExpectedColor).toBe(true, 'backgroundColor');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('the `HighlightDirective` is among the element\'s providers', () => {
							 | 
						||
| 
								 | 
							
								    expect(page.highlightDe.providerTokens).toContain(HighlightDirective, 'HighlightDirective');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/////////// Helpers /////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Create the component and set the `page` test variables */
							 | 
						||
| 
								 | 
							
								function createComponent() {
							 | 
						||
| 
								 | 
							
								  fixture = TestBed.createComponent(HeroListComponent);
							 | 
						||
| 
								 | 
							
								  comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // change detection triggers ngOnInit which gets a hero
							 | 
						||
| 
								 | 
							
								  fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return fixture.whenStable().then(() => {
							 | 
						||
| 
								 | 
							
								    // got the heroes and updated component
							 | 
						||
| 
								 | 
							
								    // change detection updates the view
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    page = new Page();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Page {
							 | 
						||
| 
								 | 
							
								  /** Hero line elements */
							 | 
						||
| 
								 | 
							
								  heroRows: HTMLLIElement[];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /** Highlighted element */
							 | 
						||
| 
								 | 
							
								  highlightDe: DebugElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /** Spy on router navigate method */
							 | 
						||
| 
								 | 
							
								  navSpy: jasmine.Spy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor() {
							 | 
						||
| 
								 | 
							
								    this.heroRows    = fixture.debugElement.queryAll(By.css('li')).map(de => de.nativeElement);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Find the first element with an attached HighlightDirective
							 | 
						||
| 
								 | 
							
								    this.highlightDe = fixture.debugElement.query(By.directive(HighlightDirective));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Get the component's injected router and spy on it
							 | 
						||
| 
								 | 
							
								    const router = fixture.debugElement.injector.get(Router);
							 | 
						||
| 
								 | 
							
								    this.navSpy = spyOn(router, 'navigate');
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-list.component.ts]" value="import { Component, OnInit } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { Router }            from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero, HeroService } from '../model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'app-heroes',
							 | 
						||
| 
								 | 
							
								  templateUrl: './hero-list.component.html',
							 | 
						||
| 
								 | 
							
								  styleUrls: [ './hero-list.component.css' ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class HeroListComponent implements OnInit {
							 | 
						||
| 
								 | 
							
								  heroes: Promise<Hero[]>;
							 | 
						||
| 
								 | 
							
								  selectedHero: Hero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(
							 | 
						||
| 
								 | 
							
								    private router: Router,
							 | 
						||
| 
								 | 
							
								    private heroService: HeroService) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnInit() {
							 | 
						||
| 
								 | 
							
								    this.heroes = this.heroService.getHeroes();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  onSelect(hero: Hero) {
							 | 
						||
| 
								 | 
							
								    this.selectedHero = hero;
							 | 
						||
| 
								 | 
							
								    this.router.navigate(['../heroes', this.selectedHero.id ]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero-routing.module.ts]" value="import { NgModule }             from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { RouterModule, Routes } from '@angular/router';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HeroListComponent }    from './hero-list.component';
							 | 
						||
| 
								 | 
							
								import { HeroDetailComponent }  from './hero-detail.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const routes: Routes =  [
							 | 
						||
| 
								 | 
							
								  { path: '',    component: HeroListComponent },
							 | 
						||
| 
								 | 
							
								  { path: ':id', component: HeroDetailComponent }
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export const routedComponents = [HeroDetailComponent, HeroListComponent];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@NgModule({
							 | 
						||
| 
								 | 
							
								  imports: [RouterModule.forChild(routes)],
							 | 
						||
| 
								 | 
							
								  exports: [RouterModule]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class HeroRoutingModule {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero/hero.module.ts]" value="import { NgModule }     from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { SharedModule } from '../shared/shared.module';
							 | 
						||
| 
								 | 
							
								import { routedComponents, HeroRoutingModule } from './hero-routing.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@NgModule({
							 | 
						||
| 
								 | 
							
								  imports:      [ SharedModule, HeroRoutingModule ],
							 | 
						||
| 
								 | 
							
								  declarations: [ routedComponents ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class HeroModule { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/hero.service.ts]" value="import { Injectable } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero }       from './hero';
							 | 
						||
| 
								 | 
							
								import { HEROES }     from './test-heroes';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								/** Dummy HeroService. Pretend it makes real http requests */
							 | 
						||
| 
								 | 
							
								export class HeroService {
							 | 
						||
| 
								 | 
							
								  getHeroes() {
							 | 
						||
| 
								 | 
							
								    return Promise.resolve(HEROES);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getHero(id: number | string): Promise<Hero> {
							 | 
						||
| 
								 | 
							
								    if (typeof id === 'string') {
							 | 
						||
| 
								 | 
							
								      id = parseInt(id as string, 10);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return this.getHeroes().then(
							 | 
						||
| 
								 | 
							
								      heroes => heroes.find(hero => hero.id === id)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  updateHero(hero: Hero): Promise<Hero> {
							 | 
						||
| 
								 | 
							
								    return this.getHero(hero.id).then(h => {
							 | 
						||
| 
								 | 
							
								      if (!h) {
							 | 
						||
| 
								 | 
							
								        throw new Error(`Hero ${hero.id} not found`);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return Object.assign(h, hero);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/hero.spec.ts]" value="import { Hero } from './hero';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('Hero', () => {
							 | 
						||
| 
								 | 
							
								  it('has name', () => {
							 | 
						||
| 
								 | 
							
								    const hero = new Hero(1, 'Super Cat');
							 | 
						||
| 
								 | 
							
								    expect(hero.name).toBe('Super Cat');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('has id', () => {
							 | 
						||
| 
								 | 
							
								    const hero = new Hero(1, 'Super Cat');
							 | 
						||
| 
								 | 
							
								    expect(hero.id).toBe(1);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can clone itself', () => {
							 | 
						||
| 
								 | 
							
								    const hero = new Hero(1, 'Super Cat');
							 | 
						||
| 
								 | 
							
								    const clone = hero.clone();
							 | 
						||
| 
								 | 
							
								    expect(hero).toEqual(clone);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/hero.ts]" value="export class Hero {
							 | 
						||
| 
								 | 
							
								  constructor(public id = 0, public name = '') { }
							 | 
						||
| 
								 | 
							
								  clone() { return new Hero(this.id, this.name); }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/http-hero.service.spec.ts]" value="import {
							 | 
						||
| 
								 | 
							
								   async, inject, TestBed
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  MockBackend,
							 | 
						||
| 
								 | 
							
								  MockConnection
							 | 
						||
| 
								 | 
							
								} from '@angular/http/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  HttpModule, Http, XHRBackend, Response, ResponseOptions
							 | 
						||
| 
								 | 
							
								} from '@angular/http';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Observable } from 'rxjs/Observable';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/observable/of';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/catch';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/do';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/toPromise';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero } from './hero';
							 | 
						||
| 
								 | 
							
								import { HttpHeroService as HeroService } from './http-hero.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const makeHeroData = () => [
							 | 
						||
| 
								 | 
							
								  { id: 1, name: 'Windstorm' },
							 | 
						||
| 
								 | 
							
								  { id: 2, name: 'Bombasto' },
							 | 
						||
| 
								 | 
							
								  { id: 3, name: 'Magneta' },
							 | 
						||
| 
								 | 
							
								  { id: 4, name: 'Tornado' }
							 | 
						||
| 
								 | 
							
								] as Hero[];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////////  Tests  /////////////
							 | 
						||
| 
								 | 
							
								describe('Http-HeroService (mockBackend)', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [ HttpModule ],
							 | 
						||
| 
								 | 
							
								      providers: [
							 | 
						||
| 
								 | 
							
								        HeroService,
							 | 
						||
| 
								 | 
							
								        { provide: XHRBackend, useClass: MockBackend }
							 | 
						||
| 
								 | 
							
								      ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can instantiate service when inject service',
							 | 
						||
| 
								 | 
							
								    inject([HeroService], (service: HeroService) => {
							 | 
						||
| 
								 | 
							
								      expect(service instanceof HeroService).toBe(true);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can instantiate service with "new"', inject([Http], (http: Http) => {
							 | 
						||
| 
								 | 
							
								    expect(http).not.toBeNull('http should be provided');
							 | 
						||
| 
								 | 
							
								    let service = new HeroService(http);
							 | 
						||
| 
								 | 
							
								    expect(service instanceof HeroService).toBe(true, 'new service should be ok');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can provide the mockBackend as XHRBackend',
							 | 
						||
| 
								 | 
							
								    inject([XHRBackend], (backend: MockBackend) => {
							 | 
						||
| 
								 | 
							
								      expect(backend).not.toBeNull('backend should be provided');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  describe('when getHeroes', () => {
							 | 
						||
| 
								 | 
							
								      let backend: MockBackend;
							 | 
						||
| 
								 | 
							
								      let service: HeroService;
							 | 
						||
| 
								 | 
							
								      let fakeHeroes: Hero[];
							 | 
						||
| 
								 | 
							
								      let response: Response;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      beforeEach(inject([Http, XHRBackend], (http: Http, be: MockBackend) => {
							 | 
						||
| 
								 | 
							
								        backend = be;
							 | 
						||
| 
								 | 
							
								        service = new HeroService(http);
							 | 
						||
| 
								 | 
							
								        fakeHeroes = makeHeroData();
							 | 
						||
| 
								 | 
							
								        let options = new ResponseOptions({status: 200, body: {data: fakeHeroes}});
							 | 
						||
| 
								 | 
							
								        response = new Response(options);
							 | 
						||
| 
								 | 
							
								      }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should have expected fake heroes (then)', async(inject([], () => {
							 | 
						||
| 
								 | 
							
								        backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        service.getHeroes().toPromise()
							 | 
						||
| 
								 | 
							
								        // .then(() => Promise.reject('deliberate'))
							 | 
						||
| 
								 | 
							
								          .then(heroes => {
							 | 
						||
| 
								 | 
							
								            expect(heroes.length).toBe(fakeHeroes.length,
							 | 
						||
| 
								 | 
							
								              'should have expected no. of heroes');
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								      })));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should have expected fake heroes (Observable.do)', async(inject([], () => {
							 | 
						||
| 
								 | 
							
								        backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        service.getHeroes()
							 | 
						||
| 
								 | 
							
								          .do(heroes => {
							 | 
						||
| 
								 | 
							
								            expect(heroes.length).toBe(fakeHeroes.length,
							 | 
						||
| 
								 | 
							
								              'should have expected no. of heroes');
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								          .toPromise();
							 | 
						||
| 
								 | 
							
								      })));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should be OK returning no heroes', async(inject([], () => {
							 | 
						||
| 
								 | 
							
								        let resp = new Response(new ResponseOptions({status: 200, body: {data: []}}));
							 | 
						||
| 
								 | 
							
								        backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        service.getHeroes()
							 | 
						||
| 
								 | 
							
								          .do(heroes => {
							 | 
						||
| 
								 | 
							
								            expect(heroes.length).toBe(0, 'should have no heroes');
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								          .toPromise();
							 | 
						||
| 
								 | 
							
								      })));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should treat 404 as an Observable error', async(inject([], () => {
							 | 
						||
| 
								 | 
							
								        let resp = new Response(new ResponseOptions({status: 404}));
							 | 
						||
| 
								 | 
							
								        backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        service.getHeroes()
							 | 
						||
| 
								 | 
							
								          .do(heroes => {
							 | 
						||
| 
								 | 
							
								            fail('should not respond with heroes');
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								          .catch(err => {
							 | 
						||
| 
								 | 
							
								            expect(err).toMatch(/Bad response status/, 'should catch bad response status code');
							 | 
						||
| 
								 | 
							
								            return Observable.of(null); // failure is the expected test result
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								          .toPromise();
							 | 
						||
| 
								 | 
							
								      })));
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/http-hero.service.ts]" value="import { Injectable }     from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { Http, Response } from '@angular/http';
							 | 
						||
| 
								 | 
							
								import { Headers, RequestOptions } from '@angular/http';
							 | 
						||
| 
								 | 
							
								import { Hero }           from './hero';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Observable }     from 'rxjs/Observable';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/observable/throw';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/do';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/catch';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/map';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								export class HttpHeroService {
							 | 
						||
| 
								 | 
							
								  private _heroesUrl = 'app/heroes';  // URL to web api
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor (private http: Http) {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getHeroes (): Observable<Hero[]> {
							 | 
						||
| 
								 | 
							
								    return this.http.get(this._heroesUrl)
							 | 
						||
| 
								 | 
							
								                    .map(this.extractData)
							 | 
						||
| 
								 | 
							
								                    // .do(data => console.log(data)) // eyeball results in the console
							 | 
						||
| 
								 | 
							
								                    .catch(this.handleError);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getHero(id: number | string) {
							 | 
						||
| 
								 | 
							
								    return this.http
							 | 
						||
| 
								 | 
							
								            .get('app/heroes/?id=${id}')
							 | 
						||
| 
								 | 
							
								            .map((r: Response) => r.json().data as Hero[]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addHero (name: string): Observable<Hero>  {
							 | 
						||
| 
								 | 
							
								    let body = JSON.stringify({ name });
							 | 
						||
| 
								 | 
							
								    let headers = new Headers({ 'Content-Type': 'application/json' });
							 | 
						||
| 
								 | 
							
								    let options = new RequestOptions({ headers: headers });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this.http.post(this._heroesUrl, body, options)
							 | 
						||
| 
								 | 
							
								                    .map(this.extractData)
							 | 
						||
| 
								 | 
							
								                    .catch(this.handleError);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  updateHero (hero: Hero): Observable<Hero>  {
							 | 
						||
| 
								 | 
							
								    let body = JSON.stringify(hero);
							 | 
						||
| 
								 | 
							
								    let headers = new Headers({ 'Content-Type': 'application/json' });
							 | 
						||
| 
								 | 
							
								    let options = new RequestOptions({ headers: headers });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this.http.put(this._heroesUrl, body, options)
							 | 
						||
| 
								 | 
							
								                    .map(this.extractData)
							 | 
						||
| 
								 | 
							
								                    .catch(this.handleError);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  private extractData(res: Response) {
							 | 
						||
| 
								 | 
							
								    if (res.status < 200 || res.status >= 300) {
							 | 
						||
| 
								 | 
							
								      throw new Error('Bad response status: ' + res.status);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    let body = res.json();
							 | 
						||
| 
								 | 
							
								    return body.data || { };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  private handleError (error: any) {
							 | 
						||
| 
								 | 
							
								    // In a real world app, we might send the error to remote logging infrastructure
							 | 
						||
| 
								 | 
							
								    let errMsg = error.message || 'Server error';
							 | 
						||
| 
								 | 
							
								    console.error(errMsg); // log to console instead
							 | 
						||
| 
								 | 
							
								    return Observable.throw(errMsg);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/index.ts]" value="// Model barrel
							 | 
						||
| 
								 | 
							
								export * from './hero';
							 | 
						||
| 
								 | 
							
								export * from './hero.service';
							 | 
						||
| 
								 | 
							
								export * from './http-hero.service';
							 | 
						||
| 
								 | 
							
								export * from './test-heroes';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export * from './user.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/test-heroes.ts]" value="import { Hero } from './hero';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export var HEROES: Hero[] = [
							 | 
						||
| 
								 | 
							
								  new Hero(11, 'Mr. Nice'),
							 | 
						||
| 
								 | 
							
								  new Hero(12, 'Narco'),
							 | 
						||
| 
								 | 
							
								  new Hero(13, 'Bombasto'),
							 | 
						||
| 
								 | 
							
								  new Hero(14, 'Celeritas'),
							 | 
						||
| 
								 | 
							
								  new Hero(15, 'Magneta'),
							 | 
						||
| 
								 | 
							
								  new Hero(16, 'RubberMan')
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/testing/fake-hero.service.ts]" value="// re-export for tester convenience
							 | 
						||
| 
								 | 
							
								export { Hero }        from '../hero';
							 | 
						||
| 
								 | 
							
								export { HeroService } from '../hero.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero }        from '../hero';
							 | 
						||
| 
								 | 
							
								import { HeroService } from '../hero.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export var HEROES: Hero[] = [
							 | 
						||
| 
								 | 
							
								  new Hero(41, 'Bob'),
							 | 
						||
| 
								 | 
							
								  new Hero(42, 'Carol'),
							 | 
						||
| 
								 | 
							
								  new Hero(43, 'Ted'),
							 | 
						||
| 
								 | 
							
								  new Hero(44, 'Alice'),
							 | 
						||
| 
								 | 
							
								  new Hero(45, 'Speedy'),
							 | 
						||
| 
								 | 
							
								  new Hero(46, 'Stealthy')
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export class FakeHeroService implements HeroService {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  heroes = HEROES.map(h => h.clone());
							 | 
						||
| 
								 | 
							
								  lastPromise: Promise<any>;  // remember so we can spy on promise calls
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getHero(id: number | string) {
							 | 
						||
| 
								 | 
							
								    if (typeof id === 'string') {
							 | 
						||
| 
								 | 
							
								      id = parseInt(id as string, 10);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    let hero = this.heroes.find(h => h.id === id);
							 | 
						||
| 
								 | 
							
								    return this.lastPromise = Promise.resolve(hero);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getHeroes() {
							 | 
						||
| 
								 | 
							
								    return this.lastPromise = Promise.resolve<Hero[]>(this.heroes);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  updateHero(hero: Hero): Promise<Hero> {
							 | 
						||
| 
								 | 
							
								    return this.lastPromise = this.getHero(hero.id).then(h => {
							 | 
						||
| 
								 | 
							
								      return h ?
							 | 
						||
| 
								 | 
							
								        Object.assign(h, hero) :
							 | 
						||
| 
								 | 
							
								        Promise.reject(`Hero ${hero.id} not found`) as any as Promise<Hero>;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/testing/index.ts]" value="export * from './fake-hero.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/model/user.service.ts]" value="import { Injectable } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								export class UserService {
							 | 
						||
| 
								 | 
							
								  isLoggedIn = true;
							 | 
						||
| 
								 | 
							
								  user = {name: 'Sam Spade'};
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/highlight.directive.spec.ts]" value="import { Component, DebugElement }   from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { ComponentFixture, TestBed } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { By } from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HighlightDirective } from './highlight.directive';
							 | 
						||
| 
								 | 
							
								import { newEvent }           from '../../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  template: `
							 | 
						||
| 
								 | 
							
								  <h2 highlight="yellow">Something Yellow</h2>
							 | 
						||
| 
								 | 
							
								  <h2 highlight>The Default (Gray)</h2>
							 | 
						||
| 
								 | 
							
								  <h2>No Highlight</h2>
							 | 
						||
| 
								 | 
							
								  <input #box [highlight]="box.value" value="cyan"/>`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								class TestComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('HighlightDirective', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<TestComponent>;
							 | 
						||
| 
								 | 
							
								  let des: DebugElement[];  // the three elements w/ the directive
							 | 
						||
| 
								 | 
							
								  let bareH2: DebugElement; // the <h2> w/o the directive
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ HighlightDirective, TestComponent ]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .createComponent(TestComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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])'));
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // color tests
							 | 
						||
| 
								 | 
							
								  it('should have three highlighted elements', () => {
							 | 
						||
| 
								 | 
							
								    expect(des.length).toBe(3);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should color 1st <h2> background "yellow"', () => {
							 | 
						||
| 
								 | 
							
								    const bgColor = des[0].nativeElement.style.backgroundColor;
							 | 
						||
| 
								 | 
							
								    expect(bgColor).toBe('yellow');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should color 2nd <h2> background w/ default color', () => {
							 | 
						||
| 
								 | 
							
								    const dir = des[1].injector.get(HighlightDirective) as HighlightDirective;
							 | 
						||
| 
								 | 
							
								    const bgColor = des[1].nativeElement.style.backgroundColor;
							 | 
						||
| 
								 | 
							
								    expect(bgColor).toBe(dir.defaultColor);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should bind <input> background to value color', () => {
							 | 
						||
| 
								 | 
							
								    // easier to work with nativeElement
							 | 
						||
| 
								 | 
							
								    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();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(input.style.backgroundColor).toBe('green', 'changed backgroundColor');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('bare <h2> should not have a customProperty', () => {
							 | 
						||
| 
								 | 
							
								    expect(bareH2.properties['customProperty']).toBeUndefined();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future?
							 | 
						||
| 
								 | 
							
								  // // 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);
							 | 
						||
| 
								 | 
							
								  // });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // 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);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/highlight.directive.ts]" value="import { Directive, ElementRef, Input, OnChanges } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Directive({ selector: '[highlight]' })
							 | 
						||
| 
								 | 
							
								/** Set backgroundColor for the attached element to highlight color
							 | 
						||
| 
								 | 
							
								 *  and set the element's customProperty to true */
							 | 
						||
| 
								 | 
							
								export class HighlightDirective implements OnChanges {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  defaultColor =  'rgb(211, 211, 211)'; // lightgray
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @Input('highlight') bgColor: string;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(private el: ElementRef) {
							 | 
						||
| 
								 | 
							
								    el.nativeElement.style.customProperty = true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnChanges() {
							 | 
						||
| 
								 | 
							
								    this.el.nativeElement.style.backgroundColor = this.bgColor || this.defaultColor;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/shared.module.ts]" value="import { NgModule }      from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { CommonModule }  from '@angular/common';
							 | 
						||
| 
								 | 
							
								import { FormsModule }   from '@angular/forms';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HighlightDirective } from './highlight.directive';
							 | 
						||
| 
								 | 
							
								import { TitleCasePipe }      from './title-case.pipe';
							 | 
						||
| 
								 | 
							
								import { TwainComponent }     from './twain.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@NgModule({
							 | 
						||
| 
								 | 
							
								  imports:      [ CommonModule ],
							 | 
						||
| 
								 | 
							
								  exports:      [ CommonModule, FormsModule,
							 | 
						||
| 
								 | 
							
								                  HighlightDirective, TitleCasePipe, TwainComponent ],
							 | 
						||
| 
								 | 
							
								  declarations: [ HighlightDirective, TitleCasePipe, TwainComponent ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class SharedModule { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/title-case.pipe.spec.ts]" value="import { TitleCasePipe } from './title-case.pipe';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('TitleCasePipe', () => {
							 | 
						||
| 
								 | 
							
								  // This pipe is a pure, stateless function so no need for BeforeEach
							 | 
						||
| 
								 | 
							
								  let pipe = new TitleCasePipe();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('transforms "abc" to "Abc"', () => {
							 | 
						||
| 
								 | 
							
								    expect(pipe.transform('abc')).toBe('Abc');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('transforms "abc def" to "Abc Def"', () => {
							 | 
						||
| 
								 | 
							
								    expect(pipe.transform('abc def')).toBe('Abc Def');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // ... more tests ...
							 | 
						||
| 
								 | 
							
								  it('leaves "Abc Def" unchanged', () => {
							 | 
						||
| 
								 | 
							
								    expect(pipe.transform('Abc Def')).toBe('Abc Def');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('transforms "abc-def" to "Abc-def"', () => {
							 | 
						||
| 
								 | 
							
								    expect(pipe.transform('abc-def')).toBe('Abc-def');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('transforms "   abc   def" to "   Abc   Def" (preserves spaces) ', () => {
							 | 
						||
| 
								 | 
							
								    expect(pipe.transform('   abc   def')).toBe('   Abc   Def');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/title-case.pipe.ts]" value="import { Pipe, PipeTransform } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Pipe({name: 'titlecase', pure: false})
							 | 
						||
| 
								 | 
							
								/** Transform to Title Case: uppercase the first letter of the words in a string.*/
							 | 
						||
| 
								 | 
							
								export class TitleCasePipe implements PipeTransform {
							 | 
						||
| 
								 | 
							
								  transform(input: string): string {
							 | 
						||
| 
								 | 
							
								    return input.length === 0 ? '' :
							 | 
						||
| 
								 | 
							
								      input.replace(/\w\S*/g, (txt => txt[0].toUpperCase() + txt.substr(1).toLowerCase() ));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/twain.component.spec.ts]" value="import { async, fakeAsync, ComponentFixture, TestBed, tick } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { By }                        from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement }              from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { TwainService }   from './twain.service';
							 | 
						||
| 
								 | 
							
								import { TwainComponent } from './twain.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('TwainComponent', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let comp: TwainComponent;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<TwainComponent>;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let spy: jasmine.Spy;
							 | 
						||
| 
								 | 
							
								  let de: DebugElement;
							 | 
						||
| 
								 | 
							
								  let el: HTMLElement;
							 | 
						||
| 
								 | 
							
								  let twainService: TwainService; // the actually injected service
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const testQuote = 'Test Quote';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								       declarations: [ TwainComponent ],
							 | 
						||
| 
								 | 
							
								       providers:    [ TwainService ],
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(TwainComponent);
							 | 
						||
| 
								 | 
							
								    comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // TwainService actually injected into the component
							 | 
						||
| 
								 | 
							
								    twainService = fixture.debugElement.injector.get(TwainService);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Setup spy on the `getQuote` method
							 | 
						||
| 
								 | 
							
								    spy = spyOn(twainService, 'getQuote')
							 | 
						||
| 
								 | 
							
								          .and.returnValue(Promise.resolve(testQuote));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Get the Twain quote element by CSS selector (e.g., by class name)
							 | 
						||
| 
								 | 
							
								    de = fixture.debugElement.query(By.css('.twain'));
							 | 
						||
| 
								 | 
							
								    el = de.nativeElement;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should not show quote before OnInit', () => {
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toBe('', 'nothing displayed');
							 | 
						||
| 
								 | 
							
								    expect(spy.calls.any()).toBe(false, 'getQuote not yet called');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should still not show quote after component initialized', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    // getQuote service is async => still has not returned with quote
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toBe('...', 'no quote yet');
							 | 
						||
| 
								 | 
							
								    expect(spy.calls.any()).toBe(true, 'getQuote called');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should show quote after getQuote promise (async)', async(() => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.whenStable().then(() => { // wait for async getQuote
							 | 
						||
| 
								 | 
							
								      fixture.detectChanges();        // update view with quote
							 | 
						||
| 
								 | 
							
								      expect(el.textContent).toBe(testQuote);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should show quote after getQuote promise (fakeAsync)', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    tick();                  // wait for async getQuote
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges(); // update view with quote
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toBe(testQuote);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should show quote after getQuote promise (done)', done => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // get the spy promise and wait for it to resolve
							 | 
						||
| 
								 | 
							
								    spy.calls.mostRecent().returnValue.then(() => {
							 | 
						||
| 
								 | 
							
								      fixture.detectChanges(); // update view with quote
							 | 
						||
| 
								 | 
							
								      expect(el.textContent).toBe(testQuote);
							 | 
						||
| 
								 | 
							
								      done();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/twain.component.ts]" value="import { Component, OnInit } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { TwainService } from './twain.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  selector: 'twain-quote',
							 | 
						||
| 
								 | 
							
								  template: '<p class="twain"><i>{{quote}}</i></p>'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class TwainComponent  implements OnInit {
							 | 
						||
| 
								 | 
							
								  intervalId: number;
							 | 
						||
| 
								 | 
							
								  quote = '...';
							 | 
						||
| 
								 | 
							
								  constructor(private twainService: TwainService) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnInit(): void {
							 | 
						||
| 
								 | 
							
								    this.twainService.getQuote().then(quote => this.quote = quote);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/shared/twain.service.ts]" value="import { Injectable } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const quotes = [
							 | 
						||
| 
								 | 
							
								'Always do right. This will gratify some people and astonish the rest.',
							 | 
						||
| 
								 | 
							
								'I have never let my schooling interfere with my education.',
							 | 
						||
| 
								 | 
							
								'Don\'t go around saying the world owes you a living. The world owes you nothing. It was here first.',
							 | 
						||
| 
								 | 
							
								'Whenever you find yourself on the side of the majority, it is time to pause and reflect.',
							 | 
						||
| 
								 | 
							
								'If you tell the truth, you don\'t have to remember anything.',
							 | 
						||
| 
								 | 
							
								'Clothes make the man. Naked people have little or no influence on society.',
							 | 
						||
| 
								 | 
							
								'It\'s not the size of the dog in the fight, it\'s the size of the fight in the dog.',
							 | 
						||
| 
								 | 
							
								'Truth is stranger than fiction, but it is because Fiction is obliged to stick to possibilities; Truth isn\'t.',
							 | 
						||
| 
								 | 
							
								'The man who does not read good books has no advantage over the man who cannot read them.',
							 | 
						||
| 
								 | 
							
								'Get your facts first, and then you can distort them as much as you please.',
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								export class TwainService {
							 | 
						||
| 
								 | 
							
								  private next = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Imaginary todo: get quotes from a remote quote service
							 | 
						||
| 
								 | 
							
								  // returns quote after delay simulating server latency
							 | 
						||
| 
								 | 
							
								  getQuote(): Promise<string> {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      setTimeout( () => resolve(this.nextQuote()), 500 );
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  private nextQuote() {
							 | 
						||
| 
								 | 
							
								    if (this.next === quotes.length) { this.next = 0; }
							 | 
						||
| 
								 | 
							
								    return quotes[ this.next++ ];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/welcome.component.spec.ts]" value="import { ComponentFixture, inject, TestBed } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								import { By }                                from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { DebugElement }                      from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { UserService }      from './model';
							 | 
						||
| 
								 | 
							
								import { WelcomeComponent } from './welcome.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('WelcomeComponent', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let comp: WelcomeComponent;
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<WelcomeComponent>;
							 | 
						||
| 
								 | 
							
								  let componentUserService: UserService; // the actually injected service
							 | 
						||
| 
								 | 
							
								  let userService: UserService; // the TestBed injected service
							 | 
						||
| 
								 | 
							
								  let de: DebugElement;  // the DebugElement with the welcome message
							 | 
						||
| 
								 | 
							
								  let el: HTMLElement; // the DOM element with the welcome message
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let userServiceStub: {
							 | 
						||
| 
								 | 
							
								    isLoggedIn: boolean;
							 | 
						||
| 
								 | 
							
								    user: { name: string}
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    // stub UserService for test purposes
							 | 
						||
| 
								 | 
							
								    userServiceStub = {
							 | 
						||
| 
								 | 
							
								      isLoggedIn: true,
							 | 
						||
| 
								 | 
							
								      user: { name: 'Test User'}
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								       declarations: [ WelcomeComponent ],
							 | 
						||
| 
								 | 
							
								    // providers:    [ UserService ]  // NO! Don't provide the real service!
							 | 
						||
| 
								 | 
							
								                                      // Provide a test-double instead
							 | 
						||
| 
								 | 
							
								       providers:    [ {provide: UserService, useValue: userServiceStub } ]
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture = TestBed.createComponent(WelcomeComponent);
							 | 
						||
| 
								 | 
							
								    comp    = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // UserService actually injected into the component
							 | 
						||
| 
								 | 
							
								    userService = fixture.debugElement.injector.get(UserService);
							 | 
						||
| 
								 | 
							
								    componentUserService = userService;
							 | 
						||
| 
								 | 
							
								    // UserService from the root injector
							 | 
						||
| 
								 | 
							
								    userService = TestBed.get(UserService);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  get the "welcome" element by CSS selector (e.g., by class name)
							 | 
						||
| 
								 | 
							
								    de = fixture.debugElement.query(By.css('.welcome'));
							 | 
						||
| 
								 | 
							
								    el = de.nativeElement;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should welcome the user', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    const content = el.textContent;
							 | 
						||
| 
								 | 
							
								    expect(content).toContain('Welcome', '"Welcome ..."');
							 | 
						||
| 
								 | 
							
								    expect(content).toContain('Test User', 'expected name');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should welcome "Bubba"', () => {
							 | 
						||
| 
								 | 
							
								    userService.user.name = 'Bubba'; // welcome message hasn't been shown yet
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(el.textContent).toContain('Bubba');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should request login if not logged in', () => {
							 | 
						||
| 
								 | 
							
								    userService.isLoggedIn = false; // welcome message hasn't been shown yet
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    const content = el.textContent;
							 | 
						||
| 
								 | 
							
								    expect(content).not.toContain('Welcome', 'not welcomed');
							 | 
						||
| 
								 | 
							
								    expect(content).toMatch(/log in/i, '"log in"');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should inject the component\'s UserService instance',
							 | 
						||
| 
								 | 
							
								    inject([UserService], (service: UserService) => {
							 | 
						||
| 
								 | 
							
								    expect(service).toBe(componentUserService);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('TestBed and Component UserService should be the same', () => {
							 | 
						||
| 
								 | 
							
								    expect(userService === componentUserService).toBe(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('stub object and injected UserService should not be the same', () => {
							 | 
						||
| 
								 | 
							
								    expect(userServiceStub === userService).toBe(false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Changing the stub object has no effect on the injected service
							 | 
						||
| 
								 | 
							
								    userServiceStub.isLoggedIn = false;
							 | 
						||
| 
								 | 
							
								    expect(userService.isLoggedIn).toBe(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/welcome.component.ts]" value="import { Component, OnInit } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { UserService }       from './model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  selector: 'app-welcome',
							 | 
						||
| 
								 | 
							
								  template: '<h3 class="welcome" ><i>{{welcome}}</i></h3>'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class WelcomeComponent  implements OnInit {
							 | 
						||
| 
								 | 
							
								  welcome = '-- not initialized yet --';
							 | 
						||
| 
								 | 
							
								  constructor(private userService: UserService) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnInit(): void {
							 | 
						||
| 
								 | 
							
								    this.welcome = this.userService.isLoggedIn ?
							 | 
						||
| 
								 | 
							
								      'Welcome, ' + this.userService.user.name :
							 | 
						||
| 
								 | 
							
								      'Please log in.';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[testing/index.ts]" value="import { DebugElement }           from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { tick, ComponentFixture } from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export * from './jasmine-matchers';
							 | 
						||
| 
								 | 
							
								export * from './router-stubs';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///// Short utilities /////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Wait a tick, then detect changes */
							 | 
						||
| 
								 | 
							
								export function advance(f: ComponentFixture<any>): void {
							 | 
						||
| 
								 | 
							
								  tick();
							 | 
						||
| 
								 | 
							
								  f.detectChanges();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Create custom DOM event the old fashioned way
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent
							 | 
						||
| 
								 | 
							
								 * Although officially deprecated, some browsers (phantom) don't accept the preferred "new Event(eventName)"
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								export function newEvent(eventName: string, bubbles = false, cancelable = false) {
							 | 
						||
| 
								 | 
							
								  let evt = document.createEvent('CustomEvent');  // MUST be 'CustomEvent'
							 | 
						||
| 
								 | 
							
								  evt.initCustomEvent(eventName, bubbles, cancelable, null);
							 | 
						||
| 
								 | 
							
								  return evt;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
							 | 
						||
| 
								 | 
							
								/** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */
							 | 
						||
| 
								 | 
							
								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);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[testing/jasmine-matchers.d.ts]" value="declare namespace jasmine {
							 | 
						||
| 
								 | 
							
								  interface Matchers {
							 | 
						||
| 
								 | 
							
								    toHaveText(actual: any, expectationFailOutput?: any): jasmine.CustomMatcher;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[testing/jasmine-matchers.ts]" value="/// <reference path="./jasmine-matchers.d.ts" />
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////  Jasmine Custom Matchers ////
							 | 
						||
| 
								 | 
							
								// Be sure to extend jasmine-matchers.d.ts when adding matchers
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function addMatchers(): void {
							 | 
						||
| 
								 | 
							
								  jasmine.addMatchers({
							 | 
						||
| 
								 | 
							
								    toHaveText: toHaveText
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function toHaveText(): jasmine.CustomMatcher {
							 | 
						||
| 
								 | 
							
								  return {
							 | 
						||
| 
								 | 
							
								    compare: function (actual: any, expectedText: string, expectationFailOutput?: any): jasmine.CustomMatcherResult {
							 | 
						||
| 
								 | 
							
								      const actualText = elementText(actual);
							 | 
						||
| 
								 | 
							
								      const pass = actualText.indexOf(expectedText) > -1;
							 | 
						||
| 
								 | 
							
								      const message = pass ? '' : composeMessage();
							 | 
						||
| 
								 | 
							
								      return { pass, message };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      function composeMessage () {
							 | 
						||
| 
								 | 
							
								        const a = (actualText.length < 100 ? actualText : actualText.substr(0, 100) + '...');
							 | 
						||
| 
								 | 
							
								        const efo = expectationFailOutput ? ` '${expectationFailOutput}'` : '';
							 | 
						||
| 
								 | 
							
								        return `Expected element to have text content '${expectedText}' instead of '${a}'${efo}`;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function elementText(n: any): string {
							 | 
						||
| 
								 | 
							
								  if (n instanceof Array) {
							 | 
						||
| 
								 | 
							
								    return n.map(elementText).join('');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (n.nodeType === Node.COMMENT_NODE) {
							 | 
						||
| 
								 | 
							
								    return '';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (n.nodeType === Node.ELEMENT_NODE && n.hasChildNodes()) {
							 | 
						||
| 
								 | 
							
								    return elementText(Array.prototype.slice.call(n.childNodes));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (n.nativeElement) { n = n.nativeElement; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return n.textContent;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[testing/router-stubs.ts]" value=" // 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()'
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class RouterLinkStubDirective {
							 | 
						||
| 
								 | 
							
								  @Input('routerLink') linkParams: any;
							 | 
						||
| 
								 | 
							
								  navigatedTo: any = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  onClick() {
							 | 
						||
| 
								 | 
							
								    this.navigatedTo = this.linkParams;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@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
							 | 
						||
| 
								 | 
							
								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 };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[index.html]" value="<!-- Run application specs in a browser -->
							 | 
						||
| 
								 | 
							
								<!DOCTYPE html>
							 | 
						||
| 
								 | 
							
								<html>
							 | 
						||
| 
								 | 
							
								<head>
							 | 
						||
| 
								 | 
							
								  <script>document.write('<base href="' + document.location + '" />');</script>
							 | 
						||
| 
								 | 
							
								  <title>Sample App Specs</title>
							 | 
						||
| 
								 | 
							
								  <meta charset="UTF-8">
							 | 
						||
| 
								 | 
							
								  <meta name="viewport" content="width=device-width, initial-scale=1">
							 | 
						||
| 
								 | 
							
								  <link rel="stylesheet" href="styles.css">
							 | 
						||
| 
								 | 
							
								  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								</head>
							 | 
						||
| 
								 | 
							
								<body>
							 | 
						||
| 
								 | 
							
								  <!-- Polyfills -->
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/core-js/client/shim.min.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.js"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.js"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js?main=browser"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js/dist/proxy.js?main=browser"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js/dist/sync-test.js?main=browser"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js/dist/jasmine-patch.js?main=browser"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js/dist/async-test.js?main=browser"></script>
							 | 
						||
| 
								 | 
							
								  <script src="https://unpkg.com/zone.js/dist/fake-async-test.js?main=browser"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <script>
							 | 
						||
| 
								 | 
							
								    var __spec_files__ = [
							 | 
						||
| 
								 | 
							
								      'app/about.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/app.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/app.component.router.spec',
							 | 
						||
| 
								 | 
							
								      'app/banner.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/banner.component.detect-changes.spec',
							 | 
						||
| 
								 | 
							
								      'app/banner-inline.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/dashboard/dashboard.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/dashboard/dashboard.component.no-testbed.spec',
							 | 
						||
| 
								 | 
							
								      'app/dashboard/dashboard-hero.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/hero/hero-list.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/hero/hero-detail.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/hero/hero-detail.component.no-testbed.spec',
							 | 
						||
| 
								 | 
							
								      'app/model/hero.spec',
							 | 
						||
| 
								 | 
							
								      'app/model/http-hero.service.spec',
							 | 
						||
| 
								 | 
							
								      'app/shared/title-case.pipe.spec',
							 | 
						||
| 
								 | 
							
								      'app/shared/twain.component.spec',
							 | 
						||
| 
								 | 
							
								      'app/welcome.component.spec'
							 | 
						||
| 
								 | 
							
								    ];
							 | 
						||
| 
								 | 
							
								  </script>
							 | 
						||
| 
								 | 
							
								  <script src="browser-test-shim.js"></script>
							 | 
						||
| 
								 | 
							
								</body>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								</html>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!-- 
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="tags[0]" value="angular"><input type="hidden" name="tags[1]" value="example"><input type="hidden" name="tags[2]" value="testing"><input type="hidden" name="private" value="true"><input type="hidden" name="description" value="Angular Example - Testing - app.specs"><input type="hidden" name="files[systemjs.config.js]" value="/**
							 | 
						||
| 
								 | 
							
								 * WEB ANGULAR VERSION
							 | 
						||
| 
								 | 
							
								 * (based on systemjs.config.js in angular.io)
							 | 
						||
| 
								 | 
							
								 * System configuration for Angular samples
							 | 
						||
| 
								 | 
							
								 * Adjust as necessary for your application needs.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								(function (global) {
							 | 
						||
| 
								 | 
							
								  System.config({
							 | 
						||
| 
								 | 
							
								    // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
							 | 
						||
| 
								 | 
							
								    transpiler: 'ts',
							 | 
						||
| 
								 | 
							
								    typescriptOptions: {
							 | 
						||
| 
								 | 
							
								      // Copy of compiler options in standard tsconfig.json
							 | 
						||
| 
								 | 
							
								      "target": "es5",
							 | 
						||
| 
								 | 
							
								      "module": "commonjs",
							 | 
						||
| 
								 | 
							
								      "moduleResolution": "node",
							 | 
						||
| 
								 | 
							
								      "sourceMap": true,
							 | 
						||
| 
								 | 
							
								      "emitDecoratorMetadata": true,
							 | 
						||
| 
								 | 
							
								      "experimentalDecorators": true,
							 | 
						||
| 
								 | 
							
								      "lib": ["es2015", "dom"],
							 | 
						||
| 
								 | 
							
								      "noImplicitAny": true,
							 | 
						||
| 
								 | 
							
								      "suppressImplicitAnyIndexErrors": true
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    meta: {
							 | 
						||
| 
								 | 
							
								      'typescript': {
							 | 
						||
| 
								 | 
							
								        "exports": "ts"
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    paths: {
							 | 
						||
| 
								 | 
							
								      // paths serve as alias
							 | 
						||
| 
								 | 
							
								      'npm:': 'https://unpkg.com/'
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    // map tells the System loader where to look for things
							 | 
						||
| 
								 | 
							
								    map: {
							 | 
						||
| 
								 | 
							
								      // our app is within the app folder
							 | 
						||
| 
								 | 
							
								      app: 'app',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // angular bundles
							 | 
						||
| 
								 | 
							
								      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
							 | 
						||
| 
								 | 
							
								      '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // other libraries
							 | 
						||
| 
								 | 
							
								      'rxjs':                      'npm:rxjs@5.0.1',
							 | 
						||
| 
								 | 
							
								      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
							 | 
						||
| 
								 | 
							
								      'ts':                        'npm:plugin-typescript@5.2.7/lib/plugin.js',
							 | 
						||
| 
								 | 
							
								      'typescript':                'npm:typescript@2.0.10/lib/typescript.js',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    // packages tells the System loader how to load when no filename and/or no extension
							 | 
						||
| 
								 | 
							
								    packages: {
							 | 
						||
| 
								 | 
							
								      app: {
							 | 
						||
| 
								 | 
							
								        main: './main.ts',
							 | 
						||
| 
								 | 
							
								        defaultExtension: 'ts'
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      rxjs: {
							 | 
						||
| 
								 | 
							
								        defaultExtension: 'js'
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								})(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Copyright 2016 Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								Use of this source code is governed by an MIT-style license that
							 | 
						||
| 
								 | 
							
								can be found in the LICENSE file at http://angular.io/license
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								"></form><script>document.getElementById("mainForm").submit();</script></body></html>
							 |