shared functionality in mocha tests - javascript

I put the following code in its own file called shared.js
afterEach(function () {
// insert code
});
var foo;
beforeEach(function () {
foo = {
bar: []
};
});
exports = module.exports = {};
exports.foo = foo;
I'd like the afterEach and beforeEach to be ran in every mocha.js test I have. so in each test file, I required shared.js.
The problem is it seems foo isn't available in the scope of my tests. foo.bar is undefined and inaccessible. The beforeEach() and afterEach hooks are running just fine, but I'm having trouble understanding how to properly export the scope of foo. This might be more of a Node.js problem than an actual Mocha problem.

The problem is that you can not modify the exported reference. In your case you are exporting undefined, because foo is uninitialized. If you initialize foo with an empty object and later try to reassign it to a different thing/object it will still not work because the exported reference is still the same.
The only thing you can do is modifying (mutating) the exported object like so:
afterEach(function () {
// insert code
});
var foo = {};
beforeEach(function () {
foo.bar = [];
});
exports = module.exports = {};
exports.foo = foo;

If you want something that is specific to the context of each test, you can do something like the following:
afterEach(function () {
// insert code
});
beforeEach(function () {
this.foo = [];
});
exports = module.exports = {};
each test can then access its own this.foo:
describe('myTest', function() {
it('should do something', function() {
this.foo.push("1"); // same 'this' as from beforeEach
// ...insert code
})
})

Related

Jasmine checking if variable is defined in method

