<!DOCTYPE html>
<html>

  <head>
    <title>Angular2 Testing Playground - Jasmine</title>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css">
  
    <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://code.angularjs.org/tools/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>    
    <script src="config.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/angular2.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/http.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/testing.dev.js"></script>
  </head>

  <body>
    <script>
      Promise.all([
        System.import('app/testsetup'),
        System.import('app/app.spec'),
        System.import('app/myservice.spec'),
      ])
      .then(window.onload)
      .catch(console.error.bind(console));
    </script>
  </body>

</html>
/* Styles go here */

THIS IS A FAILING CONDITION IN TESTING

However, it looks like it passes.

But look at myservice.spec.ts and see the reason is MockBackend is being provided 
to the injector.

Issue on Angular2 https://github.com/angular/angular/issues/6375
System.config({
  //use typescript for compilation
  transpiler: 'typescript',
  //typescript compiler options
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  //map tells the System loader where to look for things
  map: {
    app: "./src"
  },
  //packages defines our app package
  packages: {
    app: {
      defaultExtension: 'ts'
    }
  }
});
//main entry point
import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
import {HTTP_PROVDIERS} from 'angular2/http';
import {MyService} from './myservice';

bootstrap(App, [HTTP_PROVIDERS])
  .catch(err => console.error(err));
//our root app component
import {Component} from 'angular2/core';
import {MyService} from './myservice';

@Component({
  selector: 'my-app',
  //providers: [MyService],
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <button (click)="finish()">Finish</button>
    </div>
  `,
  directives: []
})
export class App {
  constructor(public service: MyService) {
    this.name = 'Angular2'
  }
  
  finish() {
    this.service.getSomeData();
    this.name = 'Joe';
  }
}
import {
  describe,
  expect,
  it,
  injectAsync,
  TestComponentBuilder,
  beforeEachProviders
} from 'angular2/testing';

import {Component, provide} from 'angular2/core';
import {HTTP_PROVIDERS} from 'angular2/http';
import {App} from './app';
import {MyService} from './myservice';

@Component({
  template: '',
  directives: [App]
})
class TestComponent {
}

class MyServiceMock {
  doSomething() {
  }
  
  getSomeData() {
  }
};

describe('App Component', () => {
  beforeEachProviders(() => [
    provide(MyService, {useClass: MyServiceMock})
  ]);
  
  it('should be defined', () => {
    expect(App).toBeDefined();
  });
  
  it('should say Hello Angular2', injectAsync([TestComponentBuilder], (tcb) => {
    return tcb.overrideTemplate(TestComponent, '<my-app></my-app>')
        .createAsync(TestComponent).then((fixture) => {
          fixture.detectChanges();
          var compiled = fixture.debugElement.nativeElement;

          expect(compiled).toContainText('Hello Angular2');
        });
  });
  
  it('should finish when you click the button', injectAsync([TestComponentBuilder], (tcb) => {
    return tcb.overrideTemplate(TestComponent, '<my-app></my-app>')
        .createAsync(TestComponent).then((fixture) => {
          fixture.detectChanges();
          
          let element = fixture.debugElement;
          let compiled = element.nativeElement;
          let button = compiled.querySelector('button');
          
          button.click();
          fixture.detectChanges();
          
          expect(compiled).toContainText('Hello Joe');
        });
  });
});
import 'angular2/testing';
import 'rxjs/Rx';
import {BrowserDomAdapter} from 'angular2/platform/browser';
BrowserDomAdapter.makeCurrent();

beforeEach(() => {
    jasmine.addMatchers({
        toContainText: function() {
            return {
                compare: function(actual, expectedText) {
                    var actualText = actual.textContent;
                    return {
                        pass: actualText.indexOf(expectedText) > -1,
                        get message() { return 'Expected ' + actualText + ' to contain ' + expectedText; }
                    };
                }
            };
        }
    });
});
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';

@Injectable()
export class MyService {
  constructor(public http: Http) {
    
  }
  doSomething() {
    return 'done';
  }
  
  getSomeData() {
    return this.http.get('./users.json')
      .map((res) => res.json());
  }
}
import {
  describe,
  expect,
  it,
  inject,
  beforeEachProviders
} from 'angular2/testing';
import {provide, Injector} from 'angular2/core';
import {MyService} from './myservice';
import {Http, HTTP_PROVIDERS, XHRBackend, Response, ResponseOptions} from 'angular2/http';
import {MockBackend} from 'angular2/http/testing';

describe('MyService', () => {
  let injector,
      backend,
      mockBackend,
      httpService,
      service;
      
  beforeEach(() => {
    injector = Injector.resolveAndCreate([
      HTTP_PROVIDERS,
      // this next value should NOT be provided, but when it is,
      // we lose the ability to correlate the backend calls
      // to the test Is there a way to detect this has been
      // done and reject it out-of-hand? 
      MockBackend,  // this is clearly wrong...
      provide(XHRBackend, {useClass: MockBackend}),
      MyService
    ]);
    
    mockBackend = injector.get(MockBackend);
    backend = injector.get(XHRBackend);
    httpService = injector.get(Http);
    service = injector.get(MyService);
  ]);
  
  it('should be defined', () => {
    expect(service).toBeDefined();
  });
  
  // if not, somehow I'd like the test to fail with an error
  // stating that another backend is in use - could we somehow
  // ask the test injector NOT to provide two Mock backends? 
  // or log a warning when it does?
  
  // bottom line: beginners can get very confused if they 
  // accidentally provide the MockBackend class as a simple
  // class definition in addition to using the provide function
  // to replace XHRBackend with MockBackend
  it('should be the same instance of the mockBackend or provide warning/error...', () => {
    expect(httpService._backend).toBe(mockBackend);
  })
  
  it('should do something', () => {
    expect(service.doSomething()).toBe('done');
  });
  
  it('should get some data', () => {
    backend.connections.subscribe(connection => {
      connection.mockRespond(new Response(new ResponseOptions({body: { username: 'test2', password: 'test2'}})));
    });
    
    service.getSomeData().subscribe((data) => {
      expect(data.username).toBe('test2');
      expect(data.password).toBe('test2');
    });
  });
});
{
  username: "test",
  password: "test"
}