How to define grunt task that is based on other task? - javascript

For example I define my own task named jasmine. It is based on the task server.
If I call grunt server jasmine - it's ok. But I want to declare that dependency inside my task.
grunt.task.run - add task to the queue (after my task).
grunt.task.requires - only check dependency, not run it...
Does any way exist to run server task before my jasmine task?
P.S. I don't want to create jasmine_orig task and then .registerTask('jasmine', 'server jasmine_orig'). It looks like silly.

The way the server task is currently written, no this isn't possible. However, you may be able to do what you want by using the grunt-connect plugin, or rolling your own grunt server task. The source for the built-in one is here:
https://github.com/gruntjs/grunt/blob/0.3-stable/tasks/server.js
As you can see, there isn't much to it, other than reading a config, starting a connect server, and possibly logging when --debug is passed. You could, in fact, copy all of that code into a helper (woefully underdocumented, I'm afraid), and call it from your jasmine task.
It's probably a good idea to start a separate server for your tests (for test independence), but if you needed to save the resources for some reason, or you find multiple servers distasteful in some other way, you'll have to write some custom task code to check if the server is there, and then start the server if it's not.
Probably the best solution is the following:
install the grunt-contrib-connect npm package:
npm install grunt-contrib-connect --save-dev
Make configurations for your dev and test environments:
connect: {
dev: {
base: 'path/to/serve',
port: 8000
},
test: {
base: 'path/to/serve',
port: 8001
}
}
Register a test task that runs grunt server:test jasmine for you.
grunt.registerTask('test', 'server:test jasmine')

One partial solution is to define the steps for specific tasks as variables. Then, you can concatenate them like such:
var buildSteps = [ ... ];
var distDevSteps = [ ... ];
grunt.registerTask('build', buildSteps);
grunt.registerTask('dist_dev', [].concat(buildSteps, distDevSteps));

Related

Sails.js: How to actually run tests

I'm completely new to sails, node and js in general so I might be missing something obvious.
I'm using sails 0.10.5 and node 0.10.33.
In the sails.js documentation there's a page about tests http://sailsjs.org/#/documentation/concepts/Testing, but it doesn't tell me how to actually run them.
I've set up the directories according to that documentation, added a test called test/unit/controllers/RoomController.test.js and now I'd like it to run.
There's no 'sails test' command or anything similar. I also didn't find any signs on how to add a task so tests are always run before a 'sails lift'.
UPDATE-2: After struggling a lil bit with how much it takes to run unit test this way, i decided to create a module to load the models and turn them into globals just as sails does, but without taking so much. Even when you strip out every hook, but the orm-loader depending on the machine, it can easily take a couple seconds WITHOUT ANY TESTS!, and as you add models it gets slower, so i created this module called waterline-loader so you can load just the basics (Its about 10x faster), the module is not stable and needs test, but you are welcome to use it or modify it to suit your needs, or help me out to improve it here -> https://github.com/Zaggen/waterline-loader
UPDATE-1:
I've added the info related to running your tests with mocha to the docs under Running tests section.
Just to expand on what others have said (specially what Alberto Souza said).
You need two steps in order to make mocha work with sails as you want. First, as stated in the sails.js Docs you need to lift the server before running your test, and to do that, you create a file called bootstrap.test.js (It can be called anything you like) in the root path (optional) of your tests (test/bootstrap.test.js) that will be called first by mocha, and then it'll call your test files.
var Sails = require('sails'),
sails;
before(function(done) {
Sails.lift({
// configuration for testing purposes
}, function(err, server) {
sails = server;
if (err) return done(err);
// here you can load fixtures, etc.
done(err, sails);
});
});
after(function(done) {
// here you can clear fixtures, etc.
sails.lower(done);
});
Now in your package.json, on the scripts key, add this line(Ignore the comments)
// package.json ....
scripts": {
// Some config
"test": "mocha test/bootstrap.test.js test/**/*.test.js"
},
// More config
This will load the bootstrap.test.js file, lift your sails server, and then runs all your test that use the format 'testname.test.js', you can change it to '.spec.js' if you prefer.
Now you can use npm test to run your test.
Note that you could do the same thing without modifying your package.json, and typying mocha test/bootstrap.test.js test/**/*.test.js in your command line
PST: For a more detailed configuration of the bootstrap.test.js check Alberto Souza answer or directly check this file in hist github repo
See my test structure in we.js: https://github.com/wejs/we-example/tree/master/test
You can copy and paste in you sails.js app and remove we.js plugin feature in bootstrap.js
And change you package.json to use set correct mocha command in npm test: https://github.com/wejs/we-example/blob/master/package.json#L10
-- edit --
I created a simple sails.js 0.10.x test example, see in: https://github.com/albertosouza/sails-test-example
Given that they don't give special instructions and that they use Mocha, I'd expect that running mocha from the command line while you are in the parent directory of test would work.
Sails uses mocha as a default testing framework.
But Sails do not handle test execution by itself.
So you have to run it manually using mocha command.
But there is an article how to make all Sails stuff included into tests.
http://sailsjs.org/#/documentation/concepts/Testing

