Using Jasmine to spy on a function without an object

JavascriptUnit TestingJasmine

Javascript Problem Overview


I'm new to Jasmine and have just started using it. I have a library js file with lots of functions which are not associated with any object (i.e. are global). How do I go about spying on these functions?

I tried using window/document as the object, but the spy did not work even though the function was called. I also tried wrapping it in a fake object as follows :

var fakeElement = {};
fakeElement.fakeMethod = myFunctionName;
spyOn(fakeElement, "fakeMethod");

and test with

expect(fakeElement.fakeMethod).toHaveBeenCalled();

This does not work either as the spy did not work

Javascript Solutions


Solution 1 - Javascript

If you are defining your function:

function test() {};

Then, this is equivalent to:

window.test = function() {}  /* (in the browser) */

So spyOn(window, 'test') should work.

If that is not, you should also be able to:

test = jasmine.createSpy();

If none of those are working, something else is going on with your setup.

I don't think your fakeElement technique works because of what is going on behind the scenes. The original globalMethod still points to the same code. What spying does is proxy it, but only in the context of an object. If you can get your test code to call through the fakeElement it would work, but then you'd be able to give up global fns.

Solution 2 - Javascript

TypeScript users:

I know the OP asked about javascript, but for any TypeScript users who come across this who want to spy on an imported function, here's what you can do.

In the test file, convert the import of the function from this:

import {foo} from '../foo_functions';

x = foo(y);

To this:

import * as FooFunctions from '../foo_functions';

x = FooFunctions.foo(y);

Then you can spy on FooFunctions.foo :)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();

Solution 3 - Javascript

There is 2 alternative which I use (for jasmine 2)

This one is not quite explicit because it seems that the function is actually a fake.

test = createSpy().and.callFake(test); 

The second more verbose, more explicit, and "cleaner":

test = createSpy('testSpy', test).and.callThrough();

-> jasmine source code to see the second argument

Solution 4 - Javascript

A very simple way:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');

Solution 5 - Javascript

import * as saveAsFunctions from 'file-saver';
..........
....... 
let saveAs;
            beforeEach(() => {
                saveAs = jasmine.createSpy('saveAs');
            })
            it('should generate the excel on sample request details page', () => {
                spyOn(saveAsFunctions, 'saveAs').and.callFake(saveAs);
                expect(saveAsFunctions.saveAs).toHaveBeenCalled();
            })

This worked for me.

Solution 6 - Javascript

The approach we usually follow, is as follows:

utils.ts file for all global utilities:

function globalUtil() {
  // some code
}

abc.component.ts:

function foo {
  // some code
  globalUtil();  // calls global function from util.ts
}

While writing a Jasmine test for function foo (), you can spy on the globalUtil function as follows:

abc.component.spec.ts:

import * as SharedUtilities from 'util.ts';

it('foo', () =>
{
  const globalUtilSpy = jasmine.createSpy('globalUtilSpy');
  spyOnProperty(SharedUtilities, "globalUtilSpy").and.returnValue(globalUtilSpy);
  
  foo();
  expect(globalUtilSpy).toHaveBeenCalled();
});

Solution 7 - Javascript

My answer differs slightly to @FlavorScape in that I had a single (default export) function in the imported module, I did the following:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');

Solution 8 - Javascript

I guess it's the easiest way:

const funcSpy = spyOn(myFunc, 'call');

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChetter HumminView Question on Stackoverflow
Solution 1 - JavascriptndpView Answer on Stackoverflow
Solution 2 - JavascriptAlexander TaylorView Answer on Stackoverflow
Solution 3 - JavascriptIxDayView Answer on Stackoverflow
Solution 4 - JavascriptFlavorScapeView Answer on Stackoverflow
Solution 5 - JavascriptSushilView Answer on Stackoverflow
Solution 6 - JavascriptAkshAy AgrawalView Answer on Stackoverflow
Solution 7 - JavascriptIonicBurgerView Answer on Stackoverflow
Solution 8 - JavascriptLudwigView Answer on Stackoverflow