X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=tests%2Fqunit%2Fdata%2Ftestrunner.js;h=929fa1fb5e64856bba8361d9b6bc806c86e9afc1;hb=43dc5c1539e887c68a6c0ba09de83277ee71b9d3;hp=d7da5a05c3e0402c507c2a95a1f5977ec13503dd;hpb=f246973a44ea17eec0dd721e64e0481deb48a8b9;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/qunit/data/testrunner.js b/tests/qunit/data/testrunner.js index d7da5a05c3..929fa1fb5e 100644 --- a/tests/qunit/data/testrunner.js +++ b/tests/qunit/data/testrunner.js @@ -4,6 +4,22 @@ var addons; + /** + * Make a safe copy of localEnv: + * - Creates a copy so that when the same object reference to module hooks is + * used by multipe test hooks, our QUnit.module extension will not wrap the + * callbacks multiple times. Instead, they wrap using a new object. + * - Normalise setup/teardown to avoid having to repeat this in each extension + * (deprecated in QUnit 1.16, removed in QUnit 2). + * - Strip any other properties. + */ + function makeSafeEnv( localEnv ) { + return { + beforeEach: localEnv.setup || localEnv.beforeEach, + afterEach: localEnv.teardown || localEnv.afterEach + }; + } + /** * Add bogus to url to prevent IE crazy caching * @@ -42,9 +58,6 @@ * * Glue code for nicer integration with QUnit setup/teardown * Inspired by http://sinonjs.org/releases/sinon-qunit-1.0.0.js - * Fixes: - * - Work properly with asynchronous QUnit by using module setup/teardown - * instead of synchronously wrapping QUnit.test. */ sinon.assert.fail = function ( msg ) { QUnit.assert.ok( false, msg ); @@ -60,70 +73,94 @@ useFakeTimers: false, useFakeServer: false }; + // Extend QUnit.module to provide a Sinon sandbox. ( function () { var orgModule = QUnit.module; - QUnit.module = function ( name, localEnv, executeNow ) { + var orgBeforeEach, orgAfterEach; + if ( QUnit.config.moduleStack.length ) { + // In a nested module, don't re-run our handlers. + return orgModule.apply( this, arguments ); + } if ( arguments.length === 2 && typeof localEnv === 'function' ) { executeNow = localEnv; localEnv = undefined; } localEnv = localEnv || {}; - orgModule( name, { - setup: function () { - var config = sinon.getConfig( sinon.config ); - config.injectInto = this; - sinon.sandbox.create( config ); - - if ( localEnv.setup ) { - localEnv.setup.call( this ); - } - }, - teardown: function () { - if ( localEnv.teardown ) { - localEnv.teardown.call( this ); - } - - if ( this.sandbox ) { - this.sandbox.verifyAndRestore(); - } + orgBeforeEach = localEnv.beforeEach; + orgAfterEach = localEnv.afterEach; + localEnv.beforeEach = function () { + var config = sinon.getConfig( sinon.config ); + config.injectInto = this; + sinon.sandbox.create( config ); + + if ( orgBeforeEach ) { + return orgBeforeEach.apply( this, arguments ); } - }, executeNow ); + }; + localEnv.afterEach = function () { + var ret; + if ( orgAfterEach ) { + ret = orgAfterEach.apply( this, arguments ); + } + + this.sandbox.verifyAndRestore(); + return ret; + }; + return orgModule( name, localEnv, executeNow ); }; }() ); // Extend QUnit.module to provide a fixture element. ( function () { var orgModule = QUnit.module; - QUnit.module = function ( name, localEnv, executeNow ) { - var fixture; - + var orgBeforeEach, orgAfterEach; + if ( QUnit.config.moduleStack.length ) { + // In a nested module, don't re-run our handlers. + return orgModule.apply( this, arguments ); + } if ( arguments.length === 2 && typeof localEnv === 'function' ) { executeNow = localEnv; localEnv = undefined; } 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 ); + orgBeforeEach = localEnv.beforeEach; + orgAfterEach = localEnv.afterEach; + localEnv.beforeEach = function () { + this.fixture = document.createElement( 'div' ); + this.fixture.id = 'qunit-fixture'; + document.body.appendChild( this.fixture ); + + if ( orgBeforeEach ) { + return orgBeforeEach.apply( this, arguments ); } - }, executeNow ); + }; + localEnv.afterEach = function () { + var ret; + if ( orgAfterEach ) { + ret = orgAfterEach.apply( this, arguments ); + } + + this.fixture.parentNode.removeChild( this.fixture ); + return ret; + }; + return orgModule( name, localEnv, executeNow ); + }; + }() ); + + // Extend QUnit.module to normalise localEnv. + // NOTE: This MUST be the last QUnit.module extension so that the above extensions + // may safely modify the object and assume beforeEach/afterEach. + ( function () { + var orgModule = QUnit.module; + QUnit.module = function ( name, localEnv, executeNow ) { + if ( typeof localEnv === 'object' ) { + localEnv = makeSafeEnv( localEnv ); + } + return orgModule( name, localEnv, executeNow ); }; }() ); @@ -190,18 +227,14 @@ ajaxRequests.push( { xhr: jqXHR, options: ajaxOptions } ); } - return function ( localEnv ) { - localEnv = $.extend( { - // QUnit - setup: $.noop, - teardown: $.noop, - // MediaWiki - config: {}, - messages: {} - }, localEnv ); + return function ( orgEnv ) { + var localEnv = orgEnv ? makeSafeEnv( orgEnv ) : {}; + // MediaWiki env testing + localEnv.config = orgEnv && orgEnv.config || {}; + localEnv.messages = orgEnv && orgEnv.messages || {}; return { - setup: function () { + beforeEach: function () { // Greetings, mock environment! mw.config = new MwMap(); mw.config.set( freshConfigCopy( localEnv.config ) ); @@ -218,13 +251,17 @@ // Start tracking ajax requests $( document ).on( 'ajaxSend', trackAjax ); - localEnv.setup.call( this ); + if ( localEnv.beforeEach ) { + return localEnv.beforeEach.apply( this, arguments ); + } }, - teardown: function () { - var timers, pending, $activeLen; + afterEach: function () { + var timers, pending, $activeLen, ret; - localEnv.teardown.call( this ); + if ( localEnv.afterEach ) { + ret = localEnv.afterEach.apply( this, arguments ); + } // Stop tracking ajax requests $( document ).off( 'ajaxSend', trackAjax ); @@ -279,6 +316,8 @@ throw new Error( 'Pending AJAX requests: ' + pending.length + ' (active: ' + $activeLen + ')' ); } + + return ret; } }; }; @@ -352,32 +391,62 @@ // Expect boolean true assertTrue: function ( actual, message ) { - QUnit.push( actual === true, actual, true, message ); + this.pushResult( { + result: actual === true, + actual: actual, + expected: true, + message: message + } ); }, // Expect boolean false assertFalse: function ( actual, message ) { - QUnit.push( actual === false, actual, false, message ); + this.pushResult( { + result: actual === false, + actual: actual, + expected: false, + message: message + } ); }, // Expect numerical value less than X lt: function ( actual, expected, message ) { - QUnit.push( actual < expected, actual, 'less than ' + expected, message ); + this.pushResult( { + result: actual < expected, + actual: actual, + expected: 'less than ' + expected, + message: message + } ); }, // Expect numerical value less than or equal to X ltOrEq: function ( actual, expected, message ) { - QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message ); + this.pushResult( { + result: actual <= expected, + actual: actual, + expected: 'less than or equal to ' + expected, + message: message + } ); }, // Expect numerical value greater than X gt: function ( actual, expected, message ) { - QUnit.push( actual > expected, actual, 'greater than ' + expected, message ); + this.pushResult( { + result: actual > expected, + actual: actual, + expected: 'greater than ' + expected, + message: message + } ); }, // Expect numerical value greater than or equal to X gtOrEq: function ( actual, expected, message ) { - QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message ); + this.pushResult( { + result: actual >= true, + actual: actual, + expected: 'greater than or equal to ' + expected, + message: message + } ); }, /** @@ -390,16 +459,12 @@ htmlEqual: function ( actualHtml, expectedHtml, message ) { var actual = getHtmlStructure( actualHtml ), expected = getHtmlStructure( expectedHtml ); - - QUnit.push( - QUnit.equiv( - actual, - expected - ), - actual, - expected, - message - ); + this.pushResult( { + result: QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message + } ); }, /** @@ -413,15 +478,13 @@ var actual = getHtmlStructure( actualHtml ), expected = getHtmlStructure( expectedHtml ); - QUnit.push( - !QUnit.equiv( - actual, - expected - ), - actual, - expected, - message - ); + this.pushResult( { + result: !QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message, + negative: true + } ); } }; @@ -431,7 +494,7 @@ * Small test suite to confirm proper functionality of the utilities and * initializations defined above in this file. */ - QUnit.module( 'test.mediawiki.qunit.testrunner', QUnit.newMwEnvironment( { + QUnit.module( 'testrunner', QUnit.newMwEnvironment( { setup: function () { this.mwHtmlLive = mw.html; mw.html = { @@ -484,7 +547,7 @@ assert.deepEqual( missing, [], 'Modules in missing state' ); } ); - QUnit.test( 'htmlEqual', function ( assert ) { + QUnit.test( 'assert.htmlEqual', function ( assert ) { assert.htmlEqual( '

