Gulp tasks working alone but not in watch mode - javascript

I am developing a CLI tool running on node.js. I am trying to setup my environment for tdd but I have difficulties to do it with gulp.
All my 'standalone' tasks from gulp work.
Here they are:
Build task:
var tsProject = ts.createProject({
declarationFiles: true,
noEmitOnError: true,
module: 'commonjs',
target: 'es5',
sortOutput: true,
typescript: require('typescript') //usefull during typescript 1.5 alpha
});
gulp.task('build', function() {
var tsResult = gulp.src([
PATHS.lib + '/**/*.ts'
])
.pipe(sourcemaps.init())
.pipe(ts(tsProject));
return merge([ // Merge the two output streams, so this task is finished when the IO of both operations are done.
tsResult.dts.pipe(gulp.dest(PATHS.build + '/definitions')),
tsResult.js
.pipe(sourcemaps.write())
.pipe(gulp.dest(PATHS.build + '/js'))
]);
});
Test task:
gulp.task('test', ['build'], function () {
return gulp.src(PATHS.test + '/**/*.js', {read: false})
.pipe(mocha({
reporter: 'spec',
globals: {
should: require('should'),
sinon: require('sinon'),
mockery: require('mockery')
}
}))
.on('error', gutil.log);
});
As you can see I have one task which build my typescript files into es5 compatible js. And another task that run my tests with the precedent build.
If I run them alone. It works.
I have tried to add a watch mode:
build:watch:
gulp.task('build:watch', ['build'], function() {
gulp.watch([
PATHS.lib + '/**/*.ts'
], ['build']);
});
test:watch:
gulp.task('test:watch', ['test'], function () {
gulp.watch([
PATHS.lib + '/**/*.ts',
PATHS.test + '/**/*.js'
], ['test']);
});
build:watch works. Every time I edit a typescript file, the build task is triggered and rebuild my project. (It's not really relevant here because the test task trigger build. It's just to say that this watch mode works)
test:watch doesn't work. The first iteration (triggered by the task dependencie) work, but when I edit a typescript file or a test file, I got this error:
{ [TypeError: Cannot read property 'defaultEncoding' of undefined]
domain:
{ domain: null,
_events: { error: [Function: handleException] },
_maxListeners: undefined,
members: [] },
domainThrown: true,
name: 'TypeError',
message: 'Cannot read property \'defaultEncoding\' of undefined',
stack: 'TypeError: Cannot read property \'defaultEncoding\' of undefined\n at DestroyableTransform.Writable.write (/Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:186:21)\n at Glob.<anonymous> (/Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/glob-stream/index.js:44:14)\n at Glob.emit (events.js:107:17)\n at Glob._emitMatch (/Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/glob-stream/node_modules/glob/glob.js:457:8)\n at Glob._processReaddir2 (/Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/glob-stream/node_modules/glob/glob.js:405:12)\n at /Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/glob-stream/node_modules/glob/glob.js:345:17\n at RES (/Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/glob-stream/node_modules/glob/node_modules/inflight/inflight.js:23:14)\n at /Users/thomashourlier/Documents/Work/jsProjects/hawker/node_modules/gulp/node_modules/vinyl-fs/node_modules/glob-stream/node_modules/glob/node_modules/inflight/inflight.js:30:13\n at process._tickDomainCallback (node.js:381:11)',
showStack: true,
showProperties: true,
plugin: 'gulp-mocha' }
And if you want, here the gulp stack :
[10:58:24] Using gulpfile ~/Documents/Work/jsProjects/hawker/gulpfile.js
[10:58:24] Starting 'build'...
[10:58:25] Finished 'build' after 1.01 s
[10:58:25] Starting 'test'...
Hawker
✓ should get the Logger
✓ should get the Parser
✓ should define a file loader
✓ should define a url loader
✓ should launch hawker
FileLoader
✓ should be defined
✓ should get a configuration file
Parser
✓ should be defined
✓ should parse configuration file
9 passing (24ms)
[10:58:26] Finished 'test' after 98 ms
[10:58:26] Starting 'test:watch'...
[10:58:26] Finished 'test:watch' after 14 ms
[10:58:28] Starting 'build'...
[10:58:28] { [TypeError: Cannot read property 'defaultEncoding' of undefined] ...
Do you have any suggestion?

All right, I find the problem.
I use mockery in my unit tests and I forget to disable it after some tests. I just add in my test files :
afterEach(function() {
mockery.disable();
});
Have a good day.
Thomas

Related

Mocha test passes locally, but fails on Travis CI

I am trying to add testing to the website I'm building. I'm using Mocha as my testing framework and Chai and expect as my assertion library. I made a simple test just to make sure things work and then I created a Gruntfile to run my tests. The test is a simple test that just verifies that true === true and it worked both locally and on Travis CI. Now, even though I haven't changed anything in the test, it only works locally, but fails on Travis CI. It was passing before and it still passes locally, so I'm not sure what to change.
My simple test code looks like this:
'use strict';
var chai = require('chai');
var expect = chai.expect;
describe('Test that tests run', function(done) {
it('should run a test', function(done) {
expect(true).to.eql(true);
done();
});
});
My Gruntfile looks like this:
'use strict';
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-simple-mocha');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-jscs');
// initialize Grunt
grunt.initConfig({
// create jshint task
jshint: {
dev: {
// tell jshint what check
src: ['Gruntfile.js', 'server.js', 'js/**/*.js', 'models/**/*.js', 'routes/**/*.js', '!build/**', '!tests/client/bundle.js', '!tests/karma_tests/bundle.js', '!js/imageMapResizer.min.js', '!js/kickstart.js', '!js/form-validator.js'],
options: {
node: true,
globals: {
describe: true,
it: true,
before: true,
after: true,
beforeEach: true,
afterEach: true,
res: true
}
}
},
mocha: {
// tell mocha where test files are
src: ['tests/**/*.js', '!tests/client/bundle.js', '!tests/karma_tests/bundle.js'],
options: {
node: true,
globals: {
describe: true,
it: true,
before: true,
after: true,
beforeEach: true,
afterEach: true,
res: true,
expect: true
}
}
},
// create jscs task
jscs: {
dev: {
// tell jscs to test the same files as jshint
src: ['<%= jshint.dev.src %>', '<%= jshint.mocha.src %>']
}
}
},
// create simplemocha task
simplemocha: {
dev: {
src: ['tests/test_entry.js']
}
}
});
// register linting task
grunt.registerTask('lint', ['jshint:dev', 'jshint:mocha' /*, 'jshint:jasmine'*/ ]);
// register mocha test task
grunt.registerTask('test', ['simplemocha:dev']);
grunt.registerTask('default', ['test']);
};
And .travis.yml looks like this:
language: node_js
node_js:
- "4.1"
- "4.0"
- "0.12"
- "0.11"
- "0.10"
- "0.8"
- "0.6"
- "iojs"
before_install:
- npm install -g grunt-cli
script: grunt test
Let me know if you have questions or want to see more code. Thanks in advance for all your help!
After some more digging with Travis CI I found there were 2 problems. The first was that node.js versions 0.6 and 0.8 were incompatible with many of my node packages. The other problem was 2 node packages I had included were not compatible with linux, which is the OS Travis CI uses to run tests. The packages were node-sqlserver-unofficial and msnodesqlv8.
I don't really need to work on node.js versions 0.6 or 0.8 and the I can work without the 2 node packages, so once I removed the the older node versions and the packages and my tests passed with flying colors.

