0

First I've searched for "No provider for Http", as the error was showing, but I've realised that I've imported http within videoplayer.component, but I diddn't used it. But I've learned much about mocking services and especially the post on an observable abstract mock up is very helpfull. After removing the http from the videoplayer.component, I've got the next error: VideoService is not defined. I've forgotten the import in the testing module! After resolving this in the test component, I've received "No provider for HTTP" again.

So first my testing code (videoplayer.component.spec.ts) with the mock up from the post above

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By }              from '@angular/platform-browser';
import { DebugElement }    from '@angular/core';
import { async } from '@angular/core/testing';

import { AbstractMockObservableService } 
    from '../shared/test/abstract.mock.observable.service';
import { VideoPlayer } from './videoplayer.component';
import { VideoService } from './video.service';

describe('VideoPlayer (inline template)', () => {

    class MockService extends AbstractMockObservableService {
      getLoading(cb) {
      return true;// stubbing?
  }

  pushLoadState() {
      return false;// stubbing?
  }

  getOptions(requestDisplayId) : Observable<VideoDetail> {
      return false;// return Observable???
  }

  reservePlayer(displayID,domID) { // TODO register ids?
      return false;
  }

    }

  let mockService;
  let comp:    VideoPlayer;
  let fixture: ComponentFixture<VideoPlayer>;
  let de:      DebugElement;
  let el:      HTMLElement;

  // async beforeEach
  beforeEach(async(() => {
     mockService = new MockService();
    TestBed.configureTestingModule({
      declarations: [ VideoPlayer ], // declare the test component
      providers:    [ {provide: VideoService, useValue: mockService } ],

  })
  .compileComponents();  // compile template and css
  }));

  // synchronous befareEach...
  beforeEach(() => {
    fixture = TestBed.createComponent(VideoPlayer);

    comp = fixture.componentInstance; // VideoPlayer test instance

    // query for the title <h1> by CSS element selector
    de = fixture.debugElement.query(By.css('.videocontainer'));
    el = de.nativeElement;
    console.log(de);
    console.log(el);
  });
  it('SOME CONTENT', () => {

});

});

Now the videoplayer.component.ts, please excuse the direct dom manipulations for the Youtube iFrame-API, I'm still searching for an Angular2 compatible way.

import {Component,Input,Output,Inject,ElementRef} from '@angular/core';
import {NgIf} from '@angular/common';

import {VideoService} from './video.service';

@Component({
    selector: 'my-video-player',
    providers: [VideoService],
    template: require('./videoplayer.html'),
})
export class VideoPlayer implements OnChanges {
    @Input() displayid : String;
    @Input() displayflag : Number;
    // -1 button to load player,0 no display,1 load but dont start, 
    // 2 autostart after load
    @Output() onStateChange = new EventEmitter<any>();

    private options : Object;
    private loadingFlag : boolean;
    private errorFlag : boolean;
    private myPlayer : Object;

    ngOnChanges(changes: SimpleChanges) {
        var refreshed = false;
        if (changes.includes('displayid'))
        {
            let did = changes['displayid'];
            if (did.previousValue !== did.currentValue) {
                refreshPlayer();
                refreshed = true;
            }
        }
        if (!refreshed && changes.includes('displayid'))
        {
            let did = changes['displayflag'];
            if (did.previousValue !== did.currentValue) {
                refreshPlayer();
                refreshed = true;
            }
        }
        /*for (let propName in changes) {
            let chng = changes[propName];
            let cur  = JSON.stringify(chng.currentValue);
            let prev = JSON.stringify(chng.previousValue);
        }*/
    }
  constructor(@Inject(ElementRef) elr: ElementRef,
              @Inject(VideoService) videoService: VideoService) {
      this.loadingFlag = true;
  }

  ngOnInit() {
    refreshPlayer();
  }

  loadPlayer() {
    this.displayflag = 2;
    this.refreshPlayer();
  }

  refreshPlayer() {
      // loadingFlag with Callback
      this.loadingFlag = videoService.getLoading(this.refreshPlayer);
      if (this.loadingFlag) return;
      if (this.myPlayer !== null) {
          this.myPlayer.destroy();
          this.myPlayer = null;
      }
      this.errorFlag = false;
      if (this.displayid !== null && this.displayflag > 0) {
          console.log('refreshPlayer: ' + this.displayid);
          videoService.getOptions(this.displayid)
            .subscribe(
                this.getOptionsOnNext,
                this.getOptionsOnError,
                this.getOptionsOnCompleted
                );
      }
  }
  private getOptionsOnNext(data) {
      this.displayid = data.displayid; //?
      var myId = 'vp'+this.displayid;
      // check if element exists
      if (document.getElementById(myId)===null)
      {
          var newNode = document.createElement("div");
          newNode.id = myId;
          elr.nativeElement.insertBefore(newNode);
      }
      this.options = data.options;
      this.options.events = {
        'onReady': onPlayerReady,
        'onStateChange': onPlayerStateChange,
        'onError': onPlayerError,
      };
      this.myPlayer = new YT.Player(myId, options);
      videoService.reservePlayer(this.displayid,myId);
  }
  private getOptionsOnError(err) {
      // console.log(err);
      this.errorFlag = true;
  }
  private getOptionsOnCompleted() {
      console.log('getOptionsOnCompleted: ' + this.displayid);
  }

