How to test an internal function - javascript

I'm trying to create a unit test to cover an internal function
fileA.js
module.exports.functionA = () {
const functionB = () {
// do something
}
functionB()
}
test.js
const { functionA } = require('fileA')
...
it('runs functionB', () => {
functionA()
expect(...).toHaveBeenCalled()
}
How do I access it?

There are two possibilities here (your situation looks like the first one, but is also clearly simplified for the purposes of the question).
Either:
functionB is entirely private to functionA, part of its implementation, which means you can't access it to test it (directly). Instead, test functionA, which presumably uses functionB as part of the work it does (otherwise, there's no point in an entirely private function in functionA).
or
functionA exposes functionB in some way (for instance, as a return value, or as a method on a returned object, or by setting it on an object that's passed in, etc.), in which case you can get it in whatever way functionA provides and then test it.
(Again, I think yours is the first case.)

Related

Internal vs Exported References to Module Methods

I'm trying to better understand the how & why of differences between references to an internal module method vs the reference that is created when that same method is exported.
I'm not even sure my terminology is correct, and searching for information has not turned up anything useful.
A simplified example ...I have a simple module that performs some maths:
export const doubleNumber = (num) => {
return num * 2
}
export const squareNumber = (num) => {
return num * num
}
export default {
double: (num) => doubleNumber(num),
square: (num) => squareNumber(num),
}
...and I have some unit tests to verify functionality:
import * as numProvider from './number-provider'
describe('the default methods', () => {
it('should call the correct math method when its property method is called', () => {
const doubleSpy = jest.spyOn(numProvider, 'doubleNumber')
const result = numProvider.default.double(1)
expect(result).toBe(2)
expect(doubleSpy).toHaveBeenCalledTimes(1)
})
})
(example project with the above code)
Now when I run my test it fails. From what I understand, the method I'm spying on (the exported method), is never called because numProvider.default.double is referencing the internal method.
I can verify this (and fix the test) by attaching the exported method to the default export object instead, double: (num) => exports.doubleNumber(num) but then of course the site breaks because exports is not defined in the browser.
So my question (I think?) is..
What is JavaScript (or some other process?) doing that causes the creation of these two separate references?
What is JavaScript (or some other process?) doing that causes the creation of these two separate references?
The crux of the issue is that exports are properties on an object that contain separate references to functions within the module and you're only spying on function calls made through the exported property on the object. You're not spying on the underlying function itself so calls made directly to the underlying function are not monitored.
In fact, the Javascript language doesn't provide a way to spy on the underlying core function when all you have is a reference to it. Calls to the core function are made through whatever reference you have. Declaring a function creates a symbol and assigns it a reference to the function you declared. Declaring an export for that creates a property on an object and assigns it another reference to the same underlying function.
Spying on the object hooks the function reference in that object (replaces it with a monitoring function) and it can only monitor calls that are made through that object property because only those will actually call the replacement monitoring function.
I'll give you an example using plain objects so you can see what's going on without the added distraction of exports:
// simple version of spyOn
const spy = function(obj, methodName) {
let orig = obj[methodName];
obj[methodName] = function() {
console.log(`spyhit for obj.${methodName}()`);
}
}
// core function
const doubleNumber = function(num) {
return num * 2
}
// object that contains reference to core function
const myObj = {
double: doubleNumber
};
// lets spy on myObj.double
spy(myObj, "double");
myObj.double(1); // generates spyhit
doubleNumber(1); // does not generate spyhit
Here you can see that only calls made through the actual property that you spied on myObj.double() are actually spied on. There's no spying of the actual core function.
This is because myObj.double is all that the spy function is given. That property contains a reference to doubleNumber, but isn't the actual function itself. The spy() method here (similar to what jest is doing) just replaces the actual property with a monitoring function so that it can record when it's called. But, it has no ability to replace the actual core function itself.

Using this vs using variable in JS

I am having tough time figuring out when should we preferably use this keyword and when shouldn't we use it..
For example, I was earlier doing something like this.
let socket;
class something extends Component {
componentDidMount() {
socket = openSocket('https://coincap.io');
}
componentDidUpdate() {
socket.on('trades', (tradeMsg) => {
}
componentWillUnmount() {
this.socket.disconnect();
}
then someone re-structured my code did something like
class something extends Component {
componentDidMount() {
this.socket = openSocket('https://coincap.io');
}
componentDidUpdate() {
this.socket.on('trades', (tradeMsg) => {
}
componentWillUnmount() {
this.socket.disconnect();
}
[Question:] While, Both the code works and do the job, I am perplexed between understanding which methods should we use and why did he used this keyword?
You are dealing with ES6, which takes out a lot of ambiguity pertaining to the this keyword in the language.
Quite simply, this means (in the more traditional sense) the current scope; however, in JavaScript, this means the object calling the function as opposed to the current scope.
As mentioned previously, ES6 takes out a lot of complexity regarding variable hoisting and the likes.
Coming to your question, the reason it was refactored to this.something was because when your class is called (now, remember, JavaScript follows prototypal inheritance and is a first-class language; meaning that function prototypes are the class bases and functions can be passed as parameters) it will act like a function and the this keyword will refer to the object or the context where it was called.
If we have the following bit of code:
let foo = 'bar';
const fn = () => { console.log( this.foo ); }
fn();
The execution context would be window and the foo variable would be window.foo; hence, this.foo would translate to window.foo.
Similarly, your code will be transpiled something like:
var socket = new Socket();
function className() {}
className.prototype.someFunction = function() {
console.log( socket );
}
Here, the this keyword would make sure that the current context is used instead of local variables which you might use within your function.
I hope this makes it clear. Here is a great article to understand the this keyword! :)
The problem isn't the difference between this and a variable per se. It's that this refers to class instance and allows to have multiple class instances and thus multiple socket instances, while socket variable refers to specific socket instance and will be overridden in subsequent component instances.
The component will malfunction if there's more than one component instance at time, because socket variable refers to latest openSocket('https://coincap.io') result.
Also, this
let socket;
class something extends Component {
componentDidMount() {
socket = openSocket('https://coincap.io');
}
componentDidUpdate() {
socket.on('trades', (tradeMsg) => {
}
componentWillUnmount() {
this.socket.disconnect();
}
will result in error on component unmount because there's no this.socket.

declaring a function inside a function - javascript

I'm trying to build a middleware in redux to handle api requests.
While looking for inspiration I found this code:
redux api middleware
export default store => next => action => {
const callAsync = action[CALL_API];
if(typeof callAsync === 'undefined') {
return next(action);
}
.
.
.
function actionWith(data) {
const finalAction = assign({}, action, data);
delete finalAction[CALL_API];
return finalAction;
}
next(actionWith({ type: types.REQUEST }));
.
.
.
}
My question is: Why is the function actionWith decalared inside of the main function? Wouldn't it be more simple if the function was decalared outside and one will pass the function the action object also?
What is the benefit here?
Wouldn't it be more simple if the function was decalared outside and one will pass the function the action object also?
You are correct: you could have take actionWith outside of the outer function as long as you supplied action as an argument (actionWith(data, action)).
The functionality would be the same. However, the primary concern I have is maintainability: if you needed to modify the inner function to do something that required yet another variable from the outer function , you'd need to add another argument. If the duty of the function is closely tied to the internals of the outer function, leaving it in gives you ready access to the outer function's variables when you need to modify the code.
I would balance this concern of extra arguments (which generally favors keeping the function internal) against the usefulness of having the function available to other part of the code (which would favor taking it outside, for increased visibility). For example, if I had many outer functions that each had their own internal copies of actionWith, it would be better to have them to share a single version of actionWith.
That is, if I had
function outer1(action) {
function actionWith(data) { ... }
actionWith(thing);
}
function outer2(action) {
function actionWith(data) { ... }
actionWith(thing);
}
From a maintainability perspective, I would rather have
function actionWith(action, data) { ... }
function outer1(action) {
actionWith(action, thing);
}
function outer2(action) {
actionWith(action, thing);
}

Javascript: Mocking Constructor using Sinon

I am pulling my hair out trying to figure out how to mock a constructor using sinon. I have a function that will create multiple widgets by calling a constructor that accepts a few arguments. I want to verify that the constructor is called the correct number of times with the correct parameters, but I don't want to actually construct the widgets. The following links seemingly explain a straightforward way of mocking the constructor, however it does not work for me:
Spying on a constructor using Jasmine
http://tinnedfruit.com/2011/03/25/testing-backbone-apps-with-jasmine-sinon-2.html
When I make the following call to stub the constructor:
sinon.stub(window, "MyWidget");
I get the following error:
Uncaught TypeError: Attempted to wrap undefined property MyWidget as function
When debugging in Chrome I see MyWidget shows up in the Local section of the Scope Variables, however there is not MyWidget property off of window.
Any help would be greatly appreciated.
I needed a solution for this because my code was calling the new operator. I wanted to mock the object that the new call created.
var MockExample = sinon.stub();
MockExample.prototype.test = sinon.stub().returns("42");
var example = new MockExample();
console.log("example: " + example.test()); // outputs 42
Then I used rewire to inject it into the code that I was testing
rewiredModule = rewire('/path/to/module.js');
rewiredModule.__set__("Example", example);
From the official site of sinonjs:
Replaces object.method with a stub function. The original function can be restored bycalling object.method.restore(); (or stub.restore();). An exception is thrown if the property is not >already a function, to help avoid typos when stubbing methods.
this simply states that the function for which you want to create the stub must be member of the object object.
To make things clear; you call
sinon.stub(window, "MyWidget");
The MyWidget function needs to be within the global scope (since you pass window as parameter). However, as you already said, this function is in a local scope (probably defined within an object literal or a namespace).
In javascript everyone can have access to the global scope, but not the other way around.
Check where you declare the MyWidget function and pass container object as first parameter to sinon.stub()
Using Sinon 4.4.2, I was able to mock an instance method like this:
const testObj = { /* any object */ }
sinon.stub(MyClass.prototype, "myMethod").resolves(testObj)
let myVar = await new MyClass(token).myMethod(arg1, arg2)
// myVar === testObj
A similar solution provided here:
Stubbing a class method with Sinon.js
I used Mockery to Mock a Constructor/Function without any problems.
var mockery = require('mockery');
var sinon = require('sinon');
mockery.enable({
useCleanCache: true,
warnOnReplace: false,
warnOnUnregistered: false
});
exports.Client = function() {/* Client constructor Mock */};
var ClientSpy = sinon.spy(exports, 'Client');
mockery.registerMock('Client', ClientSpy);
var Factory = require('Factory'); // this module requires the Client module
You should be able to apply a Sinon Spy just as the example above does.
Make sure to disable or reset Mockery after the test(s)!
Use sinon.createStubInstance(MyES6ClassName), then when MyES6ClassName is called with a new keyword, a stub of MyES6ClassName instance will returned.
I ran into this error by mistakenly typing sinon.stub.throws(expectedErr) rather than sinon.stub().throws(expectedErr). I've made similar mistakes before and not encountered this particular message before, so it threw me.
Mocking and stubbing the constructor with sinon
I give two solutions. The first addresses the question, how to mock the constructor with behaviour, the second shows how to stub it with a dummy. Google guided me multiple times to this question for the search how to stub it.
Mocking the constructor with behaviour
I don't know if this is the shortest path. At least it does, what was asked for.
First I use sinon's fake method to create a mocking constructor Mock with the behaviour I want. Then I have to add the methods one by one. For reasons I didn't investigate, it did not work, when setting the whole prototype of UnderTest to Mock.
require('chai').should();
const { fake} = require('sinon');
class UnderTest {
constructor() {
this.mocked = false;
}
isMocked() {
return this.mocked;
}
}
describe('UnderTest', () => {
let underTest;
let isMocked;
before(() => {
const Mock = fake(function () { this.mocked = true; });
Mock.prototype.isMocked = UnderTest.prototype.isMocked;
underTest = new Mock();
isMocked = underTest.isMocked();
});
it('should be mocked', () => {
isMocked.should.be.true;
});
});
Stubbing the constructor with a dummy
If you are leaded to this post, because you just want to stub the constructor to keep it from being executed.
Sinon's createStubInstance creates a stubbed constructor. It also stubs all methods. Hence, the method under test has to be restored before.
require('chai').should();
const { createStubInstance } = require('sinon');
class UnderTest {
constructor() {
throw new Error('must not be called');
}
testThis() {
this.stubThis();
return true;
}
stubThis() {
throw new Error('must not be called');
}
}
describe('UnderTest', () => {
describe('.testThis()', () => {
describe('when not stubbed', () => {
let underTest;
let result;
before(() => {
underTest = createStubInstance(UnderTest);
underTest.testThis.restore();
result = underTest.testThis();
});
it('should return true', () => {
result.should.be.true;
});
it('should call stubThis()', () => {
underTest.stubThis.calledOnce.should.be.true;
});
});
});
});
Just found this in the documentation.
If you want to create a stub object of MyConstructor, but don’t want the constructor to be invoked, use this utility function.
var stub = sinon.createStubInstance(MyConstructor)
I was able to get StubModule to work after a few tweaks, most notably passing in async:false as part of the config when requiring in the stubbed module.
Kudos to Mr. Davis for putting that together

Expecting the right calling context (this) in the JavaScript object

Consider this:
window.onload = function () {
myObj.init();
};
var myObj = {
init: function () {
console.log("init: Let's call the callMe method...");
//callMe is not defined...
callMe();
//Works fine!
this.callMe();
},
callMe: function () {
console.log('callMe');
}
};
Since the init function gets called this way (myObj.init), I expect this to be myObj in the init function. And if that is the case, why the callMe function fails? How am I supposed to call the callMe function without using the this context in the init body? (Actually, it's too annoying to call the object methods using this over and over again through the functions. So what's the point of having a single object?)
I would like to know how can I fix this so that the callMe method gets called using the first invocation in the code above?
this is never implicit in JavaScript as it is in some other languages. Although there are ways to do it, like this using the with statement:
init: function () {
console.log("init: Let's call the callMe method...");
// Make `this` implicit (SEE BELOW, not recommended)
with (this) {
// Works
callMe();
}
},
...it's generally a bad idea. Douglas Crockford probably wrote one of the better descriptions of why it's a bad idea, which you can find here. Basically, using with makes it nearly impossible to tell what the code's going to do (and slows the code down, if you do anything else in that with statement that doesn't come from the this object).
This isn't the only way that JavaScript's this is not the same as it is in some other languages. In JavaScript, this is defined entirely by how a function is called, not where the function is defined. When you do this.callMe() (or the equivalent this["callMe"](), or of course foo.callMe(), etc.), two things happen: The function reference is retrieved from the property, and the function is called in a special way to set this to be the object that property came from. If you don't call a function through a property that way, the call doesn't set any particular this value and you get the default (which is the global object; window on browsers). It's the act of making the call that sets what this is. I've explored this in depth in a couple of articles on my blog, here and here.
This (no pun) can be made even clearer if you look at JavaScript's call and apply functions, which are available on all function objects. If I do this:
callMe.call({});
...it'll call the callMe function with a blank object ({}) as this.
So basically, just get used to typing this. :-) It's still useful to have properties and methods associated with an object, even without the syntactic convenience (and confusion!) of an implicit this.
You can also use the module pattern, which captures all private variables inside a closure, so you are free to use them without this, as they're in the same scope. You then pick and choose which methods/variables you want to make public:
var myObj = (function () {
var init = function () {
callMe(); // This now works
};
var callMe = function () {
...
};
// Now choose your public methods (they can even be renamed):
return {
init: init, // Same name
callMyName: callMe // Different name
};
}) ();
Now:
myObj.init(); // Works
myObj.callMyName(); // Works
myObj.callMe(); // Error

Categories