I have a Javascript modular application not using Angular/Backbone.
I am trying to write test case for my startup module but facing issue.
Startup.js:
window.claimStartup = function (options) {
this.options = $.extend({}, this.options, options);
this.cmds = new this.serviceModule(this);
}
getClaimsCategories: function (claimTypeCode) {
var self = this;
// Refresh claim categories
return $.when(self.cmds.getClaimsCategories(claimTypeCode))
.then(function (response) {
return response;
});
},
Service.js:
claimStartup.prototype.serviceModule = function (cfg) {
this.cfg = cfg;
this.init();
}
StartUp.spec.js:
var claimStartUp;
beforeEach(function () {
spyOn(window.claimStartup.prototype, 'serviceModule');
claimStartUp = new window.claimStartup();
});
it("should be able to get categories", function () {
jasmine.spyOn(claimStartUp.cmds, 'getClaimsCategories').andReturn('XYZ');
var categories= claimStartup.getClaimsCategories('ABC');
expect(categories).toEqual('XYZ');
});
I am getting error when populating this.cmds it says serviceModule constructor not defined, actually I need to mock serviceModule when claimStartup is initialised.
Please let me know how can i write test case in this scenario.
I am able to fix this, this might be useful for others.
var claimStartUp;
beforeEach(function () {
var spyService = jasmine.createSpy('serviceModule');
var methodService = window.claimStartup.prototype.serviceModule;
window.claimStartup.prototype.serviceModule = spyService;
var spyUI = jasmine.createSpy('uiModule');
var methodUI = window.claimStartup.prototype.uiModule;
window.claimStartup.prototype.uiModule = spyUI;
claimStartUp = new window.claimStartup();
});
Related
I've looked through a few questions related to this error, and most of them seem to be a misunderstanding of what the keyword this means. I don't think I'm having that problem here. Mine might be some sort of circular dependency problem that I cannot articulate well enough to figure it out on my own.
I've tried to distill my problem into three files presented below.
something.js
var A = require('../lib/a');
var Something = function (type) {
this.type = type;
};
Something.prototype.setTemplate = function (template) {
this.template = template;
};
Something.prototype.applyTemplate = function () {
var templateResult = this.template.calculate();
};
var factory = {};
factory.createSomething = function(type) {
return new Something(type);
};
factory.createA = function (input) {
return A.Make(input);
};
module.exports = factory;
a.js
var S = require('../prof/something');
var _ = require('underscore');
var A = function (input) {
this.input = input;
};
A.prototype.calculate = function () {
var calculation = 0;
var _s = S.createSomething('hello world');
// do calculation using input
return calculation;
};
var factory = {};
factory.Make = function (input) {
var a = new A(input);
return a;
};
module.exports = factory;
a_test.js
describe('Unit: A Test', function() {
var S = require('../prof/something');
it('test 1', function() {
var a = S.createA({
//input
});
var s = S.createSomething('type1');
s.setTemplate(a);
s.applyTemplate(); // error
});
});
The error gets thrown from the top level in a_test.js on the line with the comment //error. At the lowest level, the 'is not a function ' error is thrown in a.js at the S.createSomething(type) method. It says that S.createSomething() is not a function.
I've put a breakpoint in at that line and tried to call functions from the underscore library, but it gives the same error. So it seems that the require statements inside a.js are not throwing errors, but none of the injected objects can be used to call functions from. The a_test.js file is being run with the karma library.
Am I violating some javascript paradigm by referencing back and forth between A and S? How can I do this properly?
Edit: I've done some further testing. It doesn't actually matter if the test file looks like this:
describe('Unit: A Test', function() {
var S = require('../prof/something');
it('test 1', function() {
var a = S.createA({
//input
});
a.calculate(); // error
});
});
An error is still thrown at the line indicated above.
The files in the question reference each other. This is called cyclic dependencies. The solution is to move the var S = require('../prof/something'); statement into the calculate function like so:
a.js
// move the line from here
var _ = require('underscore');
var A = function (input) {
this.input = input;
};
A.prototype.calculate = function () {
var S = require('../prof/something'); // to here
var calculation = 0;
var _s = S.createSomething('hello world');
// do calculation using input
return calculation;
};
var factory = {};
factory.Make = function (input) {
var a = new A(input);
return a;
};
module.exports = factory;
I am trying to mock out every instance that is created with the new keyword for an object.
Here is the Object I am trying to mock out:
var SharedWhiteboardView = function(moduleEl, domService) {
'use strict';
var self;
var sharedWhiteboardProblemImage;
var whiteboardController;
var caller = false;
var toolbarController;
return {
initWhiteboard : function()
{
self = this;
sharedWhiteboardProblemImage = domService.find(moduleEl, '#sharedWhiteboardModule-sharedWhiteboardProblemImage');
var toolbarEL = $('#sharedWhiteboard-toolbar');
toolbarController = new ToolbarController(WhiteboardConstants.SHARED_WHITEBOARD_ID, toolbarEL, null);
toolbarController.init(false);
whiteboardController = toolbarController.getWhiteboardController();
},
enableWhiteboardEdition : function(enabled)
{
if(self.getWhiteboardObject() && self.getWhiteboardObject.hasOwnProperty('enableEdition')) self.getWhiteboardObject().enableEdition(enabled);
whiteboardController.setEnabled(enabled);
}
};
}
This is the file which I am trying to test and it creates a new instance of the above object
Box.Application.addModule('SharedWhiteboardModule', function(context) {
'use strict';
var self;
var moduleEl;
var domService;
var sharedWhiteboardView;
var modal;
var assignmentTimer = 3000;
var sharing = false;
var assignmentImageData = '';
return {
/**
* Initializes the module and caches the module element
* #returns {void}
*/
init: function() {
self = this;
domService = context.getService('DomService');
moduleEl = context.getElement();
sharedWhiteboardView = new SharedWhiteboardView(moduleEl, domService);
sharedWhiteboardView.initWhiteboard();
sharedWhiteboardView.enableWhiteboardEdition(false);
};
}
I am trying to write a unit test to test that the sharedWhiteboardView.enableWhiteboardEdition method is called with 'false'
However I am failing to attach a spy or stub that method out. I have tried these solutions and they did not work
//First Attempt
sinon.stub(SharedWhiteboardView, "enableWhiteboardEdition", function() {return 0})
// Second Attempt
sinon.stub(SharedWhiteboardView.prototype, "enableWhiteboardEdition").returns(0);
//Third Attempt
sandbox.stub(SharedWhiteboardView.prototype, 'enableWhiteboardEdition', checkEnableWhiteboardEdition());
//Fourth Attempt Trying the answer provided by chrmod
it.only('when type is "SharedWhiteboardModule-setEditable" should call sharedWhiteboardView.enableWhiteboardEdition', function (done) {
const view = SharedWhiteboardView();
sinon.stub(view, "enableWhiteboardEdition", function() {
console.log('Hit');
});
module.onmessage('SharedWhiteboardModule-setEditable', true);
done();
});
No error but it does not hit the console.log, I removed the 'new' keyword as suggested
Errors that I got:
-Attempted to wrap undefined property enableWhiteboardEdition as function
-Cannot stub non-existent own property enableWhiteboardEdition
Please any help would be great. I have reached a dead end here.
Here is a codepen: http://codepen.io/anon/pen/bgmNxx?editors=0011
All I am trying to do is to have the Fake method get hit when my module calls enableEdition
SharedWhiteboardView is not a constructor, it is rather a factory function. Once called (without new) it returns new object that has enableWhiteboardEdition as own property.
Thus a stub has to be set on that object:
const view = SharedWhiteboardView();
sinon.stub(view, "enableWhiteboardEdition", function() {return 0});
This did it.
it('when type is "SharedWhiteboardModule-setEditable" should call setEditable with appropriate callback', function (done) {
var mockSharedWhiteboardView = {
enableWhiteboardEdition: function() {},
initWhiteboard: function() {},
initScrollBar: function() {},
refreshScrollBar: function() {},
isMainWhiteboardAvailable: function() {}
};
sandbox.spy(mockSharedWhiteboardView, 'enableWhiteboardEdition');
var tempGlobals = {
SharedWhiteboardView: global.SharedWhiteboardView
};
global.SharedWhiteboardView = function() {
return mockSharedWhiteboardView;
};
module = Box.Application.getModuleForTest('SharedWhiteboardModule', contextFake);
module.init();
var shouldEnable = true;
module.onmessage('SharedWhiteboardModule-setEditable', shouldEnable);
assert(mockSharedWhiteboardView.enableWhiteboardEdition.calledWithExactly(shouldEnable),
'should enable the whiteboard');
shouldEnable = false;
module.onmessage('SharedWhiteboardModule-setEditable', shouldEnable);
assert(mockSharedWhiteboardView.enableWhiteboardEdition.calledWithExactly(shouldEnable),
'should not enable the whiteboard');
// cleanup
global.SharedWhiteboardView = tempGlobals.SharedWhiteboardView;
done();
});
I am very new to this Angular component communication. I am using Angular 1.5.X version and I am using factory to share data between components. I am facing one issue where Async value of Service Variable refreshes after certain time.
I understand one solution is to set watcher on non scope variable but I think I am missing something important here. Can you guys please share views?
This is Service.js code
Service.$inject = ['$http','$q'];
function Service($http,$q) {
this.$http = $http;
this.$q = $q;
};
Service.prototype.getTileCount = 0;
Service.prototype.getTileData = function(Url){
var deferred = this.$q.defer();
this.$http.get(Url)
.success(function(response){
Service.prototype.getTileCount = response.data.length;
console.log('data length :', Service.prototype.getTileCount);
deferred.resolve(response);
});
return deferred.promise;
};
This is component 1 controller code
function Component1Controller(Service) {
this.tileData ={};
var self = this;
var promise = Service.getTileData(this.sourceUrl);
promise.then(function(data) {
self.tileData = data;
Service.getTileCount = data.length;
console.log('This is tileData : '+ Service.getTileCount);
});
};
This is component 2 controller code
function Component2Controller(Service) {
var self = this;
console.log(Service.getTileCount);
// getting getTileCount = 0; After setting timeout function of 5 second I am able to get getTileCount value
};
The thing is that Service.getTileCount is updated asynchronously, that's why it's 0 at first and then at some point it changes. I would recommend you to simplify your service and always work with getTileData method, which would be a single source of data. The implementation would also become simpler:
function Service($http, $q) {
this._tileData = null;
this.$http = $http;
this.$q = $q;
}
Service.prototype.getTileData = function(Url) {
if (!this._tileData) {
this._tileData = this.$http.get(Url).then(function(response) {
return response.data;
}.bind(this));
}
return this._tileData;
};
Note, how it caches tiles response in "private" _tileData property. Now you can always rely on getTileData method which will return data no matter when you call it:
function Component1Controller(Service) {
this.tileData = {};
var self = this;
Service.getTileData(this.sourceUrl).then(function(data) {
self.tileData = data;
console.log('This is tileData:', self.tileData.length);
});
};
function Component2Controller(Service) {
var self = this;
Service.getTileData(this.sourceUrl).then(function(data) {
console.log('tile count', data.length);
});
};
In this case Service.getTileCount is not needed anymore.
Demo: http://plnkr.co/edit/3zE6VL4emXaLRx2nCRih?p=info
Can I get a little advice on my js modules? I'm good with js, but not quite guru status :) Am I refactoring my modules right?
I've been using the js module pattern like this (rough example, I'm just worried about the structure):
sloppy way?
/* Module Code */
var MapModule = (function ($) {
var $_address;
var $_mapContainer;
function loadApi() {
// do something. maybe load an API?
}
function someInternalMethod() {
// do other things
}
var pub = {};
pub.setAddress = function (address) {
$_address = address;
};
pub.getAddress = function () {
return $_address;
};
pub.initialize = function () {
loadApi();
}
})(jQuery);
// usage
MapModule.initialize();
But that usage seems a little sloppy. I like constructors.
I refactored some modules like this:
Better way?
(function ($) {
this.MapModule = function () {
var $_address;
var $_mapSelector;
var $_mapContainer;
function loadApi() {
// do something. maybe load an API?
}
function someInternalMethod() {
$_mapContainer = $($_mapSelector);
// do stuff with the jQ object.
}
var pub = {};
pub.setAddress = function (address) {
$_address = address;
};
pub.getAddress = function () {
return $_address;
};
pub.initialize = function (selector) {
$_mapSelector = selector;
loadApi();
}
}
})(jQuery);
var map = new MapModule();
map.initialize('#mapcontainer');
That usage seems a lot cleaner to me, and it works just fine, but am I going about it properly?
Taking it another step
Say this module does some stuff with a div that wraps Google Maps and jQuery functionality: Any tips on turning that into a jQ plugin so I can use it with a signature like var map = $('mapcontainer').mapModule();
Thanks!
I have modified your snippet and have actually implemented javascript revealing module pattern which gives the opportunity to implement public & private functions using closure.
Hope this will be helpful:
/* Module Code */
var MapModule = (function (module, $, global) {
var $_address;
var $_mapContainer;
// Public functions
function _loadApi() {
// Do something, maybe load an API?
}
function _someInternalMethod() {
// Do other things.
}
function _initialize = function () {
_loadApi();
}
// Private functions
function _setAddress = function (address) {
$_address = address;
};
function _getAddress = function () {
return $_address;
};
$.extend(module, {
loadApi: _loadApi,
someInternalMethod: _someInternalMethod,
initialize: _initialize
});
return module;
})(MapModule || {},this.jQuery, this);
// Usage
MapModule.initialize();
JSFiddle
Just came across this and thought I'd share my approach...
///////////////////////////////
// Module Code
///////////////////////////////
var ExampleModule = (function()
{
////////////////////////////
// Private Properties
////////////////////////////
var whatever = {
data: 'somedata';
};
////////////////////////////
// Private functions
////////////////////////////
function _init()
{
_loadApi();
_bindToUIEvents();
}
function _loadApi()
{
// load an api
}
function _bindToUIEvents()
{
$('#something').on('click', function(){
// Do something cool
});
}
function _getWhatever()
{
return whatever;
}
//////////////////////
// Public API
//////////////////////
return{
init: _init(),
getWhatever: function()
{
return _getWhatever();
}
};
})();
// Usage
ExampleModule.init;
I am learning how to use jsMockito to write perfect code. So, could you give me any idea on how to run callback which is provided to service?
Here is my class:
function MyClass(service) {
this.service = service;
}
MyClass.prototype.doSomething = function() {
this.service.doIt(function() {
console.log("How to run this function while running tests?");
})
}
And here is my test:
var MyClassTest = TestCase("MyClassTest");
MyClassTest.prototype.testMyClass = function() {
this.service = mock(Service);
this.myClass = new MyClass(this.service);
this.myClass.doSomething();
}
So, I need to see the log message:
"How to run this function while running tests?"
Any ideas are welcome.
Finally I have found the solution.
We need to create doItCallback:
function MyClass(service) {
this.service = service;
}
MyClass.prototype.doItCallback = function() {
console.log("How to run this function while running tests?");
}
MyClass.prototype.doSomething = function() {
this.service.doIt(this.doItCallback);
}
Also we need to update the mock:
var MyClassTest = TestCase("MyClassTest");
MyClassTest.prototype.testMyClass = function() {
this.service = mock(Service);
this.myClass = new MyClass(this.service);
var myClass = this.myClass;
when(this.service).doIt().then(function() {
myClass.doItCallback();
});
this.myClass.doSomething();
}