grunt 및 qunit을 사용한 로깅 (Logging with grunt and qunit)


문제 설명

grunt 및 qunit을 사용한 로깅 (Logging with grunt and qunit)

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?


참조 솔루션

방법 1:

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.

방법 2:

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.

(by u123Michael KropatAniket)

참조 문서

  1. Logging with grunt and qunit (CC BY‑SA 3.0/4.0)

#gruntjs #javascript #unit-testing






관련 질문

프로그램에서 연속적으로 오류 코드를 받는 Gruntfile (Gruntfile getting error codes from programs serially)

grunt.initConfig() 전에 비동기 작업을 수행하려면 어떻게 해야 합니까? (How can I perform an asynchronous operation before grunt.initConfig()?)

grunt 및 qunit을 사용한 로깅 (Logging with grunt and qunit)

Intellij IDEA 13 - 최신 JS 파일을 사용한 아티팩트 빌드 프로세스(grunt 빌드를 통해) (Intellij IDEA 13 - Artifact build process with latest JS files (Via grunt build))

IntelliJ IDEA에서 Grunt 작업에 대한 사용자 지정 config.json 위치 설정 (Setup custom config.json location for Grunt tasks in IntelliJ IDEA)

Grunt 및 Compass와 함께 node-normalize-scss 사용 (Using node-normalize-scss with Grunt and Compass)

npm grunt-libsass 설치 오류 (Error installing npm grunt-libsass)

루트 폴더에 없는 Gruntfile.js가 있는 Visual Studio 작업 실행기 탐색기 (Visual Studio Task Runner Explorer with Gruntfile.js that is not in the root folder)

하위 디렉토리의 Angular2.0, SystemJS는 각도 구성 요소를 가져올 수 없습니다. (Angular2.0 in subdirectory, SystemJS cant import angular components)

html5 모드를 사용하여 Angular 다시 로드 (Reload Angular using html5 mode)

그런트 작업 옵션을 이해하는 방법 (How to understand Grunt task options)

오류: 프로젝트의 기본 XML 네임스페이스는 MSBuild XML 네임스페이스여야 합니다. (Error: The default XML namespace of the project must be the MSBuild XML namespace)







코멘트