I have a grunt task that runs all of my nodejs server side test files.
grunt.registerTask('serverTest', ['env:test', 'mongoose', 'mochaTest']);
While developing tests I would like to only run the test I'm currently working on. My task is setup to run a list of all test assets in the code base:
mochaTest: {
src: testAssets.tests.server,
options: {
reporter: 'spec'
}
},
I would like to specify a filter parameter at the cli to only select a specific file from testAssets.tests.server which is a big list of tests since it's defined as modules/*/tests/server/**/*.js and returns every test in the code base.
For example if I entered the following at the command line:
grunt serverTest:*fileUnderTest.js
Grunt would filter the testAssets.tests.server and only execute the files that match *fileUnderTest.js
I've read through the documentation and seen a lot of examples but can't figure out how to do this without creating a separate target and specifying the file name in the grunt file.
There's probably a more efficient means but the following code at the start of my gruntfile got the filtering working for me.
// get regex epression from CLI
var expression = grunt.option('filter');
//filter the testAssets.tests.server array
var testFiles = filtered(getGlobbedPaths(testAssets.tests.server),expression);
// test array with regex and return array of matches
var filtered = (function(arr,pattern){
var filtered = [],
i = arr.length,
re = new RegExp(pattern);
while (i--) {
if (re.test(arr[i])) {
filtered.push(arr[i]);
}
}
return filtered;
});
And then the grunt task becomes:
mochaTest: {
src: testFiles,
options: {
reporter: 'spec'
}
}
grunt.registerTask('serverTest', ['env:test', 'mongoose', 'mochaTest']);
So a command line call such as:
grunt serverTest --filter=comment.server.model.tests.js
Will run any test file matching the filter and a command like:
grunt serverTest
Will run all test files in the project
For reference my project is based on meanjs which globs all the paths to files so I run the getGlobbedPaths() function which is defined in config.js to first expand the file path array prior to filtering:
var getGlobbedPaths = function(globPatterns, excludes) {
// URL paths regex
var urlRegex = new RegExp('^(?:[a-z]+:)?\/\/', 'i');
// The output array
var output = [];
// If glob pattern is array so we use each pattern in a recursive way, otherwise we use glob
if (_.isArray(globPatterns)) {
globPatterns.forEach(function(globPattern) {
output = _.union(output, getGlobbedPaths(globPattern, excludes));
});
} else if (_.isString(globPatterns)) {
if (urlRegex.test(globPatterns)) {
output.push(globPatterns);
} else {
glob(globPatterns, {
sync: true
}, function(err, files) {
if (excludes) {
files = files.map(function(file) {
if (_.isArray(excludes)) {
for (var i in excludes) {
file = file.replace(excludes[i], '');
}
} else {
file = file.replace(excludes, '');
}
return file;
});
}
output = _.union(output, files);
});
}
}
return output;
};
Related
I am trying copy my vendor files to my dev folder using gulp. When I was in development mode, I want copy only the unminified files, if unminified is not present copy minified files. And in production mode I want copy minifed files if files are not present minify the normal files.
my folder structure
js
app.js
jquery
jquery.min.js
jquery.js
fontawesome
fontawesome.min.js
fontawesome.min.css
fonts.ttf...
Here my basic I had written.
var scriptsPath = '../vendor/';
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function(file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
gulp.task('vendor', function() {
var folders = getFolders(scriptsPath);
var cssFilter = $.filter('**/*.css')
var tasks = folders.map(function(folder) {
var jsFilter;
if (isProduction) {
jsFilter = $.filter('**/*.min.js');
} else {
jsFilter = $.filter(['**/*.js', '!**/*.min.js']);
}
return gulp.src(path.join(scriptsPath, '**/'))
.pipe(jsFilter)
.pipe($.if(useSourceMaps, $.sourcemaps.init()))
.pipe($.if(isProduction, $.uglify({preserveComments: 'some'})))
.on('error', handleError)
.pipe(jsFilter.restore())
.pipe(cssFilter)
.pipe($.if( isProduction, $.minifyCss() ))
.on('error', handleError)
.pipe(cssFilter.restore())
.on('error', handleError)
.pipe(gulp.dest(build.vendor.js));
});
return es.concat.apply(null, tasks);
});
I am trying the last two days using gulp-if& some methods. But not yet get the solution.Thanks in advance.
You are trying to cram way to much into your vendor task. The stuff you do with your JS files is completely unrelated to the stuff you do with your CSS files. That's hard to read.
Instead of using gulp-filter try splitting vendor up into smaller tasks like vendor-js, vendor-css, etc... and then declare them as dependencies for your vendor task:
gulp.task('vendor', ['vendor-js', 'vendor-css' /* etc ... */]);
Your vendor-js task could then look like this:
var glob = require('glob');
gulp.task('vendor-js', function () {
var js = glob.sync('../vendor/**/*.js');
if (isProduction) {
// use <file>.min.js, unless there is only <file>.js
js = js.filter(function(file) {
return file.match(/\.min\.js$/) ||
js.indexOf(file.replace(/\.js$/, '.min.js')) < 0;
});
} else {
// use <file>.js, unless there is only <file>.min.js
js = js.filter(function(file) {
return !file.match(/\.min\.js$/) ||
js.indexOf(file.replace(/\.min\.js$/, '.js')) < 0;
});
}
gulp.src(js, { base: '../vendor' })
.pipe($.if(isProduction, // only minify for prod and when
$.if("!**/*.min.js", uglify()))) // the file isn't minified already
.pipe(gulp.dest('build'));
});
Adapting this to you specific needs should be fairly trivial from here on.
Hi I have the following simple nightwatch demo script which is looping when ran with multiple browser environment, but which works fine if I run the test with single browser.
Following arguments loops the test:
var argv = {
test: 'nightwatchgoogletest.js',
config: 'nightwatch.json',
reporter: 'junit',
env : 'default,chrome'
};
Following works fine:
var argv = {
test: 'nightwatchgoogletest.js',
config: 'nightwatch.json',
reporter: 'junit',
env : 'chrome' (or default or any single browser)
};
Following is my code, please let me know what am I doing wrong here.
nightwatchgoogletest.js :
module.exports = {
'Demo test Google' : function (client) {
client
.url('http://google.no')
.pause(1000);
// expect element to be present in 1000ms
client.expect.element('body').to.be.present.before(1000);
// expect element <#lst-ib> to have css property 'display'
client.expect.element('#lst-ib').to.have.css('display');
// expect element to have attribute 'class' which contains text 'vasq'
client.expect.element('body').to.have.attribute('class').which.contains('vasq');
// expect element <#lst-ib> to be an input tag
client.expect.element('#lst-ib').to.be.an('input');
// expect element <#lst-ib> to be visible
client.expect.element('#lst-ib').to.be.visible;
client.end();
}
};
And have written the following node script to call above test:
var Nightwatch = require('nightwatch');
function proceess_test() {
try {
var argv = {
test: 'nightwatchgoogletest.js',
config: 'nightwatch.json',
reporter: 'junit',
env : 'default,chrome'
};
console.log("\n>> Initiating Tests for ...",process.env.__NIGHTWATCH_ENV_KEY);
var settings = {};
var done = function() {console.log("done")};
Nightwatch.runner(argv, done, settings);
done();
} catch (error) {
console.log('Exception: ' + error.message);
}
}
proceess_test();
With the following nightwatch configuration:
http://www.jsoneditoronline.org/?id=7e8e1616d595417ceeafaccc6358b33d
But when I run the test, it going in an infinite testing loop as follows:
I've just started using Gulp (and NodeJs)... Obviously I ran into my first wall.
Here it is:
I have a large project that uses themes. Each theme has it's own assets (scss and js files). Here is my gulpfile.js:
// < require block here (not included, to keep this short)
var themes = ["theme1", "theme2", "theme3"];
// Since I can have up to 20 different themes, I use the 'themes' array so I can create tasks dynamically, like this:
themes.forEach(function (theme) {
gulp.task('css:' + theme, function () {
setVersion([theme], 'css'); // write asset version into a json file
gulp.src('../themes/frontend/' + theme + '/assets/css/style.scss')
.pipe(sourcemaps.init())
.pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('../themes/frontend/' + theme + '/assets/css'))
});
});
// Of course, I need an "all" task to build all CSS in rare ocasions I need to do so:
gulp.task('css:all', ("css:" + themes.join(",css:")).split(","));
// ("css:" + themes.join(",css:")).split(",") => results in the needed ['css:theme1', 'css:theme2'] tasks array
// The same logic as above for JS files
// but added the use of gulp-concat and gulp-uglify
// Having scripts = { "theme1" : ['script1', 'script2'], "theme2": ['script1', 'script2'] }
// ...
// And "per theme" both "css and js"
themes.forEach(function (theme) {
gulp.task('theme:' + theme, ['css:' + theme, 'js:' + theme]);
});
// Next I need to set versions for each asset
// I'm writing all the versions into a json file
assetsVersion = someRandomGeneratedNumber;
function setVersion(themes, assetType) {
/**
* themes: array
* assetType: 'all', 'css' or 'js'
*/
var fs = require('fs'),
path = require("path");
var versionsFilePath = path.normalize(__dirname + '/../protected/config/theme/frontend/');
var versionsFileName = '_assets-version.json';
if (!fs.existsSync(versionsFilePath + versionsFileName)) {
// Create file if it doesn't exist
fs.writeFile(versionsFilePath + versionsFileName, "{}", function (err) {
if (err) {
return console.log(err);
}
});
}
gulp.src(versionsFilePath + versionsFileName)
.pipe(jeditor(function (json) {
themes.forEach(function(theme) {
if ("undefined" == typeof (json[theme])) {
json[theme] = {};
}
if ('css' == assetType) {
json[theme]['css'] = assetsVersion;
} else if ('js' == assetType) {
json[theme]['js'] = assetsVersion;
} else {
json[theme] = {"css": assetsVersion, "js": assetsVersion};
}
if ("undefined" == typeof(json[theme]['css'])) {
// if we're missing the 'css' key (i.e. we've just created the json file), add that too
json[theme]['css'] = assetsVersion;
}
if ("undefined" == typeof(json[theme]['js'])) {
// if we're missing the 'js' key (i.e. we've just created the json file), add that too
json[theme]['js'] = assetsVersion;
}
});
return json;
}))
.pipe(gulp.dest(versionsFilePath));
}
The assets versioning json should look like this:
{
"theme1": {
"css": "20150928163236",
"js": "20150928163236"
},
"theme2": {
"css": "20150928163236",
"js": "20150928163236"
},
"theme3": {
"css": "20150928163236",
"js": "20150928163236"
}
}
running 'gulp css:theme#' - works fine...
BUT running 'gulp css:all' - makes a messy json
Of course, this happens because all css:theme# (or js:theme#) tasks run async, and more often than not there are multiple tasks writing simultaneously to my json file.
I've read about tasks depending on other tasks, but that doesn't really fit into my whole "dynamic tasks" flow (or I don't know how to fit it in).
I mean I don't think that this:
gulp.task('css:theme1', ['versioning'], function() {
//do stuff after 'versioning' task is done.
});
would help me. SO what if it waits for the version to be written? Multiple tasks would still write to the file at the same time. Also, for this to work, I would need to pass parameters that I also don't know how to do... like:
gulp.task('css:'+theme, ['versioning --theme ' + theme], function() {
//do stuff after 'versioning' task is done.
});
Like I could make it work in the console. I know this isn't working, BUT would be really useful in some cases if it would somehow be possible to send parameters to the task in the task name.
Neither runSequence() { ... done(); }, I really don't see how could I make it work within my flow...
Please, anybody... help a newb...
How can I solve this, while:
Having tasks created dynamically;
Having one versioning json file for all themes.
I'm writing a plugin for Brunch to 'filter' files from code library. Basic idea is to:
check my source files (in src\ folder, or any watched folders that don't match library pattern),
build a list of imported/required modules from code library (in lib\ folder, outside src\, somewhere on disk)
check files against this list and 'approve' or 'reject' them
compile only what's 'approved', so I don't end up with huge files that have all modules/components from my library, but only what I use in particular project
When I work only with JavaScript files this.pattern = /.*(js|jsx)$/; everything works fine. Next step is to include more files, since many modules/components in library have some sort of template or stylesheets, for example this is one AngularJS module:
lib\
modules\
pager\
controller.jsx
directive.jsx
template.html
pager.styl
README.md
But when I expand the pattern to include other files this.pattern = /.*/;, I run into all sorts of issues (; Most have to do with pipline - those are the kinds of errors I'm getting. For example:
jshint-brunch doesn't like README.md
html-brunch won't wrap template.html
stylus-brunch and sass-brunch are also unhappy
I've tried solving these problems individually, for example if I disable html-brunch config.plugins.off: ['html-brunch'], and add this code inside the compiler function, it kinda works:
if( params.path.match(/.html$/) ) {
params.data = "module.exports = function() { return " + JSON.stringify(params.data) + ";};";
return callback(null, this.config.modules.wrapper(params.path, params.data));
}
..but I couldn't resolve all the issues. Pretty much all problems have to do with this line in the compiler function: return callback(null, null);. When I 'reject' a file next plugin gets something undefined and breaks...
Any ideas how to solve this?
I'd like to eventually expand plugin's functionality to handle static assets too, for example copy lib\images\placeholder-1.jpg (but not placeholder-2.jpg) from library if it's used in html files, but I'm stuck at this point...
Here's the code of the plugin:
var CodeLibrary;
module.exports = CodeLibrary = (function() {
var required = [];
CodeLibrary.prototype.brunchPlugin = true;
function CodeLibrary(config) {
this.config = config;
this.pattern = /.*/;
this.watched = this.config.paths.watched.filter(function(path) {
return !path.match( config.plugins.library.pattern );
});
}
function is_required(path) {
var name = this.config.modules.nameCleaner(path);
return required.some(function(e, i, a) { return name.match(e); });
}
function in_library(path) {
return Boolean(path.match( this.config.plugins.library.pattern ));
}
function is_watched(path) {
return this.watched.some(function(e, i, a) { return path.match( e ); });
}
CodeLibrary.prototype.lint = function(data, path, callback) {
if( !is_watched.apply(this, [path]) &&
!is_required.apply(this, [path]) )
return callback();
var es6_pattern = /import .*'(.*)'/gm;
var commonjs_pattern = /require\('(.*)'\)/gm;
var match = es6_pattern.exec(data) || commonjs_pattern.exec(data);
while( match != null ) {
if( required.indexOf(match[1]) === -1 )
required.push( match[1] );
match = es6_pattern.exec(data) || commonjs_pattern.exec(data);
}
callback();
}
CodeLibrary.prototype.compile = function(params, callback) {
if( is_required.apply(this, [params.path]) ||
!in_library.apply(this, [params.path]) )
return callback(null, params);
return callback(null, null);
};
return CodeLibrary;
})();
I have Gulpfile with jshint configured to use jshint-stylish reporter. I need to pass option verbose to reporter in order to display warning codes. Is it possible to do it using Gulp?
Current my gulpfile.js looks like below:
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var compass = require('gulp-compass');
var path = require('path');
require('shelljs/global');
var jsFiles = ['www/js/**/*.js', '!www/js/libraries/**/*.js', 'www/spec/**/*.js', '!www/spec/lib/**/*.js'];
var sassFiles = 'www/sass/*.scss';
gulp.task('lint', function () {
return gulp
.src(jsFiles)
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('compass', function () {
gulp.src(sassFiles)
.pipe(compass({
project: path.join(__dirname, 'www'),
css: 'css',
sass: 'sass',
image: 'img',
font: 'fonts'
})).on('error', function() {});
});
var phonegapBuild = function (platform) {
if (!which('phonegap')) {
console.log('phonegap command not found')
return 1;
}
exec('phonegap local build ' + platform);
};
gulp.task('build:android', ['lint', 'compass'], function () {
phonegapBuild('android');
});
gulp.task('build:ios', ['lint', 'compass'], function () {
phonegapBuild('ios');
});
gulp.task('watch', function() {
gulp.watch(jsFiles, ['lint']);
gulp.watch(sassFiles, ['compass']);
});
gulp.task('default', ['lint', 'compass']);
Well, this, plus the fact that the output of the stylish reporter is hardly readable on Windows due to the darkness of the blue text, so I have to keep going in an manually changing the colour after installing it, has made me do something about it. So you should hopefully have more luck with this reporter I've just written:
https://github.com/spiralx/jshint-summary
You basically use it like this;
var summary = require('jshint-summary');
// ...
.pipe(jshint.reporter(summary({
verbose: true,
reasonCol: 'cyan,bold',
codeCol: 'green'
})
and the summary function will initialise the function passed to JSHint with those settings - see the page on Github for a bit more documentation.
It's got some very basic tests, and the library's gulpfile.js uses it to show its own JSHint output :)
How about using similar technique, as you already did with phonegap?
var jshint = function (parameter) {
// todo: define paths with js files, or pass them as parameter too
exec('jshint ' + paths + ' ' + parameter);
};
Based on https://github.com/wearefractal/gulp-jshint/blob/master/index.js#L99 it appears that gulp-jshint doesn't facilitate passing more than the name to the reporter if you load it with a string. It seems a simple thing to extend though. I'll race you to a pull request. :D
Alternatively, try something like this:
var stylish = require('jshint-stylish');
// ...
.pipe(jshint.reporter(stylish(opt)));
I'm pretty sure I have the syntax wrong, but this may get you unstuck.
It's annoying, and makes any decent reporter somewhat tricky to use within the existing framework. I've come up with this hack for the Stylish reporter, it's just currently in my gulpfile.js:
function wrapStylishReporter(reporterOptions) {
var reporter = require(stylish).reporter,
reporterOptions = reporterOptions || {};
var wrapped = function(results, data, config) {
var opts = [config, reporterOptions].reduce(function(dest, src) {
if (src) {
for (var k in src) {
dest[k] = src[k];
}
}
return dest;
}, {});
reporter(results, data, opts);
};
return jshint.reporter(wrapped);
}
And then for the task definition itself:
gulp.task('lint', function() {
return gulp.src('+(bin|lib)/**/*.js')
.pipe(jshint())
.pipe(wrapStylishReporter({ verbose: true }))
.pipe(jshint.reporter('fail'));
});
Ideally reporters would either be a function that takes an options parameter and returns the reporter function, or a fairly basic class so you could have options as well as state.