gulp-sass and gulp-watch, cant find file when saving scss

I am currently setting up my gulpfile and im having a problem with gulp-sass when the watch task is running the scss task.
This is how my gulpfile.js looks:
var gulp = require('gulp'),
plumber = require('gulp-plumber'),
sass = require('gulp-sass'),
sourcemaps = require('gulp-sourcemaps');
var onError = function(err) {
console.log(err);
};
var bases = {
dist: './dist/',
src: './src/'
};
var paths = {
sass: [bases.src + 'scss/base.scss'],
sourcemaps: '/'
};
gulp.task('scss', function(){
return gulp.src(paths.sass)
.pipe(plumber({
errorHandler: onError
}))
.pipe(sourcemaps.init())
.pipe(sass({
sourcemap: true,
style: 'expanded',
sourceComments: 'normal',
onError: onError
}))
.pipe(sourcemaps.write(paths.sourcemaps))
.pipe(gulp.dest(bases.dist + 'css/'))
});
gulp.task('watch', function(){
gulp.watch(bases.src + 'scss/**/*.scss', ['scss'])
});
gulp.task('default', ['scss','watch']);
base.scss only contains this:
(also tried full path and without fileext. same result)
#import 'modules/modules_base.scss';
The error i'm getting in console:
[18:54:13] Finished 'scss' after 12 ms
[18:54:15] Starting 'scss'...
{ [Error: src\scss\base.scss
1:9 file to import not found or unreadable: ./src/scss/modules/modules_base.scss
Current dir: ]
message: 'src\\scss\\base.scss\n 1:9 file to import not found or unreadable: ./src/scss/modules/modules_base.scss\nCurrent dir: ',
column: 9,
line: 1,
file: 'stdin',
status: 1,
messageFormatted: '\u001b[4msrc\\scss\\base.scss\u001b[24m\n\u001b[90m 1:9\u001b[39m file to import not found or unreadable: ./src/scss/modules/modules_base.scss\nCurrent dir: ',
name: 'Error',
stack: 'Error: src\\scss\\base.scss\n 1:9 file to import not found or unreadable: ./src/scss/modules/modules_base.scss\nCurrent dir: \n at options.error (c:\\Code\\colorpicker\\node_modules\\gu
lp-sass\\node_modules\\node-sass\\lib\\index.js:276:32)',
showStack: false,
showProperties: true,
plugin: 'gulp-sass' }
The basic error is: 1:9 File to import not found or unreadable: ./src/scss/modules/modules_base.scss
the structure of the app:
-component
gulpfile.js
-dist
-css
base.css
base.css.map
-src
-scss
base.scss
-modules
-modules_base.scss
The error only happens when i save the modules_base.scss and the watch task is fired, and never when im running the default task.
all suggestions are appreciated!
Notes:
Node -v : 0.12.0
Gulp: 3.8.11
gulp-sass: 2.0.1
Are you using vscode? I found this on github
gulp.task('sass', function () {
return gulp.src(SCSS_SRC)
.pipe(wait(500))
.pipe(sass({
outputStyle: 'compressed',
includePaths: ['./bower_components/susy/sass', './bower_components/breakpoint-sass/stylesheets']
}).on('error', sass.logError))
.pipe(concat('style.css'))
.pipe(autoprefixer({
browsers: ['>1%', 'last 2 versions'],
cascade: false
}))
.pipe(gulp.dest('./dist/css'));
});
Basically
I was having this issue when saving in sublime. The first time the
file changed, gulp watch would fire before the file either completed
saving, or was unreadable when lib-sass started. I added a 50ms delay
to the pipe which seems to work.
Have you tried this?
edit - I use run-sequence to ensure processes finish before running things that require them. Check it out
gulp.task('default',function(callback){
runSequence('clean-folder','css','js'['responsive-jpg','responsive-webp','copy-data']),callback
});
Basically clean-folder runs and deletes stuff I want a redo on, then css compiles. Nothing after will run until run-sequence gets the callback that all of the scss has been transpiled.

