<!DOCTYPE html>
<html>

  <head>
    <title>Angular2 seed wtih Jasmine</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="style.css">
    <link data-require="bootstrap-css@*" data-semver="3.3.6" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />


    <script src="https://npmcdn.com/core-js/client/shim.min.js"></script>

    <script src="https://npmcdn.com/zone.js@0.8.5?main=browser"></script>
    <script src="https://npmcdn.com/reflect-metadata@0.1.3"></script>
    <script src="https://npmcdn.com/systemjs@0.19.27/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>  
  </head>

  <body>
    <app-root>Loading...</app-root>
  
    <hr>
    <a href="jasmine-test-runner.html">Run Unit Tests</a>
  
  </body>

</html>
/* Styles go here */

Angular + ngOnChanges (see https://medium.com/@christophkrautz/testing-ngonchanges-in-angular-components-bbb3b4650ee8)
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
  `,
})
export class AppComponent {
  name:string;
  constructor() {
    this.name = 'Angular'
  }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
// 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 = 1000;

var baseURL = document.baseURI;
baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/';

System.config({
  baseURL: baseURL,
  // Extend usual application package list with test folder
  packages: { 'test': { main: 'index.js', defaultExtension: 'js' } },
  packageWithIndex: true // sadly, we can't use umd packages (yet?)
});

System.import( baseURL +'systemjs.config.js')
  .then(function () {
    return Promise.all([
      System.import('@angular/core/testing'),
      System.import('@angular/platform-browser-dynamic/testing')
    ])
  })

  .then(function (providers) {
    var testing = providers[0];
    var testingBrowser = providers[1];

    testing.TestBed.initTestEnvironment(
      testingBrowser.BrowserDynamicTestingModule,
      testingBrowser.platformBrowserDynamicTesting());
  })

  // Import the spec files defined in the html (__spec_files__)
  .then(function () {
    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
*/
<!-- Run the "bag" specs in a browser -->
<!DOCTYPE html>
<html>
<head>
  <script>document.write('<base href="' + document.location + '" />');</script>
  <title>Jasmine test runner</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="style.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css">

</head>
<body>
  <script src="https://npmcdn.com/systemjs@0.19.27/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://npmcdn.com/reflect-metadata@0.1.3"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25?main=browser"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25/dist/long-stack-trace-zone.js?main=browser"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25/dist/async-test.js?main=browser"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25/dist/fake-async-test.js?main=browser"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25/dist/sync-test.js?main=browser"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25/dist/proxy.js?main=browser"></script>
  <script src="https://npmcdn.com/zone.js@0.6.25/dist/jasmine-patch.js?main=browser"></script>

  <script>
    var __spec_files__ = [
      "app/greeter.component.spec",
      "app/greeter.host.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
-->
/**
 * PLUNKER VERSION
 * (based on systemjs.config.js in angular.io)
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function(global) {

  var ngVer = '@5.2.5'; // lock in the angular package version; do not let it float to current!

  //map tells the System loader where to look for things
  var map = {
    'app':                                         'app',

    '@angular':                                    'https://npmcdn.com/@angular', // sufficient if we didn't pin the version
    '@angular/common':                             'https://npmcdn.com/@angular/common@5.2.5/bundles/common.umd.js',
    '@angular/core':                               'https://npmcdn.com/@angular/core@5.2.5/bundles/core.umd.js',
    '@angular/core/testing':                       'https://npmcdn.com/@angular/core@5.2.5/bundles/core-testing.umd.js',
    '@angular/platform-browser-dynamic':           'https://npmcdn.com/@angular/platform-browser-dynamic@5.2.5/bundles/platform-browser-dynamic.umd.js',
    '@angular/platform-browser-dynamic/testing':   'https://npmcdn.com/@angular/platform-browser-dynamic@5.2.5/bundles/platform-browser-dynamic-testing.umd.js',
    '@angular/platform-browser':                   'https://npmcdn.com/@angular/platform-browser@5.2.5/bundles/platform-browser.umd.js',
    '@angular/platform-browser/testing':           'https://npmcdn.com/@angular/platform-browser@5.2.5/bundles/platform-browser-testing.umd.js',
    '@angular/compiler':                           'https://npmcdn.com/@angular/compiler@5.2.5/bundles/compiler.umd.js',
    '@angular/compiler/testing':                   'https://npmcdn.com/@angular/compiler@5.2.5/bundles/compiler-testing.umd.js',
    'rxjs':                                        'https://npmcdn.com/rxjs@5.3.0',
    'ts':                                          'https://npmcdn.com/plugin-typescript@7.0.6/lib/plugin.js',
    'typescript':                                  'https://npmcdn.com/typescript@2.2.2/lib/typescript.js',
 };

  //packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    'app':                        { main: 'main.ts',  defaultExtension: 'ts' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
  };

  var ngPackageNames = [
    //'common',
    //'compiler',
    //'core',
    'http',
    //'platform-browser',
   // 'platform-browser-dynamic',
    'upgrade',
  ];

  // Add map entries for each angular package
  // only because we're pinning the version with `ngVer`.
  ngPackageNames.forEach(function(pkgName) {
    map['@angular/'+pkgName] = 'https://npmcdn.com/@angular/' + pkgName + ngVer;
  });

  // Add package entries for angular packages with special versions
  ngPackageNames = ngPackageNames.concat(['forms', 'router', 'router-deprecated']);

  // Individual files (~300 requests):
  function packIndex(pkgName) {
    packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
  }

  // Bundled (~40 requests):
  function packUmd(pkgName) {
    packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
  }

  // Most environments should use UMD; some (e.g. Karma) need the individual index files
  var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;

  // Add package entries for angular packages
  ngPackageNames.forEach(setPackageConfig);

  var config = {
    // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
    transpiler: 'ts',
    typescriptOptions: {
      tsconfig: true
    },
    meta: {
      'typescript': {
        "exports": "ts"
      }
    },
    map: map,
    packages: packages
  };

  System.config(config);

})(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
*/
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}
import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {Component, SimpleChange} from '@angular/core';

import {Greeter} from './greeter.component';

describe('Component: Greeter w/ host', () => {
  let fixture, testHost, element, de;
  
  //setup
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ Greeter, TestHostComponent ]
    });

    fixture = TestBed.createComponent(TestHostComponent);
    testHost = fixture.componentInstance;
    element = fixture.nativeElement;
    de = fixture.debugElement;
  });
  
  //specs
  it('should render `Hello World!`', () => {
    testHost.name = 'World';
    
    //trigger change detection
    fixture.detectChanges();

    expect(element.querySelector('h1').innerText).toBe('Hello World!');
  });
})

@Component({
  template: '<greeter [name]="name"></greeter>'
})
class TestHostComponent {
  name: string
}
import {Component, Input, OnChanges} from '@angular/core';

@Component({
  selector: 'greeter',
  inputs: ['name'],
  template: `<h1>{{ greeting }}</h1>`,
})
export class Greeter implements OnChanges {
  @Input() name: string;
  greeting: string;
  
  constructor() {}

  ngOnChanges(changes: SimpleChanges) {
    
    if (changes['name']) {
      this.greeting = 'Hello ' + this.name + '!';
    }
  }
}
import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {SimpleChange} from '@angular/core';

import {Greeter} from './greeter.component';

describe('Component: Greeter', () => {
  let fixture, greeter, element, de;
  
  //setup
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ Greeter ]
    });

    fixture = TestBed.createComponent(Greeter);
    greeter = fixture.componentInstance;
    element = fixture.nativeElement;
    de = fixture.debugElement;
  });
  
  //specs
  it('should render `Hello World!`', () => {
    greeter.name = 'World';
    
    //directly call ngOnChanges
    greeter.ngOnChanges({
      name: new SimpleChange(null, greeter.name)
    });

    fixture.detectChanges();

    expect(element.querySelector('h1').innerText).toBe('Hello World!');
  });
})