I've built a grunt setup for testing using qunit and generating coverage reports with istanbul but I can't get the storeCoverage task to complete without the error: No coverage information was collected.
Gruntfile.js
module.exports = function (grunt)
{
"use strict";
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
connect: {
root_server: {
options: {
port: 2424,
base: 'qunit'
},
}
},
qunit: {
all: ['qunit/test1.html']
},
instrument: {
files: "testable.js",
options: {
lazy: true,
basePath: "qunit/"
}
},
storeCoverage: {
options: {
dir: "report/"
}
},
makeReport: {
src: "report/*.json",
options: {
type: "lcov",
dir: "test",
print: "detail"
}
}
});
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks("grunt-contrib-qunit");
grunt.loadNpmTasks("grunt-istanbul");
grunt.registerTask("default", ["instrument", "connect", "qunit", "storeCoverage"/*, "makeReport"*/]);
};
testable.js
function runable ()
{
return true;
};
test1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Example</title>
<link rel="stylesheet" href="qunit.css">
</head>
<body>
<script src="qunit.js"></script>
<script src="testable.js"></script>
<script>
QUnit.test("hello test", function (assert)
{
assert.ok(runable());
});
</script>
</body>
</html>
Everything works, qunit runs and the one assert does run on the instrumented file and succeeds. But when it hits the storeCoverage task it fails. Am I doing something wrong? Any help is appreciated of course.
I was able to get this working using the Gruntfile.js from the grunt-istanbul project.
Their documentation indicates that the reloadTasks is not required, but for me it actually was. The clean task they do also assists to tidy up. Also noted in their docs, you can set an ENV variable, rather than using the env task.
Try adding these to your Gruntfile.js:
env: {
coverage: {
APP_DIR_FOR_CODE_COVERAGE: rootPath + 'path/to/instrument'
}
},
clean: ['path/to/coverage'],
reloadTasks: {
rootPath: 'path/to/instrument'
},
My task looks like this:
grunt.registerTask('cover',[
'env:coverage',
'clean',
'instrument',
'reloadTasks',
'connect',
'qunit',
'storeCoverage',
'makeReport'
]);
The question is a little old, but it might help someone else.
To solve this issue, I needed to point my test code to the instrumented code otherwise the original one.
See the example:
Gruntfile.js:
module.exports = function (grunt) {
grunt.initConfig({
env: {
coverage: {
APP_DIR_FOR_CODE_COVERAGE: '../test/coverage/instrument/lib/'
}
},
clean: {
coverage: {
src: ['test/coverage/']
}
},
instrument: {
files: 'lib/*.js',
options: {
lazy: true,
basePath: 'test/coverage/instrument/'
}
},
mochaTest: {
test: {
options: {
reporter: 'spec'
},
src: ['test/**/*test.js']
}
},
storeCoverage: {
options: {
dir: 'test/coverage/reports'
}
},
makeReport: {
src: 'test/coverage/reports/**/*.json',
options: {
type: 'lcov',
dir: 'test/coverage/reports',
print: 'detail'
}
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-istanbul');
grunt.loadNpmTasks('grunt-env');
grunt.registerTask('test', 'mochaTest');
grunt.registerTask('coverage', ['env:coverage', 'clean', 'instrument', 'mochaTest', 'storeCoverage', 'makeReport']);};
In you test code, point to the instrumented ones.
As described in the grunt-istanbul site, you can create a requireHelper file.
module.exports = function (path) {
return require((process.env.APP_DIR_FOR_CODE_COVERAGE || '../lib/') + path);
};
And use it in your test file.
var requireHelper = require('./require_helper');
var fileToBeTested = requireHelper('file-to-be-tested');
describe('Test', function () {
it('should do some test', function () {
expect(1).to.equal(1);
});
});
Related
I am maintaining an existing Aurelia project that apparently wasn't created with Aurelia CLI.
I need to create a production build but am not being able with the current configuration. The development build works just fine, but, as expected, downloads a lot of code to user machine.
After running gulp prod (gulpfile listed below), I get two JS files: app-build-{revnumber}.js and vendor-build-{revnumber}.js, but Aurelia keeps trying to load the main.js file.
I tried building the main.js together (commented code in gulpfile.js), but had no success - only vendor bundle is loaded:
Here are my config files:
config.js
System.config({
baseURL: "/www",
defaultJSExtensions: true,
transpiler: "babel",
babelOptions: {
"stage": 0,
"optional": [
"runtime",
"optimisation.modules.system"
]
},
paths: {
"*": "src/*",
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
map: { /* mappings */ }
});
gulpfile.js
var gulp = require('gulp');
var bundler = require('aurelia-bundler');
var image = image = require('gulp-image');
var replace = require('gulp-replace');
var gulpsync = require('gulp-sync')(gulp);
var config = {
force: true,
baseURL: '.',
configPath: './config.js',
bundles: {
// "dist/main": {
// includes: [
// '[main.js]'
// ],
// options: {
// inject: true,
// minify: false,
// rev: false
// }
// },
"dist/app-build": {
includes: [
'[**/*.js]',
'**/*.html!text',
'**/*.css!text'
],
options: {
inject: true,
minify: true,
rev: true
}
},
"dist/vendor-build": {
includes: [ /* all external modules */ ],
options: {
inject: true,
minify: true,
rev: true
}
}
}
};
gulp.task("bundle", function () {
return bundler.bundle(config)
.then(function () {
gulp.src('config.js')
.pipe(replace('dist/', ''))
.pipe(replace('src', 'dist'))
.pipe(gulp.dest(''));
});
});
gulp.task("unbundle",
function () {
return bundler.unbundle(config)
.then(function () {
gulp.src('config.js')
.pipe(replace('dist', 'src'))
.pipe(gulp.dest(''));
});
});
gulp.task("image-bundle",
function () {
gulp.src('./src/media/*')
.pipe(image())
.pipe(gulp.dest('./dist/media'));
});
gulp.task("files-bundle", function () {
return gulp
.src('./src/style/material.woff2')
.pipe(gulp.dest('./dist/style'));
});
gulp.task('prod', gulpsync.sync(['unbundle', 'bundle', 'image-bundle', 'files-bundle']));
gulp.task('dev', gulpsync.sync(['unbundle']));
index.html
<!DOCTYPE html>
<html>
<head>...</head>
<body aurelia-app="main">
<script src="www/jspm_packages/system.js"></script>
<script src="www/config.js"></script>
<script>
System.import('aurelia-bootstrapper');
</script>
</body>
</html>
After a lot of little adjustments, I solved the main.js issue.
It seems like System.js looks for the dependency in the bundle and, if not found, it hits the network. Here's what I did to fix my bundle:
Consolidated dist/ folder as the bundle source
In config.js, set the path of * to dist/* and don't modify it in any Gulp task.
Before the bundle task runs, I copy all contents from src/ to dist/
In the dist/app-build bundle, I added the option depCache: true. It does not work when false (gives the error of main.js not found), but I don't really know why.
The added/modified Gulp tasks:
// deletes all files in the output path
gulp.task('clean', ['unbundle'], function () {
return gulp.src(['dist/'])
.pipe(vinylPaths(del));
});
gulp.task('copy', function () {
return gulp.src(['src/**/*'])
.pipe(gulpCopy('dist/', { prefix: 1 }));
});
gulp.task("bundle", sync(['clean', 'copy']), function () {
return bundler.bundle(config);
});
gulp.task("unbundle", function () {
return bundler.unbundle(config);
});
I have a React app that I am transforming, uglifying and browserfying via Grunt. My grunt file looks like this...
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
dist: {
files: {
'./Scripts/build/App.js': ['./Scripts/src/**/*.js']
},
options: {
browserifyOptions: {
debug: true
},
transform: [ require('grunt-react').browserify ],
ignore: './Scripts/src/**/*-test.js'
}
}
},
uglify: {
my_target: {
files: {
'./Scripts/build/App-min.js': ['./Scripts/build/App.js']
}
}
},
watch: {
scripts: {
files: ['./Scripts/src/**/*.js'],
tasks: ['browserify', 'uglify'],
options: {
spawn: false
},
},
},
})
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch');
}
You will notice the ignore property of the browserify task is telling it to ignore any file with -test.js in the filename, the reason being that my tests are stored in folders directly next to the file I am testing (as seems to be the convention when looking at the React Flux examples) and I don't want the test files being bundled in to my app.js file. Can anyone tell me if I am doing this wrong because so far it doesnt seem to be working at all? The test files get bundled into app.js and then I get console errors about jest not being defined.
Did a bit of lateral Googling and found a post on stack Here
It seems that you can add files to the src array and if you prefix them with a '!' it marks them as ignored files.
My now working grunt file....
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
dist: {
files: {
'./Scripts/build/App.js': ['./Scripts/src/**/*.js', '!./Scripts/src/**/*-test.js']
},
options: {
browserifyOptions: {
debug: true
},
transform: [ require('grunt-react').browserify ]
}
}
},
uglify: {
my_target: {
files: {
'./Scripts/build/App-min.js': ['./Scripts/build/App.js']
}
}
},
jest: {
options: {
coverage: true,
testPathPattern: /.*-test.js/
}
},
watch: {
scripts: {
files: ['./Scripts/src/**/*.js'],
tasks: ['browserify', 'uglify'],
options: {
spawn: false
},
},
},
})
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-jest');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch');
}
What I tried to accomplish, when I type grunt into my cmd shell, is the following:
start mongod
start elasticsearch
start nodemon
when mongod and elasticsearch runs, execute load_JSON_into_elasticSearch.js (because I need a connection to both of them)
when everything is done, open http://localhost:8080 in the system default browser
The only thing what works at the moment is, that it'll start mongod, elasticsearch and nodemon. That's it...
Gruntfile.js
module.exports = function (grunt) {
grunt.initConfig({
shell: {
mongo: {
command: 'mongod',
options: {
async: true
}
},
elasticsearch: {
command: 'elasticsearch',
options: {
async: true
}
}
},
nodemon: {
dev: {
script: 'server.js'
}
},
execute: {
target: {
src: ['load_JSON_into_elasticSearch.js']
}
},
open: {
dev: {
path: 'http://localhost:8080',
app: 'Google Chrome'
}
}
});
grunt.loadNpmTasks('grunt-shell-spawn');
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-execute');
grunt.loadNpmTasks('grunt-open');
grunt.registerTask('startServices', ['shell', 'nodemon']);
grunt.registerTask('indexAndBrowser', ['execute', 'open']);
grunt.registerTask('default', 'Start it...', function() {
var done = this.async();
grunt.log.writeln('\n===========================================\nStarting Mongod/ ElasticSearch/ Nodemon...\n===========================================\n');
var init = function () {
grunt.task.run('startServices');
var process = function () {
setTimeout(function () {
grunt.log.writeln('\n==================================\nStarting Index and Browser...\n==================================\n');
grunt.task.run('execute');
}, 20000);
};
process();
done();
};
init();
});
};
I personally would recommend using grunt-run (I wrote it to manage similar needs).
https://www.npmjs.org/package/grunt-run
It has a few useful features that you could take advantage of. Here is an example of what using grunt-run might look like for you:
grunt.initConfig({
run: {
elasticsearch: {
cmd: 'elasticsearch',
options: {
wait: false,
ready: /started/
}
},
mongo: {
command: 'mongod',
options: {
wait: false,
ready: /waiting for connections on port/
}
},
load_json_into_es: {
args: [
'load_JSON_into_elasticSearch.js'
]
}
},
open: {
dev: {
path: 'http://localhost:8080',
app: 'Google Chrome'
}
},
nodemon: {
dev: {
script: 'server.js'
}
}
});
grunt.loadNpmTasks('grunt-run');
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-open');
grunt.registerTask('default', [
'run:mongo'
'run:elasticsearch'
'run:load_json_into_es',
'nodemon',
'open'
]);
I want to use Grunt Bake for my grunt workflow. This is my grunt.js setup:
grunt.initConfig({
bake: {
build: {
files: {
'dev/foo.html': 'public/foo.html',
'dev/bar.html': 'public/bar.html',
'dev/foo2.html': 'public/foo2.html'
// ...
}
}
},
watch: {
bake: {
files: ['dev/*.html'],
tasks: ['bake:build']
}
}
});
My problem: If I change one file all files will be compiled. I could solve this with creating a watch listener for each file but this seems not to be a clever solution:
grunt.initConfig({
bake: {
foo: {
files: {
'dev/foo.html': 'public/foo.html'
}
},
bar: {
files: {
'dev/bar.html': 'public/bar.html'
}
},
foo2: {
files: {
'dev/foo2.html': 'public/foo2.html'
}
}
// ...
},
watch: {
foo1: {
files: ['dev/foo.html'],
tasks: ['bake:foo']
},
bar: {
files: ['dev/bar.html'],
tasks: ['bake:bar']
},
foo2: {
files: ['dev/foo2.html'],
tasks: ['bake:foo2']
}
}
});
Imagine there are 20+ different html files... So this is not an option for me. Any other solutions for doing that?
Ok, got it!
There is a newer task exactly for doing this:
grunt.initConfig({
bake: {
build: {
files: {
'dev/foo.html': 'public/foo.html',
'dev/bar.html': 'public/bar.html',
'dev/foo2.html': 'public/foo2.html'
// ...
}
}
},
watch: {
bake: {
files: ['dev/*.html'],
tasks: ['newer:bake:build']
}
}
});
I am having a go at grunt for optimizing my Durandal SPA. It seems to work great but now I would like to output a second file called libs.js which is the merged uglified version of all my required libraries but my first dist is getting ignored and still the only file I get is main-built.js
I only get one file so app/libs.js never gets created. I also have no grunt errors.
Here is my Gruntfile:
module.exports = function (grunt) {
grunt.initConfig({
durandal: {
libs: {
src: [
"../scripts/jquery-1.9.1.js",
"../scripts/typeahead.js",
"../scripts/jquery-ui-1.10.3.js",
"../scripts/knockout-3.0.0rc.js",
"../scripts/toastr.js",
"../scripts/q.js",
"../scripts/breeze.min.js",
"../scripts/bootstrap.js",
"../scripts/moment.js",
"../scripts/lodash.js",
"../scripts/respond.js",
"../scripts/knockout-sortable.js",
"../scripts/knockout-bootstrap.js",
"../scripts/knockout.validation.js",
],
dest: 'scripts/libs.js',
options: {
uglify2: {
compress: {
global_defs: {
DEBUG: false
}
}
}
}
},
dist: {
src: [
"app/**/*.*",
"scripts/durandal/**/*.*"
],
options: {
baseUrl: "app/",
mainPath: "app/main.js",
out: "app/main-built.js",
uglify2: {
compress: {
global_defs: {
DEBUG: false
}
}
}
}
}
}
});
grunt.loadTasks('tasks');
grunt.registerTask('default', ['durandal']);
};
This is JavaScript. If you create an object like { a: 'a', a: 'b' }, the first key will be overwritten by the second by the VM.
Instead of configuring it like this:
dist: {
// config goes here
},
dist: {
// config goes here
}
Try
libs: {
// config goes here
},
main: {
// config goes here
}