Logging with grunt and qunit - javascript

I am running javascript unittests with grunt/qunit. Sometimes the tests fails because of e.g syntax errors in the source files (works fine with file info if syntax errors are introduced in the test files). When that happens grunt simply prints the line number and not the file where the problem is.
Running "qunit:all" (qunit) task
Warning: Line 99: Unexpected identifier Use --force to continue.
Aborted due to warnings.
This does not help much since I have 100 of js files. I have looked into:
https://github.com/gruntjs/grunt-contrib-qunit
and tried to add the following to my Gruntfile.js (grunt.event.on):
module.exports = function(grunt) {
"use:strict";
var reportDir = "output/reports/"+(new Date()).getTime().toString();
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
qunit: {
options: {
'--web-security': 'no',
coverage: {
src: ['../src/**/*.js'],
instrumentedFiles: 'output/instrument/',
htmlReport: 'output/coverage',
coberturaReport: 'output/',
linesTresholdPct: 85
}
},
all: ["testsSuites.html"]
}
});
// Has no effect
grunt.event.on('qunit.error.onError', function (msg, stack) {
grunt.util._.each(stack, function (entry) {
grunt.log.writeln(entry.file + ':' + entry.line);
});
grunt.warn(msg);
});
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-qunit-istanbul');
grunt.registerTask('test', ['qunit']);
Where testsSuites.html contains:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="qunit/qunit.css">
<script src="qunit/qunit.js"></script>
<script src="sinonjs/sinon-1.7.3.js"></script>
<script src="sinonjs/sinon-qunit-1.0.0.js"></script>
<!-- Sources -->
<script src="../src/sample.js"></script>
<!-- Test-->
<script src="test/sample-test.js"></script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script>
</script>
</body>
</html>
But the source file where the problem is located is still not printed. Is is out of Grunts hands to verify source code/show line number/file where e.g a syntax error is located?
I have also tried running:
grunt test --debug 9
It prints some debug info but not any information regarding syntax errors in the javascript sources.
I have tried to install JSHint and call it on all my javascript source files:
for i in $(find ../src -iname "*.js"); do jshint $i; done
Now I get tons of errors but Grunt is still happy. If I introduce a simple syntax error e.g:
(function(){
var sampleVar 32;
}
to provoke an error in Grunt:
Running "qunit:all" (qunit) task
Warning: Line 2: Unexpected number Use --force to continue.
Aborted due to warnings.
it simply disappears in the stream of errors generated by JSHint. How do I filter JSHint "warnings" from critical errors that will actually make Grunt fail?
Or is it qunit that should be configured for more verbose output?

grunt-contrib-qunit will display filenames when encountering a syntax error. Take this simplified version of your Gruntfile.js:
module.exports = function(grunt) {
"use:strict";
grunt.initConfig({
qunit: {
options: { '--web-security': 'no' },
all: ["testsSuites.html"]
}
});
grunt.loadNpmTasks('grunt-contrib-qunit');
};
Running it gives the error you're looking for:
$ grunt qunit
Running "qunit:all" (qunit) task
Testing testsSuites.html F.
>> global failure
>> Message: SyntaxError: Parse error
>> file:///tmp/src/sample.js:2
Warning: 1/2 assertions failed (17ms) Use --force to continue.
Aborted due to warnings.
The issue you're having looks to be a bug(?) in grunt-qunit-istanbul. The warning you're getting:
Warning: Line 99: Unexpected identifier Use --force to continue.
is Grunt handling an uncaught exception. The exception is being raised by the grunt-qunit-istanbul task. You can prove it by modifying this line in your original Gruntfile.js from:
src: ['../src/**/*.js'],
to:
src: ['../src/**/*.js.nomatch'],
This will prevent grunt-qunit-istanbul from finding and parsing any Javascript files before Qunit is run. If you let Qunit run, its error handler prints out the filenames with syntax errors like you want.
The only fix is the workaround I've described, or to patch grunt-qunit-istanbul to add an error handler for parse errors like Qunit does.
Patching grunt-qunit-istanbul
The function that is throwing the exception is Instrumenter.instrumentSync, which it is supposed to do:
instrumentSync ( code, filename )
Defined in lib/instrumenter.js:380
synchronous instrumentation method. Throws when illegal code is passed to it
You can fix it by wrapping the function call:
diff -r 14008db115ff node_modules/grunt-qunit-istanbul/tasks/qunit.js
--- a/node_modules/grunt-qunit-istanbul/tasks/qunit.js Tue Feb 25 12:14:48 2014 -0500
+++ b/node_modules/grunt-qunit-istanbul/tasks/qunit.js Tue Feb 25 12:19:58 2014 -0500
## -209,7 +209,11 ##
// instrument the files that should be processed by istanbul
if (options.coverage && options.coverage.instrumentedFiles) {
- instrumentedFiles[fileStorage] = instrumenter.instrumentSync(String(fs.readFileSync(filepath)), filepath);
+ try {
+ instrumentedFiles[fileStorage] = instrumenter.instrumentSync(String(fs.readFileSync(filepath)), filepath);
+ } catch (e) {
+ grunt.log.error(filepath + ': ' + e);
+ }
}
cb();
Then the test will keep running (and inform you of the syntax error):
$ grunt qunit
Running "qunit:all" (qunit) task
>> /tmp/src/sample.js: Error: Line 2: Unexpected number
Testing testsSuites.html F.
>> global failure
>> Message: SyntaxError: Parse error
>> file:///tmp/src/sample.js:2
Warning: 1/2 assertions failed (19ms) Use --force to continue.
Aborted due to warnings.

I have used grunt-contrib-qunit in the past but I have never attempted something like this. The problem you are facing is fairly interesting because the docs mention that the event qunit.error.onError should be emitted by grunt but it is not happening for you.
I created a new project using a jquery template and changed the code so that my test would fail. After that I wrote the following code:
grunt.event.on('qunit.error.onError', function(message, stackTrace) {
grunt.file.write('log/qunit-error.log', message);
});
When I ran the command grunt, I received no output in the file. To check this, I made a change to the event:
grunt.event.on('qunit.log', function(result, actual, expected, message, source) {
grunt.file.write('log/qunit-error.log', message);
});
Now, this piece of code did give me the error message in my file but it was useless because I could not get the stacktrace or the exact error message.
After this, I though of reading up the source and this is what I found:
phantomjs.on('error.onError', function (msg, stackTrace) {
grunt.event.emit('qunit.error.onError', msg, stackTrace);
});
The grunt event is only emitted when phantomjs throws an error.
At the moment I am not sure how I can get a phantomjs error while testing a simple JavaScript file without any browser related testing. This is my analysis so far and I hope this helps you in someway.

Related

requireJS, origin of the define statement

I'm working on a large project that uses Requirejs for dependency management, specifically the convention is for every file to have this pattern:
define(['dependency1', 'dependency2'], function (dependency1, dependency2) {
... some code ...
});
now I'm investigating a failure where some file is trying to require a dependency that no longer exists.
I'm getting this error from RequireJS:
GET https://some-location/some-file.js net::ERR_ABORTED
Uncaught Error: Script error for: some-file
http://requirejs.org/docs/errors.html#scripterror
at C (require.min.js:8)
at HTMLScriptElement.onScriptError (require.min.js:29)
at HTMLScriptElement.nrWrapper (...)
How can I know which file contains the faulty dependency?
Simply searching the project files is not good enough since it is a large project that spans across multiple code bases.
Is there a way to make RequireJS tell me who asked for it?
What version of requirejs are you using? I'm using 2.3.2 and the error output provide more info, take a look:
GET http://localhost:9090/requirejs/js/dependency1.js net::ERR_ABORTED
require.js:168 Uncaught Error: Script error for "home/dependency1",needed by: home/somefile
http://requirejs.org/docs/errors.html#scripterror
at makeError (require.js:168)
at HTMLScriptElement.onScriptError (require.js:1735)
Please, note that the part that says needed by: home/somefile is telling us the file that is requiring the failed dependency. This is the small local test I did.
requirejs config
require.config(
{
paths: {
'home': './js'
},
callback: function() {
require(['home/somefile'], function(a) {
console.log(a);
});
}
}
);
./js/somefile.js
define(['home/dependency1'], function (dependency1) {
console.log(dependency1);
});
So, after getting the error Uncaught Error: Script error for "home/dependency1",needed by: home/somefile, we can say that the file requiring the failed dependency is PATH_TO_OUR_PROJECT/js/somefile.js. Remember that we need to pay attention to our paths in the require config.
You can play and test the Global requirejs.onError function but it won't give you more info than the regular requirejs output.
More info in Handling Errors from docs.
Hope it helps.
Following Castro Roy's answer i made a test to verify this is indeed issue of requireJS version.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Require Test</title>
<script data-main="main" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.2/require.min.js"></script>
</head>
<body></body>
</html>
main.js
requirejs(['someFile'], function(someFile) {
console.log('main executing')
});
someFile.js
define(['someDependency'], function (someDependency) {
console.log('someFile executing')
});
and someDependency.js obviously missing.
Results:
using requireJs 2.1.20 (used in my project)
GET http://localhost:63342/playground-simple/someDependency.js net::ERR_ABORTED
Uncaught Error: Script error for: someDependency
http://requirejs.org/docs/errors.html#scripterror
at makeError (require.min.js:1)
at HTMLScriptElement.onScriptError (require.min.js:1)
Then again using requireJs 2.3.2
GET http://localhost:63342/playground-simple/someDependency.js net::ERR_ABORTED
Uncaught Error: Script error for "someDependency", needed by: someFile
http://requirejs.org/docs/errors.html#scripterror
at makeError (require.js:168)
at HTMLScriptElement.onScriptError (require.js:1735)
So clearly Yes.
This is an issue of version and not some unique behavior of my project and this information is given in the error message for later versions of require.
sadly i was not able to find any documentation for this change

Gulp location of unhandled error in events.js:141

When I run task for example using comman gulp scripts:common, I get this output:
[14:05:47] Requiring external module babel-core/register
[14:05:49] Using gulpfile /home/sites/blablabla/gulpfile.babel.js
[14:05:49] Starting 'scripts:common'...
events.js:141
throw er; // Unhandled 'error' event
^
SyntaxError: Unexpected token
Well, for SyntaxError it would be useful to know where it found that unexpected token. How to tell it to show at least file and line? Where to find that evetns.js file? Could I put console.trace() or something like that there?
I solve this problem by running jshint on my scripts:
/*
* `gulp check_scripts` - Lints script files
*/
gulp.task('check_scripts', function() {
return gulp.src([
'gulpfile.js' //, other scripts to check
])
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'))
.pipe(gulpif(enabled.failJSHint, jshint.reporter('fail')));
});
enabled.failJSHint is there to allow errors to pass in local environment but fail in production.
This will lint any syntax errors in your scripts.
Additionally you may want to hook it to other task so it's run automatically before proper build:
gulp.task('default', ['check_scripts', 'clean'], function() {
gulp.start('build');
});
This is the general idea.
You can look at error stack trace by adding custom "on error" handler to the gulp task.
gulp.task('compile:js', function() {
return (
gulp.src(jsPath)
.pipe(yourCustomTask())
.on('error', function(err) {
console.log(err.stack);
this.end();
})
);
});
Also, as another variant, adding gulp-plumber into pipeline makes error messages more clear.

Why do I get an error code from growl when using grunt-notify?

I installed grunt-notify to get messages on desktop.
Here is the Gruntfile.js :
module.exports = function(grunt) {
grunt.initConfig({
notify: {
test: {
options: {
message: "YO"
}
}
}
});
grunt.loadNpmTasks('grunt-notify');
// simplified example
grunt.registerTask('default', ['notify:test']);
};
The console output on grunt -v
E:\Temp>grunt -v
Initializing
Command-line options: --verbose
Reading "Gruntfile.js" Gruntfile...OK
Registering Gruntfile tasks.
Initializing config...OK
Registering "grunt-notify" local Npm module tasks.
Reading E:\Temp\node_modules\grunt-notify\package.json...OK
Parsing E:\Temp\node_modules\grunt-notify\package.json...OK
Loading "notify.js" tasks...OK
+ notify
Loading "notify_hooks.js" tasks...OK
+ notify_hooks
Loading "Gruntfile.js" tasks...OK
+ default
No tasks specified, running default tasks.
Running tasks: default
Running "default" task
Running "notify:test" (notify) task
Verifying property notify.test exists in config...OK
File: [no files]
Options: title="Temp", message="YO"
>> [grunt-notify] growl: C:\Utils\growlnotify\growlnotify.COM
>> [growl] cmd: growlnotify
>> [growl] args: /i:E:\Temp\node_modules\grunt-notify\images\grunt-logo.png YO /t:Temp
>> [growl] return_code: 4294967295
Done, without errors.
We can see a return_code: 4294967295 (-1 converted to unsigned 32-bit value). .
If I manually do the following command line : E:\Temp>growlnotify /i:E:\Temp\node_modules\grunt-notify\images\grunt-logo.png YO /t:Temp
I got the message (without the logo) :
So, why I got an error code when passing via grunt-notify, but not on a manual line command?
Note : I'm using Windows 7 Pro
Edit : after following this issue : https://github.com/dylang/grunt-notify/issues/91, I succeed to get the image with the command line :
C:\temp>growlnotify /i:"C:/temp/node_modules/grunt-notify/images/grunt-logo.png" "YO" /t:temp
But still doesn't work through grunt...

Intermittent browserify bundle failure (probably brfs)

This is an intermittent problem. That is, I can repeat the same build command n times without changing anything and sometimes it will work and sometimes (~30%) it will fail with seemingly no cause. I've been living with this for months now, but it is terribly annoying.
I'm using node (v0.10.35) and browserify (v6.3.4) and brfs (v1.2.0) to bundle some html in my javascript. Intermittently, the build fails with:
events.js:72
throw er; // Unhandled 'error' event
^
SyntaxError: Unterminated string constant (17:4) while parsing file: blah.js
at raise (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:333:15)
at readString (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:1073:11)
at getTokenFromCode (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:854:14)
at readToken (./httpd/node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:902:15)
at next (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:1232:5)
at eat (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:1335:7)
at expect (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:1360:5)
at parseExprList (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:2443:9)
at parseSubscripts (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:2032:24)
at parseSubscripts (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:2021:14)
at parseExprSubscripts (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:2012:12)
at parseMaybeUnary (./node_modules/brfs/node_modules/static-module/node_modules/falafel/node_modules/acorn/acorn.js:1995:16)
It's different line numbers, but each time the build fails, it points to
fs.readFileSync(
I don't think it matters, but I am using gulp v3.8.8. My gulp task is quite simple.
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
gulp.task('build', function(cb) {
return browserify(app.src, {
fullPaths: true,
transform: ['brfs'],
debug: true
}).bundle().pipe(source(app.name)).pipe(gulp.dest(app.dest));
});
Others on this same project with slightly different versions of node and gulp and even different OSes are also experiencing the same problem.
Update: It also fails with just browserify+brfs (most current versions) with the same message. I'm convinced this is a problem with brfs because it doesn't seem to fail if I leave out the transform.
var browserify = require('browserify');
var fs = require('fs');
var b = browserify('blah.js');
b.transform('brfs');
b.bundle().pipe(fs.createWriteStream('out.js'));
I was getting this problem with a similar setup (using reactify to transform, though; it was just giving me "Unterminated string constant" in the error message and didn't specify a js file). Turned out I had a syntax error in a json file (a stray newline inside of a string literal)...

"Hello World" + JS V8 + VS2010

I downloaded and built JS V8 for using in VS2010 in Release mode. Now I try run Hello World example:
#include "v8.h"
int _tmain(int argc, _TCHAR* argv[])
{
v8::HandleScope handle_scope;
v8::Persistent<v8::Context> context = v8::Context::New();
v8::Context::Scope context_scope(context);
v8::Handle<v8::String> source = v8::String::New("'Hello' + ', World'");
v8::Handle<v8::Script> script = v8::Script::Compile(source);
v8::Handle<v8::Value> result = script->Run();
context.Dispose();
v8::String::AsciiValue ascii (result);
printf ("%s\n", *ascii);
return 0;
}
I added Additional Dependencies:
"C:\v8\build\Release\lib\preparser_lib.lib"
"C:\v8\build\Release\lib\v8_base.lib"
When I try to compile and run the program, I encountered a linking error:
1>------ Build started: Project: V8_example, Configuration: Release Win32 ------
1>LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
1>v8_base.lib(platform-win32.obj) : error LNK2001: unresolved external symbol __imp__inet_addr#4
...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
When I have set "Ignore All Default Libraries: Yes(/NODEFAULTLIB)", these errors showed up:
1>------ Build started: Project: V8_example, Configuration: Release Win32 ------
1>v8_base.lib(strtod.obj) : error LNK2001: unresolved external symbol #__security_check_cookie#4
1>v8_base.lib(full-codegen-ia32.obj) : error LNK2001: unresolved external symbol #__security_check_cookie#4
...
1>c:\users\admin\documents\visual studio 2010\Projects\V8_example\Release\V8_example.exe : fatal error LNK1120: 141 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Has anyone tried to run this example or know how to fix these errors?
The error is caused by the missing symbol __imp__inet_addr#4, which is located in Ws2_32.lib.
Go to project Properties -> Linker -> Input -> Additional Dependencies. Simply add Ws2_32.lib and you're done.
I had to include the following libraries:
v8_base.lib;v8_snapshot.lib;ws2_32.lib;winmm.lib
DO NOT DEFINE /NODEFAULTLIB:LIBCMT this caused my build to fail.
If you're curious as to how I found out, I looked under the ALL.sln that is generated by GYP and checked the shell target. It's an executable that has to link with v8_base at some point, so it has the required Linker options. It was a bit difficult to find, however.
how about /NODEFAULTLIB:LIBCMT, to exclude only this single library?
also I believe you need to link v8_snapshot.lib or v8_nosnapshot.lib
or you build shared library and link to v8.lib

Categories

Resources