grunt: Add Karma task for automated QUnit testing in browsers
authorTimo Tijhof <krinklemail@gmail.com>
Wed, 10 Dec 2014 05:58:31 +0000 (05:58 +0000)
committerKrinkle <krinklemail@gmail.com>
Mon, 5 Jan 2015 18:00:13 +0000 (18:00 +0000)
To use, ensure npm modules are up to date by running 'npm install'
in tests/frontend. Then run 'grunt qunit' to run it in Chrome.

To run it in both Firefox and Chrome (locally), run

 grunt karma:more

Moved fixture from hardcoded HTML to the testrunner so that our
tests don't depend on arbitrary HTML and thus also pass in browser
contexts where the page only loads QUnit + test suites (e.g. Karma).

Change-Id: I4e96da137340a28789b38940e75d4b6b8bc5d76a

includes/specials/SpecialJavaScriptTest.php
tests/frontend/Gruntfile.js
tests/frontend/package.json
tests/qunit/data/testrunner.js

index 3dc4410..fa719eb 100644 (file)
@@ -160,7 +160,6 @@ class SpecialJavaScriptTest extends SpecialPage {
                $baseHtml = <<<HTML
 <div class="mw-content-ltr">
 <div id="qunit"></div>
-<div id="qunit-fixture"></div>
 </div>
 HTML;
 
@@ -254,7 +253,6 @@ HTML;
 <title>QUnit</title>
 $head
 <div id="qunit"></div>
-<div id="qunit-fixture"></div>
 HTML;
                $html .= "\n" . Html::linkedScript( $url );
 
index c011a68..fd89e56 100644 (file)
@@ -9,9 +9,13 @@ module.exports = function ( grunt ) {
        grunt.loadNpmTasks( 'grunt-banana-checker' );
        grunt.loadNpmTasks( 'grunt-jscs' );
        grunt.loadNpmTasks( 'grunt-jsonlint' );
+       grunt.loadNpmTasks( 'grunt-karma' );
 
        grunt.file.setBase(  __dirname + '/../..' );
 
+       var wgServer = process.env.MW_SERVER,
+               wgScriptPath = process.env.MW_SCRIPT_PATH;
+
        grunt.initConfig( {
                pkg: grunt.file.readJSON( __dirname + '/package.json' ),
                jshint: {
@@ -61,10 +65,53 @@ module.exports = function ( grunt ) {
                                '.jshintrc'
                        ],
                        tasks: 'test'
+               },
+               karma: {
+                       options: {
+                               proxies: ( function () {
+                                       var obj = {};
+                                       // Set up a proxy for requests to relative urls inside wgScriptPath. Uses a
+                                       // property accessor instead of plain obj[wgScriptPath] assignment as throw if
+                                       // unset. Running grunt normally (e.g. npm test), should not fail over this.
+                                       // This ensures 'npm test' works out of the box, statically, on a git clone
+                                       // without MediaWiki fully installed or some environment variables set.
+                                       Object.defineProperty( obj, wgScriptPath, {
+                                               enumerable: true,
+                                               get: function () {
+                                                       if ( !wgServer ) {
+                                                               grunt.fail.fatal( 'MW_SERVER is not set' );
+                                                       }
+                                                       if ( !wgScriptPath ) {
+                                                               grunt.fail.fatal( 'MW_SCRIPT_PATH is not set' );
+                                                       }
+                                                       return wgServer + wgScriptPath;
+                                               }
+                                       } );
+                                       return obj;
+                               }() ),
+                               files: [ {
+                                       pattern: wgServer + wgScriptPath + '/index.php?title=Special:JavaScriptTest/qunit/export',
+                                       watched: false,
+                                       included: true,
+                                       served: false
+                               } ],
+                               frameworks: [ 'qunit' ],
+                               reporters: [ 'dots' ],
+                               singleRun: true,
+                               autoWatch: false
+                       },
+                       main: {
+                               browsers: [ 'Chrome' ]
+                       },
+                       more: {
+                               browsers: [ 'Chrome', 'Firefox' ]
+                       }
                }
        } );
 
        grunt.registerTask( 'lint', ['jshint', 'jscs', 'jsonlint', 'banana'] );
+       grunt.registerTask( 'qunit', 'karma:main' );
+
        grunt.registerTask( 'test', ['lint'] );
-       grunt.registerTask( 'default', ['test'] );
+       grunt.registerTask( 'default', 'test' );
 };
index 9b15379..101fcd9 100644 (file)
@@ -6,10 +6,16 @@
   },
   "devDependencies": {
     "grunt": "0.4.2",
+    "grunt-banana-checker": "0.2.0",
     "grunt-contrib-jshint": "0.10.0",
     "grunt-contrib-watch": "0.6.1",
-    "grunt-banana-checker": "0.2.0",
     "grunt-jscs": "0.8.1",
-    "grunt-jsonlint": "1.0.4"
+    "grunt-jsonlint": "1.0.4",
+    "grunt-karma": "0.9.0",
+    "karma": "0.12.28",
+    "karma-chrome-launcher": "0.1.7",
+    "karma-firefox-launcher": "0.1.3",
+    "karma-qunit": "0.1.4",
+    "qunitjs": "1.15.0"
   }
 }
index 7294d62..a11f554 100644 (file)
                };
        }() );
 
+       // Extend QUnit.module to provide a fixture element.
+       ( function () {
+               var orgModule = QUnit.module;
+
+               QUnit.module = function ( name, localEnv ) {
+                       var fixture;
+                       localEnv = localEnv || {};
+                       orgModule( name, {
+                               setup: function () {
+                                       fixture = document.createElement( 'div' );
+                                       fixture.id = 'qunit-fixture';
+                                       document.body.appendChild( fixture );
+
+                                       if ( localEnv.setup ) {
+                                               localEnv.setup.call( this );
+                                       }
+                               },
+                               teardown: function () {
+                                       if ( localEnv.teardown ) {
+                                               localEnv.teardown.call( this );
+                                       }
+
+                                       fixture.parentNode.removeChild( fixture );
+                               }
+                       } );
+               };
+       }() );
+
        // Initiate when enabled
        if ( QUnit.urlParams.completenesstest ) {