  private onPlayerReady(event) {
        if (this.displayflag == 2)
            event.target.playVideo();
      }
  private onPlayerStateChange(event) {
        onStateChange.emit(event.data);
      }
  private onPlayerError(event) {
        console.log(event);
        errorFlag = true;
      }
}

And here is the stack trace, telling me nothing.

    Error: No provider for Http!
    Error: DI Error
        at NoProviderError.ZoneAwareError (webpack:///~/zone.js/dist/zone.js:811:0 <- src/polyfills.ts:3833:33)
        at NoProviderError.BaseError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:22:0 <- src/test.ts:22301:16)
        at NoProviderError.AbstractProviderError [as constructor] (webpack:///~/@angular/core/src/di/reflective_errors.js:54:0 <- src/test.ts:45305:16)
        at new NoProviderError (webpack:///~/@angular/core/src/di/reflective_errors.js:116:0 <- src/test.ts:45367:16)
        at ReflectiveInjector_._throwOrNull (webpack:///~/@angular/core/src/di/reflective_injector.js:485:0 <- src/test.ts:63446:19)
        at ReflectiveInjector_._getByKeyDefault (webpack:///~/@angular/core/src/di/reflective_injector.js:524:0 <- src/test.ts:63485:25)
        at ReflectiveInjector_._getByKey (webpack:///~/@angular/core/src/di/reflective_injector.js:456:0 <- src/test.ts:63417:25)
        at ReflectiveInjector_.get (webpack:///~/@angular/core/src/di/reflective_injector.js:325:0 <- src/test.ts:63286:21)
        at TestBed.get (webpack:///~/@angular/core/bundles/core-testing.umd.js:827:0 <- src/test.ts:8978:67)
        at CompiledTemplate.proxyViewClass.AppView.injectorGet (webpack:///~/@angular/core/src/linker/view.js:152:0 <- src/test.ts:64221:45)
        at CompiledTemplate.proxyViewClass.DebugAppView.injectorGet (webpack:///~/@angular/core/src/linker/view.js:580:0 <- src/test.ts:64649:49)
        at CompiledTemplate.proxyViewClass.View_VideoPlayer_Host0.createInternal (/DynamicTestModule/VideoPlayer/host.ngfactory.js:19:55)
        at CompiledTemplate.proxyViewClass.AppView.createHostView (webpack:///~/@angular/core/src/linker/view.js:108:0 <- src/test.ts:64177:21)
        at CompiledTemplate.proxyViewClass.DebugAppView.createHostView (webpack:///~/@angular/core/src/linker/view.js:564:0 <- src/test.ts:64633:52)
        at ComponentFactory.create (webpack:///~/@angular/core/src/linker/component_factory.js:202:0 <- src/test.ts:33107:25)
Community
  • 1
  • 1
Myonara
  • 1,197
  • 1
  • 14
  • 33
  • if you want to use real http then you should provide it. – Roman C Feb 14 '17 at 18:56
  • Well, I don't know, where to provide it. I've learned from the other posts, that I cannot mock http, I should either mock the services, which are using the http (what I tried above) or I have to simulate the http backend. – Myonara Feb 15 '17 at 05:28
  • Where it comes from Http, I don't see in the code that you have used it. – Roman C Feb 15 '17 at 09:38
  • OK, the only place in this construct, where Http is used, is the video.service.ts itself. But with the line ` providers: [ {provide: VideoService, useValue: mockService } ],` I've assumed, that the VideoService is replaced by the mockService, Somehow the unused VideoService seems to be loaded... – Myonara Feb 15 '17 at 16:26
  • Workaround: I've copied the video service to a different folder and now the test is passing with no error. I think it's a bug, not a feature. the video service should be ignored as stated above. – Myonara Feb 15 '17 at 17:41
  • I've continued with the testing and I realized, that the testing code is using the VideoService for testing not the mock service. – Myonara Feb 15 '17 at 18:49

0 Answers0