I'm new to jasmine. My Company is using jasmine 1.3.1
I am trying to test if a variable is defined in a method. I keep coming back with a failure.
objectParentName.accessoriesSlider = {
modifyJSON: function(obj) {
var contentLoadJSON = [];
for (var property in obj) {
objectParentName.accessoriesSlider.contentJSONTotal++
contentLoadJSON.push(obj[property]);
}
contentLoadJSON = objectParentName.accessoriesSlider.sortJSON(contentLoadJSON, 'dateAdded', false);
return contentLoadJSON;
}
}
Here is jasmine for that method.
describe('Test "modifyJSON" function', function () {
beforeEach(function() {
spyOn(objectParentName.accessoriesSlider, 'modifyJSON');
var contentLoadJSON = []; //forcibly add variable to see if that fixes issue
objectParentName.accessoriesSlider.modifyJSON();
});
it('is defined as "modifyJSON"', function () {
/**
* objectParentName.accessoriesSlider.modifyJSON should be defined.
*/
expect(objectParentName.accessoriesSlider.modifyJSON).toBeDefined();
});
it('and "modifyJSON" is a function', function () {
/**
* This should be a 'function'.
*/
expect(objectParentName.accessoriesSlider.modifyJSON).toBeFunction();
});
describe('Test "contentLoadJSON" variable', function () {
it('is defined', function () {
expect(contentLoadJSON).toBeDefined();
});
});
});
I am getting this error
ReferenceError: contentLoadJSON is not defined
at .<anonymous> (http://localhost:8234/spec/jasmine_accessories_slider.js:300:24)
at jasmine.Block.execute (http://localhost:8234/?spec=accessories_slider.js:1164:19)
at jasmine.Queue.next_ (http://localhost:8234/?spec=accessories_slider.js:2196:33)
at jasmine.Queue.start (http://localhost:8234/?spec=accessories_slider.js:2149:10)
at jasmine.Spec.execute (http://localhost:8234/?spec=accessories_slider.js:2476:16)
at jasmine.Queue.next_ (http://localhost:8234/?spec=accessories_slider.js:2196:33)
at jasmine.Queue.start (http://localhost:8234/?spec=accessories_slider.js:2149:10)
at jasmine.Suite.execute (http://localhost:8234/?spec=accessories_slider.js:2621:16)
at jasmine.Queue.next_ (http://localhost:8234/?spec=accessories_slider.js:2196:33)
at jasmine.Queue.start (http://localhost:8234/?spec=accessories_slider.js:2149:10)
So, I have no idea why I am getting an error here.
The first problem is that the variable contentLoadJSON is not defined in the scope of the function you are calling it from.
When you define a variable using var, it becomes a local variable, and is only accessible inside the scope of that function. In this case, the function it exists in is:
beforeEach(function() {
spyOn(objectParentName.accessoriesSlider, 'modifyJSON');
var contentLoadJSON = [];
objectParentName.accessoriesSlider.modifyJSON();
});
The function you are getting the error in is a different function() { ... } that isn't nested in beforeEach. It is therefore can't see the local variable you defined.
One way to rectify this is by defining the variable in the scope of your test suite, instead of in the scope of the beforeEach function:
describe('Test "modifyJSON" function', function () {
var contentLoadJSON; // Define it here
beforeEach(function() {
contentLoadJSON = []; // Assign it here
// ... more code here ...
}
// ... more code here ...
describe('Test "contentLoadJSON" variable', function () {
it('is defined', function () {
// Test contentLoadJSON here...
The second problem is that just because variables have the same name doesn't mean they are actually the same variable. They have to also be in the same scope for that to be true. var contentLoadJSON inside modifyJSON is actually a totally different variable than the var contentLoadJSON you are defining in beforeEach in your test suite.
When you call the function under test, you are not assigning its result to the variable you are trying to test. In fact, you are actually throwing away the result immediately after you call the function.
To fix this, change:
var contentLoadJSON = [];
objectParentName.accessoriesSlider.modifyJSON();
// Note that contentLoadJSON still equals [] at this point.
// The return of the function call is getting thrown away,
// because you don't assign it to a variable
To:
var contentLoadJSON = objectParentName.accessoriesSlider.modifyJSON();
The third problem is that expect(someVariable).toBeDefined(); might not do what you are expecting it to do. It doesn't check that the variable is "in scope". It checks that the value someVariable is not equal to the value undefined. Unless your function might sometimes return undefined, then this particular test isn't very important and will probably never fail.
It may be better to check that the result is "truthy" (expect(contentLoadJSON).toBeTruthy()). It might even make sense to just check that it is equal to the value you'd expect for the given data/input.

JavaScript Function Hoisting in my Object

I have created an object and am attaching a bunch of functions to the object. I am concerned about how the ordering of the functions effects when I can call my functions. In my example below, I must define my functions first before I can use them. My problem with this is that I cannot call init() immediately until I have defined it. Init() will contain a bunch of other functions that it will need to call, which will have to be placed above init(). So in the end, init() will have to be the very last function defined in my object. I believe this is related to Hoisting.
My question is if there is a way for me to call a function before defining it? Is there some sort of way to create a 'placeholder' function like in C?
https://jsfiddle.net/13hdbysh/1/
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
//this will error
foo.init();
foo.init = function() {
console.log('init()');
};
})();
What you're asking deals with how objects store member data. This can be seen in a weird light because of prototypal inheritance. Javascript by default will parse naked functions before they execute.
Example:
(function() {
init();
function init()
{
console.log("Init");
}
)};
This gets muddied when storing behavior as a member to an object. Because prototypal inheritances dynamic functionality you need to declare your members before accessing them. This is Javascript's main difference from traditional OOP languages.
You mentioned, "is there a way to create a 'placeholder' function like in C." You can, but not in the same way. You can assign it to a naked function and assign that to your object. Look in my example, the hello function.
Alternatively you can store the behavior on the prototype of your object and override it when necessary.
Example:
function hello()
{
console.log("Hello my name is "+this.name);
}
(function() {
var something = function(name) {
this.name = name;
};
something.prototype.initTwo = function() {
console.log("My Name is: "+this.name);
};
var thingOne = new something("Thing One");
thingOne.init = "SomeThing";
var thingTwo = new something("Thing Two");
thingTwo.init = function() {
console.log(this.name);
};
thingTwo.initTwo = function() {
console.log("SomethingTwo is Named: "+this.name);
};
thingTwo.hello = hello;
console.log(thingOne.init);
thingTwo.init();
thingOne.initTwo();
thingTwo.initTwo();
thingTwo.hello();
}) ();
Demo: Fiddle
Documentation on objects in javascript.
Try using similar IIFE pattern
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
//this will error
// foo.init();
foo.init = (function _foo() {
console.log('init()');
this.init = _foo;
return this.init
}).call(foo);
foo.init()
})();
jsfiddle https://jsfiddle.net/13hdbysh/2/
I am not sure why would you wanna call it before it is defined but here is how to do it:
foo = window.foo || { init: function() { } };
How about declaring it as a local variable first.
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
var initFunction = function() {
console.log('init()');
};
//this will no longer error
initFunction();
foo.init = initFunction;
})();
Init() will contain a bunch of other functions that it will need to call, which will have to be placed above init().
You are operating under a misapprehension.
A function must be defined before you call it, not before you define another function which will call it later.
Just define all your functions and then start calling them.
(function() {
foo = window.foo || {};
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.init = function() {
console.log('init()');
};
foo.init();
foo.helloWorld();
})();
As far as hoisting is concerned, function declarations (you only have function expressions) are hoisted, but they create locally scoped variables, not object properties. You would have to assign them to object properties before you could call them as such, and that assignment wouldn't be hoisted.
It's throwing an error because you're calling the method init() before it's declared.
This way will works
foo.init = function() {
console.log('init()');
};
foo.init();
Since foo is an object, you can put those functions into an object so that will be assigned to foo once window.foo is null
(function() {
foo = window.foo || {
helloWorld: function() {
console.log('helloWorld()');
},
init: function() {
console.log('init()');
}
};
//this will not error
foo.helloWorld();
foo.init()
})();

Jasmine - how to spyOn instance methods

I have a function
var data = {};
var myFunc = function() {
data.stuff = new ClassName().doA().doB().doC();
};
I'd like to test that doA, doB, and doC were all called.
I tried spying on the instance methods like this
beforeEach(function() {
spyOn(ClassName, 'doA');
};
it('should call doA', function() {
myFunc();
expect(ClassName.doA).toHaveBeenCalled();
});
but that just gives me a "doA() method does not exist" error.
Any ideas?
Where you went wrong was your understanding of how to refer to methods in JavaScript in a static context. What your code is actually doing is spying on ClassName.doA (that is, the function attached to the ClassName constructor as the property doA, which is not what you want).
If you want to detect when that method gets called on any instance of ClassName anywhere, you need to spy on the prototype.
beforeEach(function() {
spyOn(ClassName.prototype, 'doA');
});
it('should call doA', function() {
myFunc();
expect(ClassName.prototype.doA).toHaveBeenCalled();
});
Of course, this is assuming that doA lives in the prototype chain. If it's an own-property, then there is no technique that you can use without being able to refer to the anonymous object in myFunc. If you had access to the ClassName instance inside myFunc, that would be ideal, since you could just spyOn that object directly.
P.S. You should really put "Jasmine" in the title.
Let’s do some code refactoring as we want implement constructor injection pattern as James Shore mentions that:
Dependency injection means giving an object its own instance variables. Really. That’s it.
var data = {};
var stuff = new ClassName()
var myFunc = function(stuff) { // move step of creation new object outside
data.stuff = stuff.doA().doB().doC();
};
And time for some tests
function ClassName() {
}
var data = {};
var stuff = new ClassName()
var myFunc = function(stuff) {
data.stuff = stuff.doA().doB().doC();
};
describe('stub for ClassName implementation', function() {
var stubStuff = {
doA: function() {
return stubStuff
},
doB: function() {
return stubStuff
},
doC: function() {
return stubStuff
}
}
beforeEach(function() {
spyOn(stubStuff, 'doA').and.callThrough();
});
it('calls "doA" on "myFunc" exection', function() {
myFunc(stubStuff);
expect(stubStuff.doA).toHaveBeenCalled();
});
});
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>

How to properly require a node module, exporting all the functions in it

I have a file stats.js.
It's contents are
(function () {
func1 = function () {
}
func2 = function () {
}
module.exports = this;
}).call(this);
Alegedly, when I do
var stats = require("./stats");
I should be able to get func1 and func2 with stats.func1, stats.func2, right?
Well, I can't. The stats object is just empty. A few traces in the stats.js revealed that "this" is also an empty object.
What gives?
First and foremost see this link.
Now lets see your code -
var stats = require("./stats");
//My steps -
//First Log
console.log(stats.func1); // returns undefined
//Second Log
console.log(global.func1, global === GLOBAL); // returns [Function], true
Take aways from this code -
1. In the browser the global object is window object.
2. In node.js it is the global object.
3. Defining something using var in a module will only create a variable with a module scope.
4. Defining something without the var keyword will create a variable in the global scope.
So func1 and func2 were defined in the global scope. Passing this to module.exports will pass the current module object only.
hope it helps, happy coding!
No it shouldnt? That format is nothing like what Node.js needs in order to do its job.
"What gives" is that you didn't read up on how node works. Node.js isn't just "JavaScript", it's a proramming model with a much richer API and specific behaviours. Requires use the "module.exports" object, so it would be a good idea to actually read up on how to use node.
mything.js:
var func3 = function() { ... },
prop = "something";
...
module.exports = {
func1: function() { ... },
func2: function() { ... },
func3: funct3,
prop: prop,
...
};
which is identical to:
var func3 = function() { ... },
prop = "something",
...
MyLib = {
func1: function() { ... },
func2: function() { ... },
func3: funct3,
prop: prop,
...
};
...
module.exports = MyLib;
app.js:
var mything = require("mything);

JavaScript design patterns: Injecting a dependency that is not yet created

I have a CommonJS module:
// main-module
module.exports = function () {
var foo,
someModule = require('other-module')(foo);
// A value is given to foo after other-module has been initialised
foo = "bar";
}
As you can see, this requires other-module:
// other-module.js
module.exports = function (foo) {
function example() {
console.log(foo);
// > "bar"
}
}
I would like the example function inside of other-module to be aware of the foo variable inside of main-module, even though is it established after the module is required.
When other-module runs, foo will not be undefined. However, the point is that by time my example function runs, foo will have been given a value of bar.
The pattern above obviously does not work. What design pattern do I need to implement?
I'm not super-familiar with CommonJS, so this might not be the idiomatic way to do it, but using a function instead of a variable should work:
// main-module
module.exports = function () {
var foo,
someModule = require('other-module')(function() { return foo; });
foo = "bar";
}
// other-module.js
module.exports = function (fooFn) {
function example() {
console.log(fooFn());
}
}
The foo value (a string) will be passed by value, so it's undefined inside other-module. You could use an options object that is passed by reference:
var options = {},
someModule = require('other-module')(options);
options.foo = "bar";

Categories