// and assuming failure.
QUnit.config.testTimeout = 30 * 1000;
+ QUnit.config.requireExpects = true;
+
// Add a checkbox to QUnit header to toggle MediaWiki ResourceLoader debug mode.
QUnit.config.urlConfig.push( {
id: 'debug',
label: 'Enable ResourceLoaderDebug',
- tooltip: 'Enable debug mode in ResourceLoader'
+ tooltip: 'Enable debug mode in ResourceLoader',
+ value: 'true'
} );
- QUnit.config.requireExpects = true;
-
- /**
- * Load TestSwarm agent
- */
- // Only if the current url indicates that there is a TestSwarm instance watching us
- // (TestSwarm appends swarmURL to the test suites url it loads in iframes).
- // Otherwise this is just a simple view of Special:JavaScriptTest/qunit directly,
- // no point in loading inject.js in that case. Also, make sure that this instance
- // of MediaWiki has actually been configured with the required url to that inject.js
- // script. By default it is false.
- if ( QUnit.urlParams.swarmURL && mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) {
- jQuery.getScript( QUnit.fixurl( mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) );
- }
-
/**
* CompletenessTest
*
};
}() );
+ // 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 ) {
* </code>
*/
QUnit.newMwEnvironment = ( function () {
- var warn, log, liveConfig, liveMessages;
+ var warn, error, log, liveConfig, liveMessages,
+ ajaxRequests = [];
liveConfig = mw.config.values;
liveMessages = mw.messages.values;
function suppressWarnings() {
warn = mw.log.warn;
- mw.log.warn = $.noop;
+ error = mw.log.error;
+ mw.log.warn = mw.log.error = $.noop;
}
function restoreWarnings() {
+ // Guard against calls not balanced with suppressWarnings()
if ( warn !== undefined ) {
mw.log.warn = warn;
- warn = undefined;
+ mw.log.error = error;
+ warn = error = undefined;
}
}
return $.extend( /*deep=*/true, {}, liveMessages, custom );
}
+ /**
+ * @param {jQuery.Event} event
+ * @param {jqXHR} jqXHR
+ * @param {Object} ajaxOptions
+ */
+ function trackAjax( event, jqXHR, ajaxOptions ) {
+ ajaxRequests.push( { xhr: jqXHR, options: ajaxOptions } );
+ }
+
log = QUnit.urlParams.mwlogenv ? mw.log : function () {};
return function ( localEnv ) {
this.suppressWarnings = suppressWarnings;
this.restoreWarnings = restoreWarnings;
+ // Start tracking ajax requests
+ $( document ).on( 'ajaxSend', trackAjax );
+
localEnv.setup.call( this );
},
teardown: function () {
- var timers;
+ var timers, active;
log( 'MwEnvironment> TEARDOWN for "' + QUnit.config.current.module
+ ': ' + QUnit.config.current.testName + '"' );
localEnv.teardown.call( this );
+ // Stop tracking ajax requests
+ $( document ).off( 'ajaxSend', trackAjax );
+
// Farewell, mock environment!
mw.config.values = liveConfig;
mw.messages.values = liveMessages;
// still suppressed by the end of the test.
restoreWarnings();
- // Check for incomplete animations/requests/etc and throw
- // error if there are any.
+ // Tests should use fake timers or wait for animations to complete
+ // Check for incomplete animations/requests/etc and throw if there are any.
if ( $.timers && $.timers.length !== 0 ) {
timers = $.timers.length;
- // Tests shoulld use fake timers or wait for animations to complete
$.each( $.timers, function ( i, timer ) {
var node = timer.elem;
mw.log.warn( 'Unfinished animation #' + i + ' in ' + timer.queue + ' queue on ' +
throw new Error( 'Unfinished animations: ' + timers );
}
+
+ // Test should use fake XHR, wait for requests, or call abort()
if ( $.active !== undefined && $.active !== 0 ) {
- // Test may need to use fake XHR, wait for requests or
- // call abort().
- throw new Error( 'Unfinished AJAX requests: ' + $.active );
+ active = $.grep( ajaxRequests, function ( ajax ) {
+ return ajax.xhr.state() === 'pending';
+ } );
+ if ( active.length !== $.active ) {
+ mw.log.warn( 'Pending requests does not match jQuery.active count' );
+ }
+ // Force requests to stop to give the next test a clean start
+ $.each( active, function ( i, ajax ) {
+ mw.log.warn( 'Unfinished AJAX request #' + i, ajax.options );
+ ajax.xhr.abort();
+ } );
+ ajaxRequests = [];
+
+ throw new Error( 'Unfinished AJAX requests: ' + active.length );
}
}
};