How to write unit tests for a grunt plugin that doesn't write files?

I'm creating a grunt plugin which is responsible for finding URLs in a file and adding those URLs to a variable in the grunt file using
grunt.config.set('urls', urls);
All examples of unit test for Grunt plugins assume that the plugin is going to write a file and then compares that output to a test file with the 'expected' result.
Is there any way to test if my Grunt plugin has set a config variable?
Something like this?
urlConfigTest: function(test) {
test.expect(1);
grunt.config.set('urls','http://foo.example.com');
test.equal(grunt.config.get('urls'), 'http://foo.example.com', 'Should set foo to the grunt configuration.');
test.done();
}
The Yo generator (*) for grunt-plugins basically is basically setting up tests like this:
Setup your Gruntconfig.js to run your plugin with a specific testconfig
Then configure a testrun by creating a test task: grunt.registerTask('test', ['myPlugin', 'nodeunit']);. This means that your plugin should have set the config values you like to test against.
Run the test like test.equal(grunt.config.get('urls'), 'http://foo.example.com', 'Should ...');
The Yo generator is maintained by Addy Osmani and Stephen Sawchuck, which might be counted as credible sources ;-)
(*) npm install -g generator-gruntplugin

Grunt autorefresh from node

I used Grunt for three last days, I'm able to use this script from command line:
web-server/Gruntfile.js
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
var concat = require('./config/grunt-concat.json');
var uglify = require('./config/grunt-uglify.json');
// Overload uglify, add target.
uglify.my_target.files[concat.final.dest] = concat.final.src
// Project configuration.
grunt.initConfig({
concat: concat,
uglify: uglify
});
}
What I want to do is:
Config the target file in my config file (json) and not here. But I don't know how reference another config json file from a config json file. (I guess it's not possible from JSON, but it looks like Grunt could be able to do it, so I assume it's possible)
Don't use CLI but automatically run this script on server start. (On the app.js I guess)
Automatically reload the script when some JS files are changed (update/delete/create) to not have to stop and start the node server. (Only for files used in the browser, of course I'll still have to stop/run the server if I change the server files).
I don't know how reach these goals, I assume there are a lot of Grunt modules and some of them could help me but I don't know them. Thank you.
Solution found here:
How run grunt when server start from node?
About the part to refresh it once file is changed I won't do like this, I'll use a supercontroller to see the http request and automatically rebuild the source when page is loaded in the browser, a simple refresh.
Or change my source code and don't use the generated files in development. Probably the better way.

Programmatically controlling Grunt.js

I would like to have access to the many available plugins and tasks in the grunt ecosystem to make my life easier, but I would like control over when and how each task is run. Most importantly, I want a way to run grunt tasks programmatically instead of running grunt from the command line in a folder with a Gruntfile. So I started poking around grunt-cli and grunt for a "way in."
From the source code of GruntJS:
// Expose the task interface. I've never called this manually, and have no idea
// how it will work. But it might.
grunt.tasks = function(tasks, options, done) {
...
As you can see, Mr. Allman cautions us about the interface... my question is, has anyone gotten this to work?
My experiments, so far, have led me to believe the best way to programmatically control grunt is by mimicking the command line call with a child process:
$ npm install grunt-cli //notice no -g flag
// From runner.js
var exec =require('child_process').exec
exec('node_modules/.bin/grunt-cli tasks to run', {
cwd: 'path/to/directory/with/a/gruntfile'
}, function() { /* do stuff here */ });
This seems dirty so I'm thinking about simply writing my own task-runner that exposes an interface for grunt tasks. However, I don't want to dup work if someone has had success with grunt.tasks() despite Mr. Allman's warnings.
The obvious answer seems like it should be write a grunt task to do whatever you want to do :)
Then you can use grunt.task.run() to control other grunt tasks: http://www.gruntjs.org/article/grunt_task.html
You can also update their configs dynamically before running them very easily by messing with grunt.config
There's also this answer which may answer your question:
How can I run a grunt task from within a grunt task?
Also check out grunt.task.start() which is not publicy documented, but it seems to kick off all of the tasks https://github.com/gruntjs/grunt/blob/master/lib/util/task.js#L246 (hat tip: #jibsales)
Maybe this would help you to write a custom handler : https://www.npmjs.com/package/rungrunttask
Usage details
var RunGruntTask = require('rungrunttask').RunGruntTask;
var taskname = 'some grunt task such as backup database every 24hours';
RunGruntTask(taskname);

Grunt-contrib-jasmine aborts task when there is no spec file or spec file is empty

I have been having great fun getting started with Grunt, but have come across a situation where I don't know what the best course of action is.
tl;dr
Can grunt throw a warning without aborting the task? grunt --force will do that, but that applies the force option to all tasks.
Issue: on running a task that includes jasmine (from grunt-contrib-jasmine), if it cannot find a spec with at least one unit test in it (i.e. it("does stuff, function () {});) then it throws a warning and therefore aborts the whole task.
Code
Here is the task I'm using to build up my site:
grunt.registerTask('build', ['clean', 'sass', 'images', 'favicons', 'lint', 'minify', 'jasmine', 'hashify']);
and here is the jasmine task configuration:
jasmine: {
testdev: {
src: folders.js.src + '/**/*.js',
options: {
'specs': folders.spec.src + '/*Spec.js',
'helpers': folders.spec.src + '/*Helper.js'
}
},
//etc etc, more targets for minified code testing and istanbul coverage
}
Are any of these sensible solutions?
Option 1) I can use grunt --force but am reluctant to because it will affect other processes that I might want to genuinely fail the task.
Option 2) Warn but don't fail. Does Grunt have a STDOUT warning that doesn't abort the task?
Option 3) I could fork the plugin and add the option 'force' just to the jasmine task so it continues on, but will still log its warning to the console.
Option 4) Grunt creates an empty dummy spec if one is not found before running jasmine. This seems a bit clunky to me.
There may be an even better solution that I've not yet thought of.
Thanks in advance.
Have a look at Testem. I answered this in another unit testing question, but the nice thing about it is it's like a watch task for your tests; update your code, it runs, something goes wrong, it logs it on the console (and through the browser that you run it through).
Also, because it uses a browser to run the tests through, you can have a tab next to your project's code which will show a count of the tests that pass/fail. i.e. Testem (60/60)
https://github.com/airportyh/testem
If you want to run this as part of your build process as well, there's grunt-testem. Be careful that you quit the testem runner before running this task or it will fail. Hope this helps. :-)

Categories