guys. I have some question about how can i use require.js in my project.
I have some module. For example:
obj.js
var MyModule = (function(){
var myObject = function(){
this.options = {
foo: 'foo',
bar: 'bar'
};
};
myObject.prototype.foo = function(){
console.log(this.options.foo);
};
myObject.prototype.bar = function(){
console.log(this.options.bar);
};
return {
getMyObject : function(){
return new myObject();
}
}
})();
I haven't problems with using my object as solid. I appended to obj.js this code:
define(function(){
return MyModule;
})
And use it in my app.js module
requirejs.config({
baseUrl : 'lib',
paths : {
app:'../js/app'
}
});
require(['app/obj'], function(MyModule){
var someObj = MyModule.getMyObject();
someObj.foo();
someObj.bar();
});
It's all ok. But how can i split MyModule to some submodules? For example. In module i have 1 object, its constructor and two its methods. Can i put constructor to file, for example 'mymodule.myobject.js', foo to 'mymodule.myobject.foo.js' and bar to 'mymodule.myobject.bar.js' and use it with require.js? If it's really, how can i do this?
You can use this way. Expect following file structure
- js
-- constructors
--- objectCostructor.js
-- objects
--- objectModule.js
So the objectCostructor.js is:
define(function(){
return myObject = function(){
this.options = {
foo: 'foo',
bar: 'bar'
}
}
})
And objectModule.js
define(['constructors/objectCostructor'], function(Const){
Const.prototype.foo = function(){
console.log(this.options.foo);
};
Const.prototype.bar = function(){
console.log(this.options.bar);
};
return {
getMyObject : function(){
return new Const();
}
}
})
Related
In modules.js I have this code:
module.exports = {
BookingHotel: function() {
this.getId = function(id) {
return "Hello World";
},
this.getAll = function() {
return "Hello World";
}
},
BookingFlight: function() {
this.book = function() {
return "Hello World";
}
},
}
The modules.js file is becoming too large and difficult to maintain.
How do I separate BookingHotel and BookingFlight into separate files and export them like they currently are?
Make separate files for the objects:
BookingHotel.js
BookingFlight.js
Export the objects from their respective files:
BookingHotel.js:
export default var BookingHotel = function() {
this.getId = function(id) {
return "Hello World";
},
this.getAll = function() {
return "Hello World";
}
}
BookingFlight.js:
export default var BookingFlight = function() {
this.book = function() {
return "Hello World";
}
}
Then import them in the modules.js file and add them to the exports object:
modules.js:
import BookingHotel from 'BookingHotel.js';
import BookingFlight from 'BookingFlight.js';
module.exports = {
BookingHotel: BookingHotel,
BookingFlight: BookingFlight
};
Make a separate JavaScript file for each export in modules.js and have each file export one function, then just require each file and re-export the functions like this:
NOTE: The names of the individual files don't matter as long as they're consistent with the filenames used in modules.js.
BookingHotel.js:
module.exports = {
BookingHotel: function() {
// Your code here
}
};
BookingFlight.js:
module.exports = {
BookingFlight: function() {
// Your code here
}
};
modules.js:
// Get the exports from BookingHotel.js
var BookingHotelExports = require("./BookingHotel.js");
// Get the exports from BookingFlight.js
var BookingFlightExports = require("./BookingFlight.js");
// Combine the individual exports from the two required modules into a new exports variable for this module.
module.exports = {
// BookingHotel is a property of the module.exports object from BookingHotel.js.
BookingHotel: BookingHotelExports.BookingHotel,
// Same here, but from BookingFlight.js.
BookingFlight: BookingFlightExports.BookingFlight
};
The thing is that I have a circular dependecy between some Backbone modules so I have to use "exports" as Requirejs scpecifies in its documentation http://requirejs.org/docs/api.html#circular. So the model 'A' will look like this:
define(function(require, exports) {
var B = require('B');
var A = Backbone.Model.extend({
});
exports.model = A;
});
And the collection 'B' like this:
define(function(require, exports) {
var A = require('A');
var B = Backbone.Model.extend({
model: A.model
});
exports.model = B;
});
The problem here is that by the time I have to specify the collection 'B' model property, the model 'A' isn't yet defined. This is the error I'm getting when I try to set the collection with models like this:
B.collection.set([{id: 1}, {id: 2}]);
Uncaught TypeError: 'undefined' is not an object (evaluating 'targetModel.prototype') (http://127.0.0.1:9999/bower_components/backbone/backbone.js:689)
Any ideas on how should I solve this problem?
From the example, it's not clear that B actually depends on A. If it's just a model:collection relationship, it might make sense to remove the dependency of the model on its collection. If it's at all possible to break the circular dependency, I would strongly encourage you to do so.
If the back-reference is truly required, though, one option might be to move the resources into the same module and do a sort of lazy export:
define(function() {
var lazyThings = {
A: null,
B: null
};
lazyThings.A = Backbone.Model.extend({
collection: things.B
});
lazyThings.B = Backbone.Collection.extend({
model: A
});
return lazyThings;
});
Alternatively, you could return lazyThings.B and later access the model from its prototype:
require('b', function (B) {
var A = B.prototype.model; // A
});
Finally, requirejs could be made to work by calling the respective dependencies lazily (i.e., after the modules are resolved):
// B
define(['a'], function (A) {
return function () {
return Backbone.Collection.extend({
model: A()
});
}
});
// A
define(['b'], function (B) {
return function () {
return Backbone.Model.extend({
model: B()
});
}
});
The following works for me, try to make it clear as possible.
You have a model, you have a collection. In order for them to both depend on each other + avoid a circular dependency, you need a 3rd "mediator" dependency. It's convenient in Backbone to have a model and easily lookup what collection it belongs to, and vice versa, but the problem of course is they have a circular dependency.
So before we had:
+model
+collection
__________
= circular
and after:
+model
+collection
+mediator
________
= OK
//collection
define([
'#allModels',
'#BaseCollection',
'#AppDispatcher',
'#allFluxConstants',
'app/js/flux/flux-helpers/collectionUpdater'
],
function (allModels, BaseCollection, AppDispatcher, allFluxConstants, collUpdater) {
var dispatchCallback = function (payload) {
return true;
};
var BaymaxComponentCollection = BaseCollection.extend({
model: allModels['BaymaxComponent'],
collectionName:'baymax-component',
url: '/baymax_component',
batchURL: '/batch/baymax_component',
initialize: function (models, opts) {
this.dispatchToken = AppDispatcher.register(dispatchCallback);
},
// collection is sorted by original insertion order.
comparator: 'order'
});
return new BaymaxComponentCollection();
});
//model
define([
'#BaseModel',
'#ModelCollectionMediator',
'#AppDispatcher'
],
function ( BaseModel, MCM) {
var BaymaxComponent = BaseModel.extend({
idAttribute: 'id',
urlRoot: '/baymax_component',
collectionName: 'baymax-component',
defaults: function () { //prevents copying default attributes to all instances of UserModel
return {}
},
initialize: function (attributes, opts) {
//*** the following line is crucial ***
this.collection = MCM.findCollectionByName(this.collectionName);
},
validate: function (attr) {
return undefined;
}
},
{ //class properties
});
return BaymaxComponent;
});
//mediator
define(function (require) {
return {
findCollectionByName: function (name) {
var allCollections = require('#allCollections');
return allCollections[name];
}
};
});
I am trying to unit test node.js modules, I'd like to know how to export varibles and objects properly? So I can access them in my Unit Test and work on them.
source code:
var someObject = {};
var Array = [189, 347, 497, 632, 750, 900, 995, 1137],
someNumber = 142,
sizeOfArray = Allowance.length;
someObject = {
method1 : function (info) {
//something...
return {
someOtherMethod1: someObject.method1(info) && someObject.method2(info)
someOtherMethod2: someObject.method3(info)
};
},
method2 : function (info) {
//something...
return something2;
}
method3 : function (info) {
//something...
return something3;
}
};
module.exports = someObject;
So by doing:
module.exports = someObject;
I am able to access someObject in a unit test file in mocha, but how can I access the other variables like Array, sizeOfArray, someNumber?
I've tried adding this:
module.exports = {
someObject : someObject,
Array : Array,
someNumber : someNumber,
sizeOfArray : sizeOfArray
};
But my unit test file cannot read it
Edit:
Here is my unit test
var assert = require("assert")
var expect = require("expect.js")
var chai = require("chai")
var sourceCode = require('../src/sourceCode')
describe("Something..", function() {
var Info = {
//some data...
};
describe("Properties", function() {
it("has someObject defined", function() {
expect(someObject).not.to.be.undefined;
});
it("has Array defined", function() {
expect(Array).not.to.be.undefined;
});
it("has someNumber defined", function() {
expect(someNumber).not.to.be.undefined;
});
it("has sizeOfArray defined", function() {
expect(sizeOfArray).not.to.be.undefined;
})
})
describe("Methods", function() {
it("should have method1 defined", function() {
expect(sourceCode.someObject.method1(Info)).not.to.be.undefined;
});
it("should have method2 defined", function() {
expect(sourceCode.someObject.method2(Info)).not.to.be.undefined;
});
})
};
#Augusto
This is what I was talking about for testing Method1
it("should return positive when conditions are met", function() {
var result = sourceCode.someObject.method1(Info);
expect(result).not.to.be.undefined;
expect(result.eligible).not.to.be.undefined;
expect(sourceCode.result.someOtherMethod2).not.to.be.undefined;
expect(sourceCode.result.someOtherMethod1).to.equal(true);
});
I think that the problem is in your unit tests. You are not accessing the properties in the object
var sourceCode = require('../src/sourceCode');
//CODE CODE CODE
expect(Array).not.to.be.undefined;
There you were trying to access the Array variable instead of the sourceCode.Array property. As you were not defining an Array variable you were getting the undefined error message. The correct code would've been:
expect(sourceCode.Array).not.to.be.undefined;
So.. in your unit tests try this:
var assert = require("assert")
var expect = require("expect.js")
var chai = require("chai")
var sourceCode = require('../src/sourceCode')
describe("Something..", function() {
var Info = {
//some data...
};
describe("Properties", function() {
it("has someObject defined", function() {
expect(sourceCode.someObject).not.to.be.undefined;
});
it("has Array defined", function() {
expect(sourceCode.Array).not.to.be.undefined;
});
it("has someNumber defined", function() {
expect(sourceCode.someNumber).not.to.be.undefined;
});
it("has sizeOfArray defined", function() {
expect(sourceCode.sizeOfArray).not.to.be.undefined;
})
})
};
I'd like to know if and how it's possible to save the following config into my modules scope (think of the block below as one module):
var config = null;
var mySingleton = {
init: function(config) {
config = config; // Naming conflict!
},
printConfig: function() {
console.log(config); // Undefined!
}
};
export { mySingleton };
Unfortunately, a naming conflict occurs. I'd need something like module.config = config;.
Note: I'm using the es6-module-transpiler.
No. It's a simple variable, and not a global one (where it would be accessible as a property of the global object), so it just is shadowed and not available "namespaced".
You need to use a different name to resolve conflicts, which should be trivial and will cause no effects outside the module:
var config = null;
var mySingleton = {
init: function(conf) {
config = conf;
},
printConfig: function() {
console.log(config);
}
};
export { mySingleton };
I'm doing some testing with Jasmine, having a strange result when looking for expected params as a result of a Spy.
I'm testing using the toHaveBeenCalledWith() method and looking for something like this:
{
foo: bar,
thing: [1,2,3],
etc: function() { blah; }
}
It gives a fail, but the error message seems to confirm the exact same object is actually being found.
Any reasons why this might be the case?
Equivalent function definitions are not equal. So,
function() { return 'blah'; } == function() { return 'blah'; } // returns false
You have to reference the same function definition when using toHaveBeenCalledWith() for Jasmine to consider it equal to the argument passed to the spied object's method. Are you maybe passing in a new object definition (like the object you included in your question) to toHaveBeenCalledWith()? That will not pass the Jasmine assertion.
Here is the Jasmine spec I ran which illustrates what I said. There is a succeeding example and a failing example:
describe("A spy example", function() {
var baz = {
foo: 'bar',
thing: [1,2,3],
etc: function() { }
};
beforeEach(function() {
spyOn(baz, 'etc');
baz.etc(baz);
});
it("succeeds", function() {
expect(baz.etc).toHaveBeenCalledWith(baz);
});
it("fails", function() {
expect(baz.etc).toHaveBeenCalledWith({
foo: 'bar',
thing: [1,2,3],
etc: function() { }
});
});
});
A possible solution is to use: Custom asymmetric equality tester. Which let's the tester decide how to determine equality.
Example:
describe("A spy example", function() {
var baz = {
foo: 'bar',
thing: [1,2,3],
etc: function() { }
};
beforeEach(function() {
spyOn(baz, 'etc');
baz.etc(baz);
});
it("succeeds", function() {
expect(baz.etc).toHaveBeenCalledWith(baz);
});
var customTester = {
asymmetricMatch: function(actual) {
return actual.foo === 'bar' &&
actual.thing.length === 3 // && ... ( any deep comparison method you wish to use)
}
};
it("succeeds too", function() {
expect(baz.etc).toHaveBeenCalledWith(customTester);
});
});
Hope this helps.