5

I'm having a rough time trying to test if some function is bound to a component after the component has been initialized.

This is my ngOnInit() function:

ngOnInit() {
   this.someFunction = this.someFunction.bind(this);
}

And this is the function that I want to bind to the component::

someFunction() {
   // this empty function is not called yet but should be bound to the component
}

And this is my before each:

beforeEach(async(() => {
   fixture = TestBed.createComponent(ComponentName);
   component = fixture.componentInstance;
   fixture.detectChanges();
}));

And this is my describe function:

describe('ngOnInit', () => {
  it('someFunction has been bound to the component.', () => {
    let bindFunctionSpy = spyOn(component.someFunction, 'bind').and.callThrough();

    component.ngOnInit();

    expect(bindFunctionSpy).toHaveBeenCalledWith(component);
  });
});

The problem that I'm facing here is that there is a typescript error in the spyOn function preventing me from compiling the test cases, it says :

error TS2345: Argument of type '"bind"' is not assignable to parameter of type 'never'.

So what exactly am I not doing right here?

The same thing happens if I try spying on any of the prototype functions for a component function like apply or call for example.

Yet if I tried to spy on a prototype function for a component variable like length or toLowerCase it doesn't throw such error!

Another note is that this test actually sometimes gets compiled successfully and actually passes, and sometimes it throws the error while compilingm, but it happens only when I make any random changes like adding a space then saving them so that Karma can detect that a change happened and recompile the tests, but if I closed the terminal and then started it again and ran ng test I get the error again.

4 Answers 4

2

The best way to do this is just casting your function to the CallableFunction type.

let bindFunctionSpy = spyOn(component.someFunction as CallableFunction, 'bind').and.callThrough();

Sign up to request clarification or add additional context in comments.

Comments

1

You could try

let bindFunctionSpy = spyOn(component.someFunction.prototype, 'bind').and.callThrough();

Comments

0

Another solution is to mock bind result with Jest or other test framework and test behaviour by expect method.

In this scenario i will bind function to a component variable:

{
// my component .ts file.
someFunctionCallback?: Function;

ngOnInit() {
   this.someFunctionCallback = this.someFunction.bind(this);
}
}

Test by mocking bind function result with jest framework:

// GIVEN
const someFunctionCallbackMock = jest.fn();
spyOn(comp.someFunction, 'bind').and.returnValue(someFunctionCallbackMock);
// if someFunction is private
// spyOn<any>(comp['someFunction'], 'bind).and.returnValue(someFunctionCallbackMock);

// WHEN
component.ngOnInit();

// THEN
expect(comp.someFunctionCallback).toEqual(someFunctionCallbackMock);
// you can test callback as argument
expect(comp.otherSpyiedFunction).toHaveBeenCalledWith(someFunctionCallbackMock)

Comments

-1

Try spying on Function.prototype like this -

spyOn(Function.prototype, 'bind');

it worked for me.

1 Comment

If you are using Angular Testbed spying on Function.protype.bind will lead you to RangeError: Maximum call stack size exceeded as bind is called a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.