Jasmine-node and sails.js (0.10.0-rc8) - sails.js

When I try to run something as simple as this, I get an error: 'static() root path required'.
If only one 'it' is run, it will pass.
Anyone knows what's the catch?
var Sails = require('sails');
describe("Crud tests:", function() {
var app;
beforeEach(function(done) {
// Lift Sails and start the server
Sails.lift({
log: {
level: 'error'
},
}, function(err, sails) {
console.log("sails lifted");
app = sails;
done(err, sails);
});
});
afterEach(function(done) {
Sails.lower(done);
console.log('sails down');
});
it("1", function(done) {
expect(1).toEqual(1);
done();
});
it("2", function (done) {
expect(2).toEqual(2);
done();
});
});

See https://github.com/balderdashy/sails/issues/1860, quoted below:
Looking at the core tests, even in the ones where we lift / lower for
each individual test, it's always with a fresh instance of Sails. I
don't think a lot of testing has gone into lowering / re-lifting the
same instance, and I wouldn't be shocked to find out that some globals
are hanging around that screw up the lift sequence. So unless there's
a reason why you need it to be the same Sails, rather than a new Sails
with the same options, I'd follow the example of the core tests and
create a fresh instance. To do so, you require the Sails factory,
instead of the full Sails module:
var Sails = require('Sails/lib/app')
var sailsInstance = new Sails();
sailsInstance.lift(...);

I think that the sails v0.10 should be lifted differently. The code bellow is from my project which runs on rc9.
# test/support/sails.coffee
process.env.NODE_ENV = 'test'
process.env.PORT = 1338
Sails = require('sails/lib/app')
app = Sails()
beforeEach (done) ->
app.lift
models:
migrate: 'drop' # rebuild database (optional)
, done
afterEach (done) ->
app.lower done
describe ...
I hope it helps.

Related

reference sails config outside module.exports

