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();
});