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)