Julien METRAL
Julien METRAL

Reputation: 1974

Jasmine : Spying an exported function that is called by an another function doesn't work

I have create 2 helper functions with one of the too that is a shortcut to the first, in my test i want to verify that this function is called, these functions are in the same file :

export function test1(param1, param2, param3, param4) {
    return { param1, param2, ...(param3 && { param3 }), ...(param4 && { param4 }) };
}

export function test2(param1, param2) {
    return test1(param1, null, null, param2);
}

in the test i need to show that the first one is called by the second :

import * as Util from './my-util-file';
const test2 = Util.test2;
...
it('should call test1 when test2 is called', () => {
    const test1 = spyOn(Util, 'test1').and.callThrough();
    test2('test', 1);
    expect(test1).toHaveBeenCalledWith('test', null, null, 1);
});

Or

import {test1, test2} from './my-util-file';
...
it('should call test1 when test2 is called', () => {
    const test1Spy = jasmine.createSpy('test1');
    test2('test', 1);
    expect(test1Spy).toHaveBeenCalledWith('test', null, null, 1);
});

Or

import * as Util from './my-util-file';
const test2 = Util.test2;

...
it('should call test1 when test2 is called', () => {
    const test1Spy = spyOnProperty(Util, 'test1');
    test2('test', 1);
    expect(test1Spy).toHaveBeenCalledWith('test', null, null, 1);
});

Or

import {test1, test2} from './my-util-file';

...
it('should call test1 when test2 is called', () => {
    const test1Spy = spyOn(window as any, 'test1');
    test2('test', 1);
    expect(test1Spy).toHaveBeenCalledWith('test', null, null, 1);
});

but the problem is that i got the error:

Expected spy test1 to have been called.

Upvotes: 2

Views: 2092

Answers (1)

Siddharth Pal
Siddharth Pal

Reputation: 1458

This is not a problem with jasmine. This is how javascript modules behave when they are compiled/transpiled.

var test1 = function test1() {};
var test2 = function test2() { test1(); };

exports.test1 = test1;
exports.test2 = test2;

When the function test2 is declared, the reference to the test1 function is enclosed to the function declaration. But in spec what we are really importing is exports.test1 && exports.test2. So basically we are spying on something which is not intended i.e exports.test1.

So to hold the reference we can define & export the test functions as below:

const test1 = function(param1: any, param2: any, param3: any, param4: any) {
  return { 
    param1,
    param2,
    ...(param3 && { param3 }),
    ...(param4 && { param4 })
  };
};

const test2 = function(param1: any, param2: any) { 
  return testFunctions.test1(param1, null, null, param2); //Here we are attaching the refernce
};

export const testFunctions = {
  test1,
  test2
};

And we can test them as below:

import * as test from './test';

const functions = test.testFunctions;

it('should call test1 when test2 is called', () => {
    const test1 = spyOn(functions, 'test1').and.callThrough();
    functions.test2('test', 1);
    expect(test1).toHaveBeenCalledWith('test', null, null, 1);
});

A nice article which explains the above issue for your reference

Upvotes: 2

Related Questions