I have been writing a small grunt plugin, and now I am stuck trying to test the plugin end-to-end. What I would like to accomplish is this
Write a test case that configures a grunt instance with a minimal grunt config for my plugin and runs that task
Test that the file produced equals the intended output
Run that test automatically when running grunt nodeunit
So far, I seem stuck on configuring an individual Grunt instance, as the new instance seems to share configuration with that of the already loaded Grunt instance.
I got something like this in my plugin_test.js
var testGrunt = require('grunt');
exports.codekit = {
setUp: function(done) {
testGrunt.initConfig({
myPlugin : {
// the config
}
});
testGrunt.task.run(['myPlugin']);
done();
},
basic_parsing_works: function(test) {
test.expect(1); // no idea what this does
test.equal(1,1,'basic test');
//var actual = testGrunt.file.read('tmp/test01_result.html');
//var expected = testGrunt.file.read('expected/test01_expected.html');
//test.equal(actual, expected, 'should parse file.');
test.done();
}
};
The problem is that when I run the task for myPlugin it uses the configuration loaded in the "outer" (already running) Grunt instance. Even though I have specifically created a new Grunt instance under a different name (testGrunt).
Is there a way to avoid this?
Related
So I'm having a slight problem with producing production ready scripts for my project. I'm using gulp to concatenate and minify my css and js, and while the css is working fine the gulp js function isn't generating my final file. Please refer to my code below:
gulp.task('js', function() {
return gulp.src([source + 'js/app/**/*.js'])
.pipe(concat('development.js'))
.pipe(gulp.dest(source + 'js'))
.pipe(rename({
basename: 'production',
suffix: '-min',
}))
.pipe(uglify())
.pipe(gulp.dest(source + 'js/'))
.pipe(notify({ message: 'Scripts task complete', onLast: true }));
});
If anyone has encountered a similar problem or has any tips it would be much appreciated :)
There is nothing wrong with your gulpfile. I tested it and it works perfectly.
The only thing I can guess is that your source is not set correctly. Did you forget the trailing slash '/' ?
I would suggest 2 things to figure it out. Include node path library to check where source is actually pointing to like this:
var path = require('path');
// in gulp task ...
path.resolve(path.resolve(source + 'js/app'));
Make sure it points where you think it does.
Secondly, you could use gulp-debug to establish that any files are found:
npm install gulp-debug
Then
var debug = require('gulp-debug');
// in gulp task ...
return gulp.src([source + 'js/app/**/*.js'])
.pipe(concat('development.js'))
.pipe(debug())
.pipe(gulp.dest(source + 'js'))
.pipe(debug())
// etc.
Good luck!
Based on additional infomation in the comments I realise you are generating JS files in a separate process ...
gulp is asynchronous by default. What this boils down to is that all functions try to run at the same time - if you want a specific order it must be by design. This is great because it's very fast but can be a headache to work with.
Problem
Here is what's basically happening:
// SOME TASK THAT SHOULD BE RUN FIRST
gulp.task('copy-vendor-files-to-tempfolder', function (done) {
// copy files to vendor folder
done()
})
// SOME TASKS THAT DEPEND ON FIRST TASK
gulp.task('complile-styles', function () { /* independent task */ })
gulp.task('concat-vendor-files', function () { /* concat files in vendor folder. depends on vendor files existing */ })
// GENERAL TASK WHICH STARTS OTHERS
gulp.task('ready', ['copy-vendor-files-to-tempfolder', 'compile-styles', 'concat-vendor-files])
When you try to run:
$ gulp ready
GULP TASK WILL FAIL! Folder is being created at the same time!!
NOWHERE TO COPY FILES!
Solution
There are many solutions but the following module has come in handy for me again and again:
npm install run-sequence
Then in your gulpfile.js:
var runSequence = require('run-sequence')
gulp.task('ready', function (done) {
runSequence(
'create-folders', // do this first,
[
'copy-css-files',
'copy-html-files'
], // do these AFTER but in parallel
done // callback when ready
)
})
This will guarantee the folder exists when you try to run the other functions.
In your specific case, you should make sure the task that concatenates the JS files is run after the task that copies them out of vendor.
Note: I'm leaving other answer because it contains useful help for debugging similar issues.
HTH!
I am having a hard time trying to run tests with Mocha and RequireJS in the browser.
My attempt is based on https://gist.github.com/michaelcox/3800736
I had to diverge from that example, because my main issue is that require('mocha') always errors with "Module name "lib/mocha" has not been loaded yet for context".
But somehow magically I see that global Mocha is instantiated. I invoke it as a constructor, but the run of new Mocha() does not prepare the interface (describe, etc.)
I see that the problem is that an inner call to
this._ui = this._ui(this.suite);
leaves this._ui undefined, apparently because array this.suite.tests is empty, which is explainable as I still have to read the test suite file.
Here are the details. If anyone can shed some light, I'll be very grateful.
I start from a single HTML tag loading require.js with a data-main.
<script data-main="./js_modular/spec-runner" src="./js_modular/lib/require.js"></script>
My data-main file (not working!) is the following:
require.config({
'paths': {
'mocha': './lib/mocha',
'chai': './lib/chai',
'sinon': './lib/sinon-1.11.1'
}
});
define(['require', 'exports', 'mocha'], (function(require, exports, mocha) {
// mocha is undefined, but Mocha is not
var mocha = new Mocha({ ui: 'bdd' }); // mocha misses the characteristic methods of the bdd interface, though...
require([
'./geiesadts_test', // load of test file fails because describe is undefined
], function(require) {
mocha.run(); // never got till here :-(
});
}));
Thank you for your attention.
I am working on an AngularJS app. One of my services is really buggy. For that reason, I want to test it. To run those tests, I wanted to use a grunt task. The idea is, I would type grunt test from the command line to run my unit tests. My first step was creating my grunt file, which looks like this:
gruntfile.js
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
jasmine: {
mocks: {
src: 'dist/service.min.js',
options: {
specs: 'test/*.js',
vendor: [
'bower_components/angularjs/angular.min.js',
'bower_components/angular-mocks/angular-mocks.js'
]
}
}
}
});
require('load-grunt-tasks')(grunt);
grunt.registerTask('test', ['jasmine:unitTests']);
};
Then, my tests would look like this:
service.spec.js
describe('myModule', function() {
beforeEach(function() {
module('myModule');
});
describe('$myService', function () {
var service = null;
beforeEach(inject(function ($myService) {
service = $myService;
}));
it('should get here', function () {
console.log('first test');
var isSynchronized = service.isSynchronized();
expect(isSynchronized).toBe(true);
});
});
})
This test is intended to test my service:
service.js
'use strict';
angular.module('myModule', [])
.factory('$myService', [function () {
return {
isSynchronized: function () {
return true;
}
};
}]
);
My problem has to do with the inject command in the tests. That function call causes the test to break. If I remove the beforeEach block that uses inject, the test at least runs. I keep hearing about Karma. However, I don't know much about it.
Is Karma a required piece to test AngularJS services? I can't find an example of testing an ngularJS service from grunt. Everything I see is in the browser. I'm trying to create the minimum required grunt file that will allow me to test my AngularJS service. However, I'm totally stuck. I can't figure out why inject is failing.
Can someone please tell me what I'm missing. Or, perhaps point me to an example that uses grunt to test an AngularJS service? Currently, I see the following in the command line, so I know service.js exists.
Running "uglify:mocks" (uglify) task
Verifying property uglify.mocks exists in config...OK
Files: dist/service.js -> dist/service.min.js
Options: banner="", footer="", compress, mangle={}, beautify=false, report="min", expression=false, preserveComments=false
Minifying with UglifyJS...Reading dist/service.js...OK
OK
Writing dist/service.min.js...OK
File dist/service.min.js created: 293 B → 190 B
Running "jasmine:mocks" (jasmine) task
Verifying property jasmine.mocks exists in config...OK
Files: dist/service.min.js
Options: version="2.0.1", timeout=10000, styles=[], specs="test/*.js", helpers=[], vendor=["bower_components/angularjs/angular.min.js","bower_components/angular
-mocks/angular-mocks.js"], outfile="_SpecRunner.html", host="", template="C:\\source\\myModule\\node_modules\\grunt-contrib-jasmine\\tasks/jasmine
/templates/DefaultRunner.tmpl", templateOptions={}, junit={}, ignoreEmpty=false, display="full", summary=false
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../jasmine/reporters/PhantomReporter.js...OK
Writing .grunt\grunt-contrib-jasmine\reporter.js...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../../vendor/jasmine-2.0.1/jasmine.css...OK
Writing .grunt\grunt-contrib-jasmine\jasmine.css...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../../vendor/jasmine-2.0.1/jasmine.js...OK
Writing .grunt\grunt-contrib-jasmine\jasmine.js...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../../vendor/jasmine-2.0.1/jasmine-html.js...OK
Writing .grunt\grunt-contrib-jasmine\jasmine-html.js...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../../vendor/jasmine-2.0.1/boot.js...OK
Writing .grunt\grunt-contrib-jasmine\boot.js...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../../vendor/jasmine-2.0.1/jasmine_favicon.png...OK
Writing .grunt\grunt-contrib-jasmine\jasmine_favicon.png...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks\lib/../../node_modules/es5-shim/es5-shim.js...OK
Writing .grunt\grunt-contrib-jasmine\es5-shim.js...OK
Reading C:\source\myModule\node_modules\grunt-contrib-jasmine\tasks/jasmine/templates/DefaultRunner.tmpl...OK
Processing source...OK
Writing _SpecRunner.html...OK
Testing jasmine specs via phantom
Thank you!
I already have grunt-contrib-qunit set up. My Gruntfile.js includes something like this
qunit: { files: ['test/*.html'] }
Now I can run grunt qunit and all my tests run.
Question: how can I run just one single test without running all of them? Is there a way I can overload the value of files from the command line?
You definitely need to look into grunt-contrib-qunit and grunt-contrib-connect (https://github.com/gruntjs/grunt-contrib-qunit and https://github.com/gruntjs/grunt-contrib-connect) as the tandem will provide you with a headless phantom and a local webserver.
UPDATE - as for running just one specific test, you could write something like this, listing your tests as separate targets for your qunit task:
grunt.initConfig({
qunit: {
justSomething: ['test/justsomething.html'],
justSomethingElse: ['test/justsomethingelse.html'],
all: ['test/*.html']
}
});
Then you can call grunt qunit:justSomething, or grunt qunit:all - this is not specific to qunit, though - see http://gruntjs.com/configuring-tasks
Now, if you would really like to use the target to specify a test name, you would go with something like:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.initConfig({
qunit: {
all: ['test/**/*.html']
}
});
grunt.task.registerTask('foo', 'A sample task that run one test.', function(testname) {
if(!!testname)
grunt.config('qunit.all', ['test/' + testname + '.html']);
grunt.task.run('qunit:all');
});
}
Then call grunt foo:testname.
Yet again, this is not specific to qunit - but rather grunt task writing.
Hope that (finally) helps.
When grunt.loadNpmTasks is used, a grunt task is automatically available to the command line. It can be useful, but sometimes, I would like this task to be private, so it can be used whithin the Grunt file but not available to the command line.
Here is a contrived example. If I do :
module.exports = function(grunt) {
grunt.initConfig({
clean: {
test: ['test'],
release: ['release']
},
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.registerTask('build', 'Build the project.', function() {
console.log("building project");
});
grunt.registerTask('release', ['clean:release', 'build']);
};
... I can use the following command :
$ grunt release
However, this one is also available, and both clean:release and clean:test will be executed:
$ grunt clean
I do not want that. I want to control what can be called from the command line, since I may not have foreseen some undesirable effects if the user directly calls some tasks or subtasks.
I thought about registering a new clean task to supersedes the main one, and then choose what to call when clean is invoked (or to call nothing at all), but it does not work well since it cannot call the original clean task:
grunt.registerTask('clean', ['clean:release']);
Use grunt.task.renameTask
var ticks = +new Date();
var clean = 'clean-' + ticks;
grunt.task.renameTask('clean', clean);
grunt.registerTask('release', [clean + ':release', 'build']);
grunt.config.set(clean, grunt.config.get('clean'));
Copying the configuration over is important if you want to preserve the targets configuration