Tags

, ,

Language: Typescript (Angular Component Test)

Method to be tested:

methodToBeTested(ev) {
  ev.call();
}

Test:

it('test', () => {
   const ev = {call: () => {}};

   // Run Test
   component.methodToBeTested(ev);

   // Controls
   expect(ev.call).toHaveBeenCalled();
});

Error:  <call> : Expected a spy, but got Function.

Solution:

it('test', () => {
   const ev = {call: () => {}};

   spyOn(ev, 'call');

   // Run Test
   component.methodToBeTested(ev);

   // Controls
   expect(ev.call).toHaveBeenCalled();
});

This was easy, since the parameter ev does not have a type.

Method 2:

methodToBeTested(ev: TypeWithMultipleAttributes) {
  ev.call();
}

Test:

it('test', () => {
   const ev = {call: () => {}};
   spyOn(ev, 'call');

   // Run Test
   component.methodToBeTested(ev);

   // Controls
   expect(ev.call).toHaveBeenCalled();
});

Error:  Argument of type {call: () => {}} is not assignable to parameter of type TypeWithMultipleAttributes. Property XXX is missing in type {call: () => {}}.

Reason: we did not create a constant with the correct type. So the content of our test data is very different than the one which we should prepare.

Solution 1:  is to create our test data with the original type:

it('test', () => {
   const ev : TypeWithMultipleAttributes = {X: 1, Y: 'goh', call: () => {}, ...};
   spyOn(ev, 'call');

   // Run Test
   component.methodToBeTested(ev);

   // Controls
   expect(ev.call).toHaveBeenCalled();
});

Solution 2: What if the type has many attributes which we do not want to deal with.. In the end, we will just check if a method is called:

it('test', () => {
   const ev = {call: () => {}};
   spyOn(ev, 'call');

   // Run Test
   component.methodToBeTested(ev as TypeWithMultipleAttributes);

   // Controls
   expect(ev.call).toHaveBeenCalled();
});

as keyword takes our test object (which may have a different content), and passes it through the Typescript’s type validation. This seems like a hack, but cleverly eliminates the need for creating a specified type. Typically the test object should at least contain the attributes, the method in test needs. (In our project, we had a very complex type with more than 10 attributes, but in a specific location we wanted to test just a method call as shown above.)