Assuming x is an external library and Thing is an object that can be constructed from x. This is all wrapped in an Angular service, like so:
app.service('thingService', function() {
var thing;
this.createThing = function(thingParam){
thing = new x.Thing(thingParam);
}
});
My initial attempt included this:
xSpy = jasmine.createSpyObj('x', ['Thing']);
spyOn(window, 'x').andReturn('xSpy');
But it still complains that x() method does not exist on that line that Thing should be constructed
Your attempt
xSpy = jasmine.createSpyObj('x', ['Thing']);
spyOn(window, 'x').andReturn('xSpy');
is wrong:
spyOn() replaces methods with spies, since x is an object this won't work. This is why you get the exception x() method does not exist.
Assuming your example you can just replace the attribute:
describe("Test", function() {
var origThing;
beforeEach(function() {
// create spy object for Thing that provides its methods
var mockedThingInterface = jasmine.createSpyObj('Thing', ['methodA', 'methodB']);
mockedThingInterface.methodA.and.returnValue(1);
mockedThingInterface.methodB.and.returnValue(2);
// remember original constructor
origThing = x.Thing;
// replace the constructor
x.Thing = function() {
return mockedThingInterface;
}
});
afterEach(function() {
// restore when finished
x.Thing = origThing;
});
it("should ...", function() {
// ...
});
});
Related
I have a javascript class called "LayoutProcessor".js ,defined as follow:
define('layoutProcessor', ['jquery'], function($) {
"use strict";
function LayoutProcessor() {
return (this);
}
LayoutProcessor.prototype.process = function() {
console.log('inside process');
};
LayoutProcessor.prototype.responseHandler = function() {
console.log('inside responseHandler');
};
return new LayoutProcessor();
});
I am trying to access the method "process" in another javascript class called "test.js", which is defined as follow:
test.js
require(['LayoutProcessor.js','jquery'], function(layoutProcessor,$) {
$(document).ready(function(){
var response = new LayoutProcessor().process();
});
})
But I am getting a type error:
new LayoutProcessor() is not a constructor.
As per the implementation by OP, it should be
var response = layoutProcessor.process();
not
var response = new LayoutProcessor().process();
Please refer the fiddle
The error message is appropriate, as its not a constructor but an object.
new LayoutProcessor() is not a constructor.
LayoutProcessor.js returns an Object.
return new LayoutProcessor();
There are few things going on with those code.
The way it is current written, LayoutProcessor module returns a constructed object, not a constructor to call.
To call it you would use:
var response = layoutProcessor.process();
However, this makes a singleton, which I doubt is what you mean.
In a singleton, there will only be one instance if layoutProcessor, since that instance is created by the LayoutProcessor module.
I believe the code that you mean would be more like this, where you create a new instance of the object for everyone that needs it:
layoutProcessor
define('layoutProcessor', ['jquery'],
function($) {
"use strict";
//----------------------------------------
/**
* constructor
*/
function LayoutProcessor() {
return (this);
}
LayoutProcessor.prototype.process = function() {
console.log('inside process');
};
LayoutProcessor.prototype.responseHandler = function() {
console.log('inside responseHandler');
};
// Note: Return a FUNCTION reference to be called later.
return LayoutProcessor;
}
);
test.js
require(['LayoutProcessor.js', 'jquery'],
function(LocalLayoutProcessor, $) {
$(document).ready(function() {
var response = new LocalLayoutProcessor().process();
});
}
)
Only issue is return statement. it should be
return LayoutProcessor;
I have this class definition:
$.note = function() {}
$.note.prototype = {
init: function(note) {
this.note = note;
this.ctrl = document.getElementById(note);
},
// I have these getter functions because I was getting errors using
// myObject.note or myObject.ctrl
getNote: function() {
return this.note;
},
getCtrl: function() {
return this.ctrl;
}
}
I created a new object with this class like this:
var note = new $.note('C');
Which I can access in my console like this:
But when I try and access note.getNote(), I get undefined as the response:
Am I going about accessing these properties incorrectly? I've tried using just note.note or note.ctrl, and I get the same thing...
Nothing's going to call that "init" function if you don't.
$.note = function(note) { this.init(note); }
Some frameworks provide an object system that uses constructor helper functions like that, but plain JavaScript doesn't.
Try this:
$.note = function(note) { this.note = note;}
or you should call init function:
var note = new $.note();
note.init('C');
Problem
I have the following javascript file I want to test:
function myLocalHouse() {
this.init = function() {
$.post(//Ajax call using jQuery);
};
this.buyHouse(money, date) {
//code I want to test with mocha
};
this.init();
};
As you can see, the init method uses jQuery, and when I execute mocha in a console, to test it, fails as it doesn't find the $ object.
So my solution was to override and fake the init method. The problem is that my attemps to do that have failed miserably. So sad.
What I have tried
This is my test that tries to test myLocalHouse and my three attemps to override the init method to use an empty function instead.
var myLocalHouse = require('./myLocalHouse.js').myLocalHouse;
suite('houses suite', function() {
test('test that buy House works correctly', function() {
//First attemp at overriding init method: FAILED
myLocalHouse.prototype.init = function() {};
//Second attemp at overriding init method: FAILED
myLocalHouse.__proto__.init = function() {};
var myLocalHouseInstance = new myLocalHouse();
//Third attemp at overriding init method: FAILED
myLocalHouseInstance.prototype.init = function() {};
var something = myLocalHouseInstance.buyHouse(100, '17/08/2013');
});
});
I just...I don't know how to overriding the init method.
I'm doing something wrong? Is there another way to do the same thing?
If you don't want to modify anything at all in the legacy code, the following method can be used:
function myTestHouse() {
Object.defineProperty(this, 'init', {
set: function() { /* Ignore setter */ },
get: function() { return function() { /* dummy*/}; },
enumerable: true
});
var _this = myLocalHouse.apply(this, arguments);
return _this || this;
};
myTestHouse.prototype = myLocalHouse.prototype;
// Usage
var myLocalHouseInstance = new myTestHouse();
Using Object.defineProperty, I define a read-only method that silently ignores setters. After that, I call the original constructor (myLocalTestHouse) using apply.
Note: This method is fully transparent. The created instance behaves as if you were invoking the original constructor.
current broken code: http://jsfiddle.net/9F52n/2/
What I'm trying to do: Learn how to define an object/function that behaves like a class, and be able to define subclasses, both static , and instantiatable (singleton in my example below).
Currently, my code below doesn't work all that well. but, if the instantiatable class sand the static class were removed, you'll see that I have the very basics of class creation down.
So, I guess my question is: what is the proper / most semantic way to define nested clases (singleton or otherwise) with the way I've defined TBR? (function(){...})(window)
var TBR = (function() {
// define local copy of taco bell run
var TBR = function() {
return new TBR.fn.init();
},
message = "hello world!";
TBR.fn = TBR.prototype = {
constructor: TBR,
init: function() {
console.log("From TBR Constructor: " + message);
}
}
var InstantiatableClass = function() {
return new TBR.InstantiatableClass, fn.init();
}
InstantiatableClass.fn =InstantiatableClass.prototype = {
constructor: TBR.InstantiatableClass,
init: function() {
console.log("from InstantiatableClass: " + message);
}
}
this.staticClass = function() {
var subMessage = "little world";
init = function() {
console.log("from staticClass: " + subMessage);
}
}
// expose TBR to the window object
window.TBR = TBR;
})(window);
var InstantiatableClass = function() {
return new TBR.InstantiatableClass, fn.init();
}
InstantiatableClass.fn =InstantiatableClass.prototype ...
This does not work. Your InstantiatableClass local variable returns objects, the prototype will not get applied to them. Also, TBR.InstantiatableClass is defined nowhere. If that is what you wanted, you'd need to use
function InstantiatableClass() {
// common constructor things
}
TBR.InstantiatableClass = InstantiatableClass; // assign a "static" property
Also, you should not [need to] overwrite the prototypes. Sure, the only difference is that constructor is enumerable now (as far as it is not forgotten), but the following would be much cleaner:
InstantiatableClass.fn = InstantiatableClass.prototype; // shortcut
InstantiatableClass.fn.init = function() { … };
Oh, you want something that works like jQuery. Imho you should not make the constructor (init) a property of the prototype - that is just very odd and I can't see a reason to do so. I'd suggest this code:
window.TBR = (function() {
function TbrConstructor() {
…
}
function InstantiableConstructor() {
…
}
// Now, the creator functions:
function TBR() { return new TbrConstructor; }
function Instantiable() { return new InstantiableConstructor; }
// Now, overwrite the "prototype" properties - this is needed for
// (new TbrConstructor) instanceof TBR === true
// and also create those fn shortcuts
TBR.fn = TBR.prototype = TbrConstructor.prototype;
Instantiable.fn = Instantiable.prototype = InstantiableConstructor.prototype;
// we might overwrite the "constructor" properties like
TBR.fn.constructor = TBR;
// but I don't see much sense in that - they also have no semantic value
// At last, make Instantiable a property on the TBR function object:
TBR.Instantiable = Instantiable;
// and then only
return TBR;
})();
// Usage
TBR(); // returns a TbrConstructor instance
TBR.Instantiable(); // returns a InstantiableConstructor instance
i have seen in a framework (came across it once, and never again) where the developer defines a module like this:
core.module.define('module_name',function(){
//module tasks up here
this.init = function(){
//stuff done when module is initialized
}
});
since i never saw the framework again, i tried to build my own version of it and copying most of it's aspects - especially how the code looked like. i tried to do it, but i can't seem to call the module's init() because the callback is still a function and not an object. that's why i added return this
//my version
mycore.module.define('module_name',function(){
//module tasks up here
this.init = function(){
//stuff done when module is initialized
}
//i don't remember seeing this:
return this;
});
in mycore, i call the module this way (with the return this in the module definition):
var moduleDefinition = modules[moduleName].definition; //the callback
var module = moduleDefinition();
module.init();
how do i turn the callback function into an object but preserve the way it is defined (without the return this in the definition of the callback)?
you have to use:
var module = new moduleDefinition();
and then you're going to get an object.
Oh, and maybe you want to declare init as this:
this.init = function() {
Cheers.
How about something like this (I can only assume what mycore looks like):
mycore = {
module: {
definitions: {},
define: function(name, Module) {
this.definitions[name] = new Module();
this.definitions[name].init();
}
}
};
mycore.module.define('module_name', function () {
// module tasks up here
this.init = function () {
// init tasks here
console.log('init has been called');
};
});
I don't know what framework you're using or what requirements it places on you, but Javascript alone doesn't require a function to return anything, even a function that defines an object. For example:
function car(color) {
this.myColor = color;
this.getColor = function() {
return this.myColor;
}
//note: no return from this function
}
var redCar = new car('red');
var blueCar = new car('blue');
alert(redCar.getColor()); //alerts "red"
alert(blueCar.getColor()); //alerts "blue"
One more alternative http://jsfiddle.net/pWryb/
function module(core){this.core = core;}
function Core(){
this.module = new module(this);
}
Core.prototype.modules = {};
module.prototype.define = function(name, func){
this.core.modules[name] = new func();
this.core.modules[name].name = name;
this.core.modules[name].init();
// or
return this.core.modules[name];
}
var myCore = new Core();
var myModule = myCore.module.define('messageMaker', function(){
this.init = function(){
console.log("initializing " + this.name);
}
})
myModule.init();