What is equivalent of spyOn.and.callFake in Sinon? - javascript

How do I write a spy that callsFake in Sinon, similar to Jasmine?
Jasmine:
spyOn(window, "requestAnimationFrame").and.callFake(() => {});
Sinon:
// pseudo code
const requestAnimationFrameSpy = spy().and.callFake(() => {});
global.window.requestAnimationFrame = requestAnimationFrameSpy;

You can do this a couple different ways, either with sinon fakes similar to:
const requestAnimationFrameSpy = sinon.fake().returns({value:'some value'});
global.window.requestAnimationFrame = requestAnimationFrameSpy();
You can also do this with sinon stubs:
//from sinon website
var myObj = {};
myObj.prop = function propFn() {
return 'foo';
};
sinon.stub(myObj, 'prop').callsFake(function fakeFn() {
return 'bar';
});
myObj.prop(); // 'bar'

Related

Inherited prototype function is not a function

I'm trying to wrap my head around prototypal inheritance and I haven't been able to work out why my code is failing. I'm stuggling to call a function on an object where that function is inherited from the Objects prototype. My code is below...
const OBJ_PROTO = {
myFunction(param = 'a') {
if (['a', 'b'].includes(param)) {
this.someVar = param;
};
return this.someVar;
}
}
const obj = ({
someVar = 'a'
} = {}) => Object.assign(Object.create(OBJ_PROTO), { someVar })
export default obj;
Then in my test I'm doing...
import obj from './someFile'
test('testing my function', () => {
const myObj = obj();
expect(myObj.myFunction()).toBe('a')
});
The test seems to fail and error's saying myFunction is not a function. Running Object.getPrototypeOf(myObj) correctly lists the function which leads me to believe i'm making a stupid mistake somewhere. To which im happy to be roasted on SO for. I get that testing simple code like this with Jest is very overkill but it was just another thing i wanted to familiarise myself with. Any help is greatly appreciated! If any more info is required, ask!
const OBJ_PROTO = {
myFunction(param = 'a') {
if (['a', 'b'].includes(param)) {
this.someVar = param;
};
return this.someVar;
}
}
const obj = ({
someVar = 'a'
} = {}) => Object.assign(Object.create(OBJ_PROTO), { someVar })
const myObj = obj();
console.log(myObj.myFunction())

How do I test call and apply functions in jest?

Here's my callnapply.js file
const callAndApply = {
caller(object, method, nameArg, ageArg, tShirtSizeArg) {
method.call(object, nameArg, ageArg, tShirtSizeArg);
},
applier(object, method, argumentsArr) {
method.apply(object, argumentsArr);
},
};
module.exports = callAndApply;
And here's a snippet from the test file which contains the non-working test:
const callnapply = require('./callnapply');
test('testing Function.prototype.call as mock function', () => {
const outer = jest.fn();
const name = 'Aakash';
const age = 22;
const tee = 'M';
callnapply.caller(this, outer, name, age, tee);
expect(outer.call).toHaveBeenCalledWith(name, age, tee);
});
How do I write the test to check if the method that I am passing is, in fact, being called by the Function.prototype.call function only? I want to check whether .call() is being called and not some other implementation that has been written for the method call.
You can mock the .call() method itself:
const outer = function() {}
outer.call = jest.fn()
Then you can do usual jest mock tests on outer.call.
Here is the working test file:
const callnapply = require('./callnapply');
test('testing Function.prototype.call as mock function', () => {
const outer = function() {};
outer.call = jest.fn();
const name = 'Aakash';
const age = 22;
const tee = 'M';
callnapply.caller(this, outer, name, age, tee);
expect(outer.call).toHaveBeenCalledWith(this, name, age, tee);
});
See this working REPL.

Intercept EventEmitters with Jasmine