load grunt task from another gruntfile

I want to avoid duplicate code, so i am trying to load grunt task from Grunt file "a" and use them in gruntfile "b".
that means: i want to see all task of "a" in file "b" (but without code), just setup like a reference or template to another gruntfile.
here is grunt file "b":
module.exports = function (grunt) {
'use strict';
var karmaGrunt = './../../grunt',
abortHandler = function () {
var errors = grunt.fail.errorcount,
warnings = grunt.fail.warncount;
if (errors > 0 || warnings > 0) {
//run rocketlauncher python script and then stop the grunt runner.
grunt.task.run(["shell:rocketlauncher", "fatal"]);
}
},
fatal = function () {
// this function stops grunt and make the jenkins build red.
grunt.fail.fatal('failed');
};
require("grunt-load-gruntfile")(grunt);
// load grunt task from another file and add it.
grunt.loadGruntfile(karmaGrunt);
//grunt needs to continue on error or warnings, that's why we have to set the force property true
grunt.option('force', true);
grunt.initConfig({
shell: {
options: {
execOptions: {
cwd: '../scripts'
}
},
'rocketlauncher': {
command: './runRocketLauncher.sh'
}
}
});
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('build-process', ['karma', 'abortHandler']);
grunt.registerTask('abortHandler', abortHandler);
grunt.registerTask('fatal', fatal);
}
here is file "a":
module.exports = function (grunt) {
"use strict";
var eConfig = '../e-specs/karma.config.js',
dConfig = '../d-specs/karma.config.js',
cConfig = '../c-specs/karma.config.js';
grunt.initConfig({
karma: {
options: {
reporters: ['progress', 'coverage', 'threshold']
},
c: {
configFile: cConfig
},
d: {
configFile: dConfig
},
e: {
configFile: eConfig
}
}
});
grunt.loadNpmTasks('grunt-karma');
};
my file b load the task "Karma" but if i run only the grunt file of a i have 3 nested task ("e","c","d") but if i load them from another file, the only task i can see is "karma"
the error is:
No "karma" targets found.
Warning: Task "karma" failed. Used --force, continuing.
Done, but with warnings.
If i run the same task in file "a" directly the task is working like a charm.
There is a grunt plugin to load another Gruntfile: grunt-load-gruntfile
With this you can merge two Grunt configurations, including the defined tasks.
Here is an example:
./Gruntfile.js:
module.exports = function (grunt) {
require("grunt-load-gruntfile")(grunt);
grunt.loadGruntfile("web"); //loads the Gruntfile from the folder web/
grunt.registerTask('showConfig', "shows the current config", function(){
console.log(JSON.stringify(grunt.config(), null, 2));
});
};
and the second Gruntfile in ./web/Gruntfile.js.
module.exports = function (grunt) {
grunt.config("WebConfig", "Configuration from the Gruntfile in web/Gruntfile.js");
grunt.registerTask('server', "runs the server",function(){
console.log("just shows this message");
});
};
running grunt showConfig executes the task from the first Gruntfile and displays the configuration, including the parameter defined in ./web/Gruntfile.js.
running grunt server executes the task from ./web/Gruntfile.js.

