Welcome to Community Week 2025! Join us to learn, connect, and be recognized as we celebrate the spirit of Community and the power of AI. Get the details  

Unable to spyOn GlideSystem for test

Pitaro
Kilo Contributor

I am trying to write a Jasmine test to make sure that gs.addInfoMessage is called.

    it('Gives a message if user already added to group.', function() {
         spyOn(gs, 'addInfoMessage');
       
        wf = new CustWorkflow();
        wf.addGroup(user, group);
        expect(gs.addInfoMessage).toHaveBeenCalled();
     });

This gives the error 'Expected a spy, but got Function.' What am I doing wrong?

1 ACCEPTED SOLUTION

arthurcheung
Kilo Expert

 

I think because gs is this weird hybrid Java/JavaScript object it doesn't play nicely spying directly on it (I think... don't quote me on this). You can replace the whole thing with a mock, but keep in mind you are replacing something that is probably required to write the results as well.

  • "spyOn" spies on an existing real object.
  • "createSpy" and "createSpyObject" creates completely mocked up function / object - which replaces the real one.

The snippet below works for me. I'm guessing you're probably doing this to further understand how things work, but I wouldn't recommend doing this for any real scenario. Any addInfoMessage run through ATF appears to be logged in the test logs anyway.

IMPORTANT: Notice that I replaced the original gs with the stub!

it('Calls gs.addInfoMessage.', function() {	
  var realGs = gs;
  gs = jasmine.createSpyObj('gs', [ 'addInfoMessage']);
  gs.addInfoMessage.andCallFake(function() {
    realGs.log('gs.addInfoMessage called!');		
  });
  var test = new Test();			
  test.testMethod();
  expect(gs.addInfoMessage).toHaveBeenCalled();
});

View solution in original post

4 REPLIES 4

Ankush Agrawal
ServiceNow Employee
ServiceNow Employee

Hi Pitaro

gs is not the actual class but an object. The spy has to be put on the real definition of the function: https://stackoverflow.com/questions/12053799/expected-a-spy-but-got-function

--

Best regards
Ankush

P.S. Please mark helpful/correct as appropriate to help fellow Community user in identifying useful answers.

Ankush,

Thanks for the reply. I followed the example on the link and tried referencing the prototype, but got a different error. I put a more complete code sample in a reply to my original post.

Pitaro
Kilo Contributor

Here is a more complete code sample. The first is a server-side script include called "Test":

var Test = Class.create();
Test.prototype = {
    initialize: function() {
    },
	
	testMethod : function() {
		gs.addInfoMessage("Test was called");
	},
	
	testGlideRecord : function() {
		var gr = new GlideRecord('sys_user');
		gr.get();
	},

    type: 'Test'
};

The second is the test, with a couple ways of calling:

(function(outputs, steps, stepResult, assertEqual) {
	
describe('TestTest', function() {
	it('Gives a message, spied on with gs.', function() {
			spyOn(gs, 'addInfoMessage');
			test = new Test();
			test.testMethod();
			expect(gs.addInfoMessage).toHaveBeenCalled();
	});
	
	it('Gives a message, spied on with prototype.', function() {
			spyOn(GlideSystem.prototype, 'addInfoMessage');
			test = new Test();
			test.testMethod();
			expect(GlideSystem.prototype.addInfoMessage).toHaveBeenCalled();
	});

	it('Works when GlideRecord is spied on with prototype.', function() {
			spyOn(GlideRecord.prototype, 'get');
			test = new Test();
			test.testGlideRecord();
			expect(GlideRecord.prototype.get).toHaveBeenCalled();
	});

});	

})(outputs, steps, stepResult, assertEqual);
jasmine.getEnv().execute();

 

This is the output:

 

---- Tests Complete -----
Spec :: TestTest Gives a message, spied on with gs. :: failed
	Error: Expected a spy, but got Function.
Spec :: TestTest Gives a message, spied on with prototype. :: failed
	addInfoMessage() method does not exist
Spec :: TestTest Works when GlideRecord is spied on with prototype. :: passed
Test results :: (1/3) :: failed

arthurcheung
Kilo Expert

 

I think because gs is this weird hybrid Java/JavaScript object it doesn't play nicely spying directly on it (I think... don't quote me on this). You can replace the whole thing with a mock, but keep in mind you are replacing something that is probably required to write the results as well.

  • "spyOn" spies on an existing real object.
  • "createSpy" and "createSpyObject" creates completely mocked up function / object - which replaces the real one.

The snippet below works for me. I'm guessing you're probably doing this to further understand how things work, but I wouldn't recommend doing this for any real scenario. Any addInfoMessage run through ATF appears to be logged in the test logs anyway.

IMPORTANT: Notice that I replaced the original gs with the stub!

it('Calls gs.addInfoMessage.', function() {	
  var realGs = gs;
  gs = jasmine.createSpyObj('gs', [ 'addInfoMessage']);
  gs.addInfoMessage.andCallFake(function() {
    realGs.log('gs.addInfoMessage called!');		
  });
  var test = new Test();			
  test.testMethod();
  expect(gs.addInfoMessage).toHaveBeenCalled();
});