I'm building a node.js module and I wish also to test it with Jasmine.
Let say my module look similar to this:
var myModule = function (foo, bar) {
// Begin a workflow
var workflow = new (require('events').EventEmitter)();
workflow.on('test', function () {
var greet = greet();
return greet;
});
workflow.emit('test');
};
function greet () {
return "Hi!";
}
module.exports = {
myModule: myModule
};
How can I test my module with Jasmine targeting all my Events I emit?
Something like this:
var myModule = require('../myModule.js');
describe('My Module test', function () {
it('should get greet value', function () {
myModule.on('test', function () { // "test" as I wrote in myModule
expect(myModule.greet).toHaveBeenCalled();
});
});
});
I accomplish this using proxyquire: https://github.com/thlorenz/proxyquire
In your test file:
var proxyquire = require('proxyquire');
var mockEvents = {};
var myModule = proxyquire('../myModule.js', {
events: mockEvents
});
describe('My Module test', function () {
beforeEach(function() {
mockEvents.EventEmitter = function () {};
mockEvents.EventEmitter.prototype = {
on: function () { },
emit: function () { }
};
spyOn(mockEvents.EventEmitter.prototype, 'on');
spyOn(mockEvents.EventEmitter.prototype, 'emit');
});
it('should get greet value', function () {
myModule()
expect(mockEvents.EventEmitter.prototype.on).toHaveBeenCalledWith('test');
expect(mockEvents.EventEmitter.prototype.emit).toHaveBeenCalledWith('test');
});
});
You can also use a spy as your mock EventEmitter, etc.
The main problem is that greet is not really exposed and is therefore not accessible in the tests. Here are some ways to handle this:
Add it to the prototype chain to make it accessible (this is what I have done below).
Expose the function in the module.exports. This could be wrapped in a process.env.NODE_ENV !== production to exclude it from production.
Not expose it but test the event emitter functionality and impact of the function (this is probably not ideal).
To achieve what you want, you could monkey patch the functions and test that they have been called and test the result of greet individually:
MyModule.js
var EventEmitter = require('events').EventEmitter;
var MyModule = function (foo, bar) {
// Begin a workflow
var workflow = new EventEmitter();
workflow.on('test', function () {
return this.greet();
}.bind(this));
workflow.emit('test');
};
MyModule.prototype.greet = function () {
return "Hi!";
};
module.exports = MyModule;
MyModule-tests.js
var EventEmitter = require('events').EventEmitter;
describe('MyModule', function () {
it('emits an event upon construction', function () {
// Monkey patch
var originalEventEmitterOn = EventEmitter.prototype.on;
EventEmitter.prototype.on = jasmine.createSpy('on');
// Create module
var MyModule = require('./MyModule');
new MyModule();
expect(EventEmitter.prototype.on).toHaveBeenCalled();
// Reset
EventEmitter.prototype.on = originalEventEmitterOn;
});
it('calls greet upon construction', function () {
var MyModule = require('./MyModule');
// Monkey patch
var originalGreet = MyModule.prototype.greet
MyModule.prototype.greet = jasmine.createSpy('greet');
var myModule = new MyModule();
expect(myModule.greet).toHaveBeenCalled();
// Reset
MyModule.prototype.greet = originalGreet;
});
it('returns "Hi!"', function () {
var MyModule = require('./MyModule');
var myModule = new MyModule();
expect(myModule.greet()).toBe("Hi!");
});
});

miss prototype functions when "new" a instance

I write a module in nodejs ,which Test.js ,code blow
function Test() {
this.key = 'value';
}
Test.prototype.foo = function () { return 'foo'; }
module.exports = Test;
and then, in B.js
var Test = require('./services/Test');
var test = new Test();
console.log(test.foo());
unfortunetly, I got "undefined method foo",
anyone who can Tell me what happended? thanks so much
Check your file location it should be in services directory.
function Test() {
this.key = 'value';
}
Test.prototype.foo = function () { return 'foo'; }
module.exports = new Test();//Test;
var test = require('./services/Test');
console.log(test.foo());
You can export the new object of Test class. try this.
Or you can use ES6 JavaScript that great.
In Test.js try moving the module.exports to before you define the prototype functions.
As below:
function Test() {
this.key = 'value';
}
module.exports = Test;
Test.prototype.foo = function () { return 'foo'; }

Export function first and object subsequently

I have a custom module and would like to provide a method to initialize it on first require, but directly return an object on subsequent requires.
But the module gets cached when first required and therefore subsequent requires still return the init function instead of returning obj directly.
server.js:
var module = require('./module.js');
var obj = module.init();
console.log('--DEBUG: server.js:', obj); // <-- Works: returns `obj`.
require('./other.js');
other.js:
var obj = require('./module.js');
console.log('--DEBUG: other.js:', obj); // <-- Problem: still returns `init` function.
module.js:
var obj = null;
var init = function() {
obj = { 'foo': 'bar' };
return obj;
};
module.exports = (obj) ? obj : { init: init };
How can I work around that problem? Or is there an established pattern for achieving such?
But I would like to keep obj cached, because my real init does some work I would rather not do on every require.
There are some ways to clear the require cache. You may check here node.js require() cache - possible to invalidate?
However, I think that this is not a good idea. I'll suggest to pass the module which you need. I.e. initialize it only once and distribute it to the other modules.
server.js:
var module = require('./module.js');
var obj = module.init();
require('./other.js')(obj);
other.js:
module.exports = function(obj) {
console.log('--DEBUG: other.js:', obj); // <-- The same obj
}
module.js:
var obj = null;
var init = function() {
obj = { 'foo': 'bar' };
return obj;
};
module.exports = { init: init };

Categories