Grunt Environment Variables Don't Get Set Until All Tasks Loaded

I am using the npm modules grunt env and load-grunt-config in my project. grunt env handles environment variables for you, while load-grunt-config handles, well, loads the grunt configuration for you. You can put your tasks into other files, then load-grunt-config will bundle them up and have grunt load & consume them for you. You can also make an aliases.js file, with tasks you want to combine together into one task, running one after another. It's similar to the grunt.registerTask task in the original Gruntfile.js. I put all my grunt tasks inside a separate grunt/ folder under the root folder with the main Gruntfile, with no extra subfolders, as suggested by the load-grunt-config README.md on Github. Here is my slimmed-down Gruntfile:
module.exports = function(grunt) {
'use strict';
require('time-grunt')(grunt);
// function & property declarations
grunt.initConfig({
pkg: grunt.file.readJSON('package.json')
});
require('load-grunt-config')(grunt, {
init: true,
loadGruntConfig: {
scope: 'devDependencies',
pattern: ['grunt-*', 'time-grunt']
}
});
};
In theory, setting all these files up the correct way for load-grunt-config to load should be exactly the same as just having a Gruntfile.js. However, I seem to have run into a little snag. It seems the environment variables set under the env task do not get set for the subsequent grunt tasks, but are set by the time node processes its tasks, in this case an express server.
grunt env task:
module.exports = {
// environment variable values for developers
// creating/maintaining site
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 27017,
SERVER_PORT: 3000
}
}
}
};
grunt-shell-spawn task:
// shell command tasks
module.exports = {
// starts up MongoDB server/daemon
mongod: {
command: 'mongod --bind_ip konneka.org --port ' + (process.env.MONGO_PORT || 27017) + ' --dbpath C:/MongoDB/data/db --ipv6',
options: {
async: true, // makes this command asynchronous
stdout: false, // does not print to the console
stderr: true, // prints errors to the console
failOnError: true, // fails this task when it encounters errors
execOptions: {
cwd: '.'
}
}
}
};
grunt express task:
module.exports = {
// default options
options: {
hostname: '127.0.0.1', // allow connections from localhost
port: (process.env.SERVER_PORT || 3000), // default port
},
prod: {
options: {
livereload: true, // automatically reload server when express pages change
// serverreload: true, // run forever-running server (do not close when finished)
server: path.resolve(__dirname, '../backend/page.js'), // express server file
bases: 'dist/' // watch files in app folder for changes
}
}
};
aliases.js file (grunt-load-config's way of combining tasks so they run one after the other):
module.exports = {
// starts forever-running server with "production" environment
server: ['env:prod', 'shell:mongod', 'express:prod', 'express-keepalive']
};
part of backend/env/prod.js (environment-specific Express configuration, loaded if NODE_ENV is set to "prod", modeled after MEAN.JS):
'use strict';
module.exports = {
port: process.env.SERVER_PORT || 3001,
dbUrl: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://konneka.org:' + (process.env.MONGO_PORT || 27018) + '/mean'
};
part of backend/env/dev.js (environment-specific Express configuration for dev environment, loaded if the `NODE_ENV variable is not set or is set to "dev"):
module.exports = {
port: process.env.SERVER_PORT || 3000,
dbUrl: 'mongodb://konneka.org:' + (process.env.MONGO_PORT || 27017) + '/mean-dev'
};
part of backend/page.js (my Express configuration page, also modeled after MEAN.JS):
'use strict';
var session = require('express-session');
var mongoStore = require('connect-mongo')(session);
var express = require('express');
var server = express();
...
// create the database object
var monServer = mongoose.connect(environ.dbUrl);
// create a client-server session, using a MongoDB collection/table to store its info
server.use(session({
resave: true,
saveUninitialized: true,
secret: environ.sessionSecret,
store: new mongoStore({
db: monServer.connections[0].db, // specify the database these sessions will be saved into
auto_reconnect: true
})
}));
...
// listen on port related to environment variable
server.listen(process.env.SERVER_PORT || 3000);
module.exports = server;
When I run grunt server, I get:
$ cd /c/repos/konneka/ && grunt server
Running "env:prod" (env) task
Running "shell:mongod" (shell) task
Running "express:prod" (express) task
Running "express-server:prod" (express-server) task
Web server started on port:3000, hostname: 127.0.0.1 [pid: 3996]
Running "express-keepalive" task
Fatal error: failed to connect to [konneka.org:27018]
Execution Time (2014-08-15 18:05:31 UTC)
loading tasks 38.3s █████████████████████████████████ 79%
express-server:prod 8.7s ████████ 18%
express-keepalive 1.2s ██ 2%
Total 48.3s
Now, I can't seem to get the database connected in the first place, but ignore that for now. Notice that the server is started on port 3000, meaning that during execution of the grunt express:prod task, SERVER_PORT is not set so the port gets set to 3000. There are numerous other examples like this, where an environment variable is not set so my app uses the default. However, notice that session tries to connect to the database on port 27018 (and fails), so MONGO_PORT does get set eventually.
If I had just tried the grunt server task, I could chalk it up to load-grunt-config running the tasks in parallel instead of one after the other or some other error, but even when I try the tasks one-by-one, such as running grunt env:prod shell:mongod express-server:prod express-keepalive, I get similar (incorrect) results, so either grunt or grunt env run the tasks in parallel, as well, or something else is going on.
What's going on here? Why are the environment variables not set correctly for later grunt tasks? When are they eventually set, and why then rather than some other time? How can I make them get set for grunt tasks themselves rather than after, assuming there even is a way?
The solution is rather obvious once you figure it out, so let's start at the beginning:
The problem
You're using load-grunt-config to load a set of modules (objects that define tasks) and combine them into one module (object) and pass it along to Grunt. To better understand what load-grunt-config is doing, take a moment to read through the source (it's just three files). So, instead of writing:
// filename: Gruntfile.js
grunt.initConfig({
foo: {
a: {
options: {},
}
},
bar: {
b: {
options: {},
}
}
});
You can write this:
// filename: grunt/foo.js
module.exports = {
a: {
options: {},
}
}
// filename: grunt/bar.js
module.exports = {
b: {
options: {},
}
}
// filename: Gruntfile.js
require('load-grunt-config')(grunt);
Basically, this way you can split up a Grunt configuration into multiple files and have it be more "maintainable". But what you'll need to realize is that these two approaches are semantically equivalent. That is, you can expect them to behave the same way.
Thus, when you write the following*:
(* I've reduced the problem in an attempt to make this answer a bit more general and to reduce noise. I've excluded things like loading the tasks and extraneous option passing, but the error should still be the same. Also note that I've changed the values of the environment variables because the default was the same as what was being set.)
// filename: grunt/env.js
module.exports = {
dev: {
options: {
add: {
// These values are different for demo purposes
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
};
// filename: grunt/shell.js
module.exports = {
mongod: {
command: 'mongod --port ' + (process.env.MONGO_PORT || 27017)
}
};
// filename: grunt/aliases.js
module.exports = {
server: ['env:prod', 'shell:mongod']
};
// filename: Gruntfile.js
module.exports = function (grunt) {
require('load-grunt-config')(grunt);
};
You can consider the above the same as below:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
shell: {
mongod: {
command: 'mongod --port ' + (process.env.MONGO_PORT || 27017)
}
}
});
grunt.registerTask('server', ['env:dev', 'shell:mongod']);
};
Now do you see the problem? What command do you expect shell:mongod to run? The correct answer is:
mongod --port 27017
Where what you want to be executed is:
mongo --port dev_mongo_port
The problem is that when (process.env.MONGO_PORT || 27017) is evaluated the environment variables have not yet been set (i.e. before the env:dev task has been run).
A solution
Well let's look at a working Grunt configuration before splitting it across multiple files:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
shell: {
mongod: {
command: 'mongod --port ${MONGO_PORT:-27017}'
}
}
});
grunt.registerTask('server', ['env:dev', 'shell:mongod']);
};
Now when you run shell:mongod, the command will contain ${MONGO_PORT:-27017} and Bash (or just sh) will look for the environment variable you would have set in the task before it (i.e. env:dev).
Okay, that's all well and good for the shell:mongod task, but what about the other tasks, Express for example?
You'll need to move away from environment variables (unless you want to set them up before invoking Grunt. Why? Take this Grunt configuration for example:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
express: {
options: {
hostname: '127.0.0.1'
port: (process.env.SERVER_PORT || 3000)
},
prod: {
options: {
livereload: true
server: path.resolve(__dirname, '../backend/page.js'),
bases: 'dist/'
}
}
}
});
grunt.registerTask('server', ['env:dev', 'express:prod']);
};
What port will the express:prod task configuration contain? 3000. What you need is for it to reference the value you've defined in the above task. How you do this is up to you. You could:
Separate the env configuration and reference its values
module.exports = function (grunt) {
grunt.config('env', {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
});
grunt.config('express', {
options: {
hostname: '127.0.0.1'
port: '<%= env.dev.options.add.SERVER_PORT %>'
}
});
grunt.registerTask('server', ['env:dev', 'express:prod']);
};
But you'll notice that the semantics of the env task don't hold up here due to it no longer representing a task's configuration. You could use an object of your own design:
module.exports = function (grunt) {
grunt.config('env', {
dev: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
});
grunt.config('express', {
options: {
hostname: '127.0.0.1'
port: '<%= env.dev.SERVER_PORT %>'
}
});
grunt.registerTask('server', ['env:dev', 'express:prod']);
};
Pass grunt an argument to specify what config it should use
Have multiple configuration files (e.g. Gruntfile.js.dev and Gruntfile.js.prod) and rename them as needed
Read a development configuration file (e.g. grunt.file.readJSON('config.development.json')) if it exists and fall back to a production configuration file if it doesn't exist
Some better way not listed here
But all of the above should achieve the same end result.
This seems to be the essence of what you are trying to do, and it works for me. The important part was what I mentioned in my comment -- chaining the environment task before running the other tasks.
Gruntfile.js
module.exports = function(grunt) {
// Do grunt-related things in here
grunt.loadNpmTasks('grunt-env');
grunt.initConfig({
env: {
dev: {
PROD : 'http://production.server'
}
}
});
grunt.registerTask('printEnv', 'prints a message with an env var', function() { console.log('Env var in subsequent grunt task: ' + process.env.PROD) } );
grunt.registerTask('prod', ['env:dev', 'printEnv']);
};
Output of grunt prod
Running "env:dev" (env) task
Running "printEnv" task
Env var in subsequent grunt task: http://production.server
Done, without errors.

issue in testing with gruntjs and phantomjs

I want to create a Gruntfile.js to run bunch of phantomjs tests, when I execute > grunt run-test from commandline, it runs a bunch of tests. I created a Gruntfile.js and package.json which works ok and it reads bunch of tests from a directory. Now my problem is that when I write a phantomjs test and run the "grunt", it gives me this error:
Error: Cannot find module 'system'
Error: Cannot find module 'phantom'
However phantomjs is installed before by using npm install phantomjs
Example of phantomtest which gives me the above error:
var system = require('system');
if (system.args.length === 1) {
console.log('Try to pass some args when invoking this script!');
} else {
system.args.forEach(function (arg, i) {
console.log(i + ': ' + arg);
});
}
phantom.exit();
When I run phantomjs test1 (name of the test file) it runs the test so I think maybe I should append "phantomjs" somewhere in the Gruntfile. Any idea?
Gruntfile.js
'use strict';
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
jshint: {
all: [
'Gruntfile.js',
'tests/*.js',
'<%= nodeunit.tests %>',
],
options: {
jshintrc: '.jshintrc',
},
},
// Before generating any new files, remove any previously-created files.
clean: {
tests: ['tmp'],
},
// Configuration to be run (and then tested).
testArgs: {
configFile:"test/testConf.js",
options: {
args: {
params: {
number: 1,
bool: true,
str: "string",
nil: null, // Null is not supported.
obj: {
array: [1, 2, 3],
undef: undefined
}
},
capabilities: {
'browserName': 'chrome'
},
rootElement:"body",
specs:["test/argsTest.js"],
verbose:true
}
}
},
testDebug: {
configFile:"test/testConf.js",
options: {
debug:true,
args: {
specs:["test/debugTest.js"],
}
}
},
// Unit tests.
nodeunit: {
tests: ['tests/*_test.js'],
},
});
// Actually load this plugin's task(s).
grunt.loadTasks('tests');
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-nodeunit');
// Whenever the "test" task is run, first clean the "tmp" dir, then run this
// plugin's task(s), then test the result.
grunt.registerTask('test', ['clean']);
// By default, lint and run all tests.
grunt.registerTask('default', ['jshint', 'test']);
};

Categories