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);
Related
My web project serves static web pages and scripts. There is no preprocessing done at all. All changes are done in the client.
It has a main page that lists some other pages. When the user clicks a link, jQuery-UI will load the associated HTML page and any linked Javascript/CSS files.
This works great, and gives us flexibility to add/remove new pages with ease. The problem is when we want to debug the loaded JS and the browser appears not to know about it.
Took me a while to find out about Source Maps, and then find out they are all geared towards framework projects like Angular and React.
We don't want that in this project. Just basic HTML & JS that we can plug in and reload. I realize we may need to run an external command to generate the source maps, but it must be a free standing tool - no NPM or frameworks.
It's an internal web project, so security/privacy is not a concern. We want the clients to see the source code if they need to.
I know there are a lot of Questions about JS source maps, but every single one that I've found assumes using some framework tools. We have no framework and do not want one in this project.
Any suggestions on how we can generate the source maps we need, or do you know of any alternative to debug simple JS loaded via jQuery?
First and foremost, you do not need to use Angular/React for sourcemaps to work. These are just a common use case.
Secondly, NPM is exactly what it says it is; a package manager. So you don't need NPM either.
What you need is a build process. You're quite clear that you don't want to minify the js, but you do want sourcemaps. This is a common configuration used to debug js, and is typically accomplished by "building" or "Uglifying" the code with all of the optimizations disabled.
You could likely avoid NPM entirely if you were willing to use the Closure Compiler, but that is a can of worms and I'd suggest you avoid.
Instead I suggest using installing Uglify* globally* (per dev machine) with NPM. This is a "once per machine" step.
npm install uglify-js -g
*: Hopefully this side steps your NPM-less requirement. I did experiment with cloning the Uglify repo directly, but even then you'd need to get it running, and to do that, at a minimum, you'd want to install its dependencies with NPM). I'd love to be proven wrong about this, but I figured it was very unrelated to this post.
And then writing a build script using that. I've attempted to gather the parts for you here:
File: gen-map.sh
#!/usr/bin/env bash
uglifyjs file1.js --config-file gen-map.json \
-o file1.min.js \
--source-map "root='http://foo.com/src',url='file1.min.js.map'"
cat file1.min.js
File: gen-map.json
{
"compress": false,
"output": {
"beautify": true
},
"sourceMap": {
"content": "content from file1.js.map",
"url": "file1.js.map"
}
}
File: file1.js
var b = function() {
console.log('b');
};
function c() {
console.log('c');
};
console.log('a');
b();
c();
(function() {
console.log('d');
})();
File: file1.min.js
var b = function() {
console.log("b");
};
function c() {
console.log("c");
}
console.log("a");
b();
c();
(function() {
console.log("d");
})();
//# sourceMappingURL=file1.min.js.map
File: file1.min.js.map
{"version":3,"sources":["file1.js"],"names":["b","console","log","c"],"mappings":"AAAA,IAAIA,IAAI;IACNC,QAAQC,IAAI;;;AAGd,SAASC;IACPF,QAAQC,IAAI;;;AAGdD,QAAQC,IAAI;;AACZF;;AACAG;;CACA;IACEF,QAAQC,IAAI;EADd","sourceRoot":"http://foo.com/src"}
*: Uglify-es if you're using ES6 features.
After that the only thing left to do would be to update the paths, filenames, and actual script tags. Using this config you must still serve the min.js file, although it seems possible that manually tagging your JS file to point to the map might work...
With this config, you'll need to keep your built files up to date by running:
🐚 ./gen-map.sh
Doing this with npm and gulp would be simpler, but, if you don't mind another package, there are 2 generic "files been changed watchers" that I can suggest;
Nodemon:
🐚 nodemon gen-map.sh
entr
🐚 entr gen-map.sh
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
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
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. :-)
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));