mirror of
https://github.com/jquery/jquery.git
synced 2024-10-05 11:34:18 +00:00
1c04178939
Since global variable for callback always would be equal to undefined value it better to check for boolean instead
215 lines
6.0 KiB
JavaScript
215 lines
6.0 KiB
JavaScript
define(function() {
|
|
|
|
// Allow subprojects to test against their own fixtures
|
|
var qunitModule = QUnit.module,
|
|
qunitTest = QUnit.test,
|
|
// Store the old counts so that we only assert on tests that have actually leaked,
|
|
// instead of asserting every time a test has leaked sometime in the past
|
|
oldCacheLength = 0,
|
|
oldActive = 0,
|
|
|
|
expectedDataKeys = {},
|
|
|
|
splice = [].splice,
|
|
reset,
|
|
ajaxSettings = jQuery.ajaxSettings;
|
|
|
|
/**
|
|
* QUnit configuration
|
|
*/
|
|
|
|
// Max time for stop() and asyncTest() until it aborts test
|
|
// and start()'s the next test.
|
|
QUnit.config.testTimeout = 2e4; // 20 seconds
|
|
|
|
// Enforce an "expect" argument or expect() call in all test bodies.
|
|
QUnit.config.requireExpects = true;
|
|
|
|
/**
|
|
* QUnit hooks
|
|
*/
|
|
|
|
function keys(o) {
|
|
var ret, key;
|
|
if ( Object.keys ) {
|
|
ret = Object.keys( o );
|
|
} else {
|
|
ret = [];
|
|
for ( key in o ) {
|
|
ret.push( key );
|
|
}
|
|
}
|
|
ret.sort();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @param {jQuery|HTMLElement|Object|Array} elems Target (or array of targets) for jQuery.data.
|
|
* @param {string} key
|
|
*/
|
|
QUnit.expectJqData = function( elems, key ) {
|
|
var i, elem, expando;
|
|
|
|
// As of jQuery 2.0, there will be no "cache"-data is
|
|
// stored and managed completely below the API surface
|
|
if ( jQuery.cache ) {
|
|
QUnit.current_testEnvironment.checkJqData = true;
|
|
|
|
if ( elems.jquery && elems.toArray ) {
|
|
elems = elems.toArray();
|
|
}
|
|
if ( !supportjQuery.isArray( elems ) ) {
|
|
elems = [ elems ];
|
|
}
|
|
|
|
for ( i = 0; i < elems.length; i++ ) {
|
|
elem = elems[i];
|
|
|
|
// jQuery.data only stores data for nodes in jQuery.cache,
|
|
// for other data targets the data is stored in the object itself,
|
|
// in that case we can't test that target for memory leaks.
|
|
// But we don't have to since in that case the data will/must will
|
|
// be available as long as the object is not garbage collected by
|
|
// the js engine, and when it is, the data will be removed with it.
|
|
if ( !elem.nodeType ) {
|
|
// Fixes false positives for dataTests(window), dataTests({}).
|
|
continue;
|
|
}
|
|
|
|
expando = elem[ jQuery.expando ];
|
|
|
|
if ( expando === undefined ) {
|
|
// In this case the element exists fine, but
|
|
// jQuery.data (or internal data) was never (in)directly
|
|
// called.
|
|
// Since this method was called it means some data was
|
|
// expected to be found, but since there is nothing, fail early
|
|
// (instead of in teardown).
|
|
notStrictEqual( expando, undefined, "Target for expectJqData must have an expando, for else there can be no data to expect." );
|
|
} else {
|
|
if ( expectedDataKeys[expando] ) {
|
|
expectedDataKeys[expando].push( key );
|
|
} else {
|
|
expectedDataKeys[expando] = [ key ];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
QUnit.config.urlConfig.push({
|
|
id: "jqdata",
|
|
label: "Always check jQuery.data",
|
|
tooltip: "Trigger QUnit.expectJqData detection for all tests instead of just the ones that call it"
|
|
});
|
|
|
|
/**
|
|
* Ensures that tests have cleaned up properly after themselves. Should be passed as the
|
|
* teardown function on all modules' lifecycle object.
|
|
*/
|
|
window.moduleTeardown = function() {
|
|
var i,
|
|
expectedKeys, actualKeys,
|
|
cacheLength = 0;
|
|
|
|
// Only look for jQuery data problems if this test actually
|
|
// provided some information to compare against.
|
|
if ( QUnit.urlParams.jqdata || this.checkJqData ) {
|
|
for ( i in jQuery.cache ) {
|
|
expectedKeys = expectedDataKeys[i];
|
|
actualKeys = jQuery.cache[i] ? keys( jQuery.cache[i] ) : jQuery.cache[i];
|
|
if ( !QUnit.equiv( expectedKeys, actualKeys ) ) {
|
|
deepEqual( actualKeys, expectedKeys, "Expected keys exist in jQuery.cache" );
|
|
}
|
|
delete jQuery.cache[i];
|
|
delete expectedDataKeys[i];
|
|
}
|
|
// In case it was removed from cache before (or never there in the first place)
|
|
for ( i in expectedDataKeys ) {
|
|
deepEqual( expectedDataKeys[i], undefined, "No unexpected keys were left in jQuery.cache (#" + i + ")" );
|
|
delete expectedDataKeys[i];
|
|
}
|
|
}
|
|
|
|
// Reset data register
|
|
expectedDataKeys = {};
|
|
|
|
// Check for (and clean up, if possible) incomplete animations/requests/etc.
|
|
if ( jQuery.timers && jQuery.timers.length !== 0 ) {
|
|
equal( jQuery.timers.length, 0, "No timers are still running" );
|
|
splice.call( jQuery.timers, 0, jQuery.timers.length );
|
|
jQuery.fx.stop();
|
|
}
|
|
if ( jQuery.active !== undefined && jQuery.active !== oldActive ) {
|
|
equal( jQuery.active, oldActive, "No AJAX requests are still active" );
|
|
if ( ajaxTest.abort ) {
|
|
ajaxTest.abort("active requests");
|
|
}
|
|
oldActive = jQuery.active;
|
|
}
|
|
|
|
reset();
|
|
|
|
for ( i in jQuery.cache ) {
|
|
++cacheLength;
|
|
}
|
|
|
|
// Because QUnit doesn't have a mechanism for retrieving the number of expected assertions for a test,
|
|
// if we unconditionally assert any of these, the test will fail with too many assertions :|
|
|
if ( cacheLength !== oldCacheLength ) {
|
|
equal( cacheLength, oldCacheLength, "No unit tests leak memory in jQuery.cache" );
|
|
oldCacheLength = cacheLength;
|
|
}
|
|
};
|
|
|
|
QUnit.done(function() {
|
|
// Remove our own fixtures outside #qunit-fixture
|
|
supportjQuery("#qunit ~ *").remove();
|
|
});
|
|
|
|
// jQuery-specific post-test cleanup
|
|
reset = function() {
|
|
|
|
// Ensure jQuery events and data on the fixture are properly removed
|
|
jQuery("#qunit-fixture").empty();
|
|
// ...even if the jQuery under test has a broken .empty()
|
|
supportjQuery("#qunit-fixture").empty();
|
|
|
|
// Reset internal jQuery state
|
|
jQuery.event.global = {};
|
|
if ( ajaxSettings ) {
|
|
jQuery.ajaxSettings = jQuery.extend( true, {}, ajaxSettings );
|
|
} else {
|
|
delete jQuery.ajaxSettings;
|
|
}
|
|
|
|
// Cleanup globals
|
|
Globals.cleanup();
|
|
};
|
|
|
|
QUnit.testDone(reset);
|
|
|
|
// Register globals for cleanup and the cleanup code itself
|
|
// Explanation at http://perfectionkills.com/understanding-delete/#ie_bugs
|
|
window.Globals = (function() {
|
|
var globals = {};
|
|
return {
|
|
register: function( name ) {
|
|
globals[ name ] = true;
|
|
supportjQuery.globalEval( "var " + name + " = true;" );
|
|
},
|
|
cleanup: function() {
|
|
var name,
|
|
current = globals;
|
|
globals = {};
|
|
for ( name in current ) {
|
|
supportjQuery.globalEval( "try { " +
|
|
"delete " + ( supportjQuery.support.deleteExpando ? "window['" + name + "']" : name ) +
|
|
"; } catch( x ) {}" );
|
|
}
|
|
}
|
|
};
|
|
})();
|
|
|
|
});
|