Child paragraph with A link

Regular textA span
', '

Child paragraph with A link

Regular textA span
', @@ -531,10 +594,9 @@ 'fooexamplequux', 'Outer text nodes are compared (last text node different)' ); - } ); - QUnit.module( 'test.mediawiki.qunit.testrunner-after', QUnit.newMwEnvironment() ); + QUnit.module( 'testrunner-after', QUnit.newMwEnvironment() ); QUnit.test( 'Teardown', function ( assert ) { assert.equal( mw.html.escape( '<' ), '<', 'teardown() callback was ran.' ); @@ -542,4 +604,46 @@ assert.equal( mw.messages.get( 'testMsg' ), null, 'messages object restored to live in next module()' ); } ); + QUnit.module( 'testrunner-each', { + beforeEach: function () { + this.mwHtmlLive = mw.html; + }, + afterEach: function () { + mw.html = this.mwHtmlLive; + } + } ); + QUnit.test( 'beforeEach', function ( assert ) { + assert.ok( this.mwHtmlLive, 'setup() ran' ); + mw.html = null; + } ); + QUnit.test( 'afterEach', function ( assert ) { + assert.equal( mw.html.escape( '<' ), '<', 'afterEach() ran' ); + } ); + + QUnit.module( 'testrunner-each-compat', { + setup: function () { + this.mwHtmlLive = mw.html; + }, + teardown: function () { + mw.html = this.mwHtmlLive; + } + } ); + QUnit.test( 'setup', function ( assert ) { + assert.ok( this.mwHtmlLive, 'setup() ran' ); + mw.html = null; + } ); + QUnit.test( 'teardown', function ( assert ) { + assert.equal( mw.html.escape( '<' ), '<', 'teardown() ran' ); + } ); + + // Regression test for 'this.sandbox undefined' error, fixed by + // ensuring Sinon setup/teardown is not re-run on inner module. + QUnit.module( 'testrunner-nested', function () { + QUnit.module( 'testrunner-nested-inner', function () { + QUnit.test( 'Dummy', function ( assert ) { + assert.ok( true, 'Nested modules supported' ); + } ); + } ); + } ); + }( jQuery, mediaWiki, QUnit ) );