How can I use sails.config outside the module.exports? I'm trying to pass sails.config variables to another object, something like below;
var foo = new Foo(sails.config.myconf.myVar);
module.exports {
bar : function(){
// Use foo here
foo.blah();
}
};
(Same question also asked in a comment in this Create config variables in sails.js? See #jreptak comment)
Each files of Sails config is a module then if you want to use it, you just have to import it.
Here is an example to import Sails connections of sails.config.connections module.
Be careful about the path of the module in the require, it must be relative.
var connections = require('../../config/connections');
This was not possible in Sails v0.9. However, this is now possible in Sails v0.10 onwards.
Here's the specific issue on github: https://github.com/balderdashy/sails/issues/1672
So now you can do something like this:
//MyService.js
var client = new Client(sails.config.client);
module.exports = {
myMethod: function(callback){
client.doSomething();
}
}
If you're stuck with Sails v0.9, I would recommend that you follow the workaround specified in the github issue:
//MyService.js
var client;
module.exports = function(){
client = client || new Client(sails.config.client);
return {
myMethod: function(){
client.doSomething();
}
}
}
Which can be used like so:
//SomeController.js
module.exports = {
list: function(req,res){
MyService().myMethod();
}
}
You can't do this, if you want to access sails.config params you have to create a custom hook http://sailsjs.org/documentation/concepts/extending-sails/hooks and do your 'magic' in it

Meteor onRendered function and access to Collections

When user refresh a certain page, I want to set some initial values from the mongoDB database.
I tried using the onRendered method, which in the documentation states will run when the template that it is run on is inserted into the DOM. However, the database is not available at that instance?
When I try to access the database from the function:
Template.scienceMC.onRendered(function() {
var currentRad = radiationCollection.find().fetch()[0].rad;
}
I get the following error messages:
Exception from Tracker afterFlush function:
TypeError: Cannot read property 'rad' of undefined
However, when I run the line radiationCollection.find().fetch()[0].rad; in the console I can access the value?
How can I make sure that the copy of the mongoDB is available?
The best way for me was to use the waitOn function in the router. Thanks to #David Weldon for the tip.
Router.route('/templateName', {
waitOn: function () {
return Meteor.subscribe('collectionName');
},
action: function () {
// render all templates and regions for this route
this.render();
}
});
You need to setup a proper publication (it seems you did) and subscribe in the route parameters. If you want to make sure that you effectively have your data in the onRendered function, you need to add an extra step.
Here is an example of how to make it in your route definition:
this.templateController = RouteController.extend({
template: "YourTemplate",
action: function() {
if(this.isReady()) { this.render(); } else { this.render("yourTemplate"); this.render("loading");}
/*ACTION_FUNCTION*/
},
isReady: function() {
var subs = [
Meteor.subscribe("yoursubscription1"),
Meteor.subscribe("yoursubscription2")
];
var ready = true;
_.each(subs, function(sub) {
if(!sub.ready())
ready = false;
});
return ready;
},
data: function() {
return {
params: this.params || {}, //if you have params
yourData: radiationCollection.find()
};
}
});
In this example you get,in the onRendered function, your data both using this.data.yourData or radiationCollection.find()
EDIT: as #David Weldon stated in comment, you could also use an easier alternative: waitOn
I can't see your collection, so I can't guarantee that rad is a key in your collection, that said I believe your problem is that you collection isn't available yet. As #David Weldon says, you need to guard or wait on your subscription to be available (remember it has to load).
What I do in ironrouter is this:
data:function(){
var currentRad = radiationCollection.find().fetch()[0].rad;
if (typeof currentRad != 'undefined') {
// if typeof currentRad is not undefined
return currentRad;
}
}

Is there a way to create and run a dynamic script from karma.conf.js

I'm using karma to run tests on an angularjs application.
There are a couple JavaScript functions that I would like to run at start-up, but they need to be dynamically created based on some system data. When running the app, this is handled with node.
Is there any way to create a script as a var and pass it to the files: [] rather than just using a pattern to load an existing file?
I can make this work by creating the file, saving it to disk then loading it normally, but that's messy.
You can create your own karma preprocessor script.
For a starting point use the following as example:
var fs = require('fs'),
path = require('path');
var createCustomPreprocessor = function (config, helper, logger) {
var log = logger.create('custom'),
// get here the configuration set in the karma.conf.js file
customConfig = config.customConfig || {};
// read more config here in case needed
...
// a preprocessor has to return a function that when completed will call
// the done callback with the preprocessed content
return function (content, file, done) {
log.debug('custom: processing "%s"\n', file.originalPath);
// your crazy code here
fs.writeFile(path.join(outputDirectory, name), ... , function (err) {
if (err) {
log.error(err);
}
done(content);
});
}
};
createCustomPreprocessor.$inject = ['config', 'helper', 'logger'];
module.exports = {
'preprocessor:custom': ['factory', createCustomPreprocessor]
};
Add a package.json with the dependencies and serve it as a module. ;)
For more examples have a look to more modules here: https://www.npmjs.org/search?q=karma%20preprocessor

require.js synchronous loading

I'd like to define a module which computes a new dependancy, fetches it and then returns the result. Like so:
define(['defaults', 'get_config_name'], function(defaults, get_config_name) {
var name = get_config_name();
var config;
require.synchronous([configs / '+name'], function(a) {
config = defaults.extend(a);
});
return config;
});
Is there a way to do this or a better way to attack this problem?
You may try to use synchronous RequireJS call require('configs/'+get_config_name()), but it will load a module synchronously only if it is already loaded, otherwise it will throw an exception. Loading module/JavaScript file synchronously is technically impossible.
UPD: It's possible (see Henrique's answer) but highly unrecommended. It blocks JavaScript execution that causes to freezing of the entire page. So, RequireJS doesn't support it.
From your use case it seems that you don't need synchronous RequireJS, you need to return result asynchronously.
AMD pattern allows to define dependencies and load them asynchronously, but module's factory function must return result synchronously. The solution may be in using loader plugin (details here and here):
// config_loader.js
define(['defaults', 'get_config_name'], function(defaults, get_config_name) {
return {
load: function (resourceId, require, load) {
var config_name = 'configs/' + get_config_name();
require([config_name], function(config) {
load(defaults.extend(config));
})
}
}
});
// application.js
define(['config_loader!'], function(config) {
// code using config
});
If get_config_name() contains simple logic and doesn't depend on another modules, the better and simpler is calculating on the fly paths configuration option, or in case your config depends on context - map configuration option.
function get_config_name() {
// do something
}
require.config({
paths: {
'config': 'configs/' + get_config_name()
}
});
require(['application', 'defaults', 'config'], function(application, defaults, config) {
config = defaults.extend(config);
application.start(config);
});
Loading JavaScript synchronously is NOT technically impossible.
function loadJS(file){
var js = $.ajax({ type: "GET", url: file, async: false }).responseText; //No need to append
}
console.log('Test is loading...');
loadJS('test.js');
console.log('Test was loaded:', window.loadedModule); //loadedModule come from test.js

How to keep DRY when using node-mongodb-native

db.open(function(err,db){
//handle error
db.collection("book",function(err, collection){
//handle error
collection.doSomething1(... function(err, result){
//handle error
collection.doSomething2(... function(err, result){
...
})
})
})
})
but we wont wrote db.open every time when we want do something, but we must make sure that db has opened when we use it.
we still wont like handle error every time in the same code.
we can also reuse the collection.
just like this
errorHandledDB.doSomething1("book",... function(result){
errorHandledDB.doSomething2("book",...function(result){
...
})
})
I implemented a server-application using mongodb for logging. I implemented data access using some provider classes, as shown in the example.
provider.filelog.js
var Db= require('mongodb/db').Db,
ObjectID= require('mongodb/bson/bson').ObjectID,
Server= require('mongodb/connection').Server,
log = require('lib/common').log;
FilelogProvider = function (host, port, database) {
this.db= new Db(database, new Server(host, port, {auto_reconnect: true}, {}));
this.db.open(function(){});
};
FilelogProvider.prototype.getCollection= function(callback) {
this.db.collection('filelogs', function(error, log_collection) {
if (error) callback(error);
else {
log_collection.ensureIndex([[ 'created', 1 ]], false, function(err, indexName) {
if (error) callback(error);
callback(null, log_collection);
});
}
});
};
FilelogProvider.prototype.findAll = function(callback) {
this.getCollection(function(error, log_collection) {
if (error) callback(error);
else {
log_collection.find(function(error, cursor) {
if (error) callback(error);
else {
cursor.toArray(function(error, results) {
if (error) callback(error);
else callback(null, results);
});
}
});
}
});
};
Since i use Grasshopper as my http-middleware, i can easily inject the providers using the DI functionality provided by gh:
server.js
gh.addToContext({
providers: {
filelog: new FilelogProvider(conf.mongodb_host, conf.mongodb_port, conf.mongodb_database),
status: new ServerstatusProvider(conf.mongodb_host, conf.mongodb_port, conf.mongodb_database)
},
log: log
});
Accessing the providers in every controller function is now a breeze:
gh.get('/serve', function() {
this.providers.filelog.findAll(function(err, res) {
// access data here
});
});
This implementation is pretty specific to Grasshopper (as it's using DI) but i think you'll get the idea. I also implemented a solution using express and mongoose, you find it here. This solution is a bit cleaner than using the native driver, as it exposes models to use against the database.
Update
Just for the sake of it: if you really want to stick to the DRY-principle, stop tinkering on an ORM implementation yourself and use Mongoose. If you need special functionality like Map/Reduce, you still can use the native driver (on which Mongoose is built).
Answer my own question. Because there is no more good options, I do it myself, I start a project to simplify it, check node-mongoskin.
I'm talking theoretically here, with no regards to mongo.
I would recommend you to try building a wrapping of a kind.
A Data access layer or at least models, it all depends on your architecture and needs,
and that's on your side.
Just wrap the access to mongodb with a layer of abstract commands, than write an abstract model object and all other model objects will inherit from it, and will automatically set all getters and setters for the attributes of the record you pulled from the mongo db.
for updating you just give it a save method, that iterates and saves all the changes made to it.
Since it's not a relational and I don't know if this is well suited for your design, the model may not be useful here.
Hope this helps, Good luck!