Spies and secret agents in javascript

Hello everybody,

Have you ever had a desire to become chief of secreat agent or spy? To be honest I never had such desire, but unwilignly I become chief of spies  and secret agents which I created in javascript. 

To put simply during unit testing of javascript sometime is needed to mock calling to some functions with replacement of that function, and sometime there is a need to mock that function without it's replacement. 

The first scenario is much easier to implement, while the second one required usage of apply function. 

Take a look at the following picture:

There are many js libraries which support both options ( with and without original function ). For example jasmine, sinonjs, etc. But I want to present code which display simple idea what is going behind the curtains.

<html>
 <head></head>
 <body>
   This content doesn't matter  
  <script>
		
		var ClassForSpy = function(){
		};
		
		ClassForSpy.prototype.Function1 = function(){
			console.log('Function1 executed');
			return true;
		};
		
		var InheritedClass = function(){};
		
		InheritedClass.prototype = new ClassForSpy();
		
		InheritedClass.prototype.Function2 = function(){
			console.log('Function1 inside inherited class');
			return 'Anything';
		};
		
		function CoolSpy(victim){
			for(var key in victim)
			{
				victim[key] = CreateCoolSpy(key);
			}
		}
		
		function CoolSecretAgent(victim){
			for(var key in victim)
			{
				victim[key] = CreateSecretAgent(key, victim, victim[key]);
			}
		}
		
		function CreateCoolSpy(key){
			return function(){
				console.log('CoolSpy for ' + key);
			}
		};
		
		function CreateSecretAgent(key, context, originalFunction){
			var sendToCenter = function()
			{
				console.log('I have send to command center secret info ' + key );
				return originalFunction.apply(context, arguments);
			};
			return sendToCenter;
		}
		
		console.log('Before spy section started')
		var inhClass = new InheritedClass();
		inhClass.Function1();
		inhClass.Function2();
		console.log('--------------------Before spy section completed-------------------');
		
		
		console.log('diletant spy or spy that substitutes original Function executed');
		CoolSpy(inhClass);
		
		inhClass.Function1();
		inhClass.Function2();
		console.log('substitutes spy section ended');
		
		console.log('Invisible spy section started');
		var inhClass2 = new InheritedClass();
		CoolSecretAgent(inhClass2);
		inhClass2.Function1();
		inhClass2.Function2();
		
		console.log('Invisible spy section ended');
		
	</script> 
 </body>
</html>

If you copy/paste the following code, and look in console, you'll find following output there:

Before spy section started

Function1 executed

Function1 inside inherited class

--------------------Before spy section completed-------------------

diletant spy or spy that substitutes original Function executed

CoolSpy for Function1

CoolSpy for Function2

substitutes spy section ended

Invisible spy section started

I have send to command center secret info Function1

Function1 executed

I have send to command center secret info Function2

Function1 inside inherited class

Invisible spy section ended

Here we have two functions which imitate spies behaviour. The first one is CoolSpy  and second one is CoolSecretAgent .

CoolSpy is interesting for cases if it is needed to substitute behaviour of some code, CoolSecretAgent can be used for monitoring of execution.

No Comments

Add a Comment