jayscript jayscript - 1 year ago 229
TypeScript Question

Angular 2 TestBed, Mocking Methods without Dependency Injection

Using TestBed, we are able to create mock classes for classes that are available with dependency injection. For example,

has access to
since they are implemented with dependency injection, and so we can override them. The problem I have is that, to write a Jasmine test, I have to create mock classes to override methods of classes that are not accessed with dependency injection.

In this case,
will load
in the global space. This means, it might not be available when Jasmine reads what is inside the subscribe operator. For this reason, I would like to mock the former first and then the latter after. Or maybe there is a different way to get around this.

It would be great if someone can suggest a way to create mock classes to override the
method and

The directive to be tested:

selector: '[myButton]'
export class MyButtonClass implements AfterViewInit {

private myKey: string;

constructor(private _el: ElementRef, private myService: MyService) {}

ngAfterViewInit() {
.then((myKey: string) => {
this.myKey = myKey;
ScriptLoader.load('https://thirdpartyurl.js', this._el.nativeElement)
data => {
this.handeler = ThirdPartyCheckout.configure(<any>{
key: this.myKey
// etc
// and some methods go here
error => {

Here is the test code:

selector: 'test-cmp',
template: ''
class TestComponent {}

class mockMyService {
getKey() {
return Promise.resolve('this is a key in real code');

describe('myButton', () => {
beforeEach(() => {
declarations: [TestComponent, MyButtonClass],
providers: [
{provide: MyService, useClass: mockMyService}

describe('ngAfterViewInit', fakeAsync(() => {
const template = '<div><div myButton></div></div>';
TestBed.overrideComponent(TestComponent, {set: {template: template}});
let fixture = TestBed.createComponent(TestComponent);

Answer Source

Functions being first-class citizens, you can just assign a new function to it

let originalFn;

beforeEach(() => {
  originalFn = ScriptLoader.load;

afterEach(() => {
  ScriptLoader.load = originalFn;

it('...', fakeAsync(() => {
  ScriptLoader.load = (url, el: Element): Observable<string> => {
    return Observable.of('HelloSquirrel');

Other than this, you might want to just consider using DI. One of the main reasons for using DI is for better testability. For the ScriptLoader just make the method a non static method, and for the third party lib just create as abstraction service layer for it.