diff options
60 files changed, 2566 insertions, 1859 deletions
diff --git a/.travis.yml b/.travis.yml index aaae4185b..317c3a854 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,5 @@ node_js: - "6" - "8" - "9" +addons: + chrome: stable diff --git a/Gruntfile.js b/Gruntfile.js index edcdb4f15..19e94fad7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -147,6 +147,88 @@ module.exports = function( grunt ) { "tween" ] }, + karma: { + options: { + customContextFile: "test/karma.context.html", + customDebugFile: "test/karma.debug.html", + frameworks: [ "qunit" ], + middleware: [ "mockserver" ], + plugins: [ + "karma-*", + { + "middleware:mockserver": [ + "factory", + require( "./test/middleware-mockserver.js" ) + ] + } + ], + files: [ + "test/data/jquery-1.9.1.js", + "external/qunit-assert-step/qunit-assert-step.js", + "external/sinon/sinon.js", + "external/npo/npo.js", + "external/requirejs/require.js", + "test/data/testinit.js", + + "dist/jquery.min.js", + + // Replacement for testinit.js#loadTests() + "test/data/testrunner.js", + "test/unit/basic.js", + "test/unit/core.js", + "test/unit/callbacks.js", + "test/unit/deferred.js", + "test/unit/deprecated.js", + "test/unit/support.js", + "test/unit/data.js", + "test/unit/queue.js", + "test/unit/attributes.js", + "test/unit/event.js", + "test/unit/selector.js", + "test/unit/traversing.js", + "test/unit/manipulation.js", + "test/unit/wrap.js", + "test/unit/css.js", + "test/unit/serialize.js", + "test/unit/ajax.js", + "test/unit/effects.js", + "test/unit/offset.js", + "test/unit/dimensions.js", + "test/unit/animation.js", + "test/unit/tween.js", + "test/unit/ready.js", + + { pattern: "dist/jquery.js", included: false, served: true }, + { pattern: "dist/*.map", included: false, served: true }, + { pattern: "external/qunit/qunit.css", included: false, served: true }, + { + pattern: "test/**/*.@(js|css|jpg|html|xml)", + included: false, + served: true + } + ], + reporters: [ "dots" ], + autoWatch: false, + concurrency: 3, + captureTimeout: 20 * 1000, + + // To debug tests with Karma: + // - Run 'grunt karma:chrome' or 'grunt karma:firefox' + // (any karma subtask that has singleRun=false) + // - Press "Debug" in the opened browser window. + singleRun: false + }, + main: { + browsers: [ "ChromeHeadless" ], + singleRun: true + }, + chrome: { + browsers: [ "Chrome" ] + }, + firefox: { + browsers: [ "Firefox" ] + } + }, watch: { files: [ "<%= eslint.dev.src %>" ], tasks: [ "dev" ] @@ -222,6 +304,7 @@ module.exports = function( grunt ) { "newer:uglify", "remove_map_comment", "dist:*", + "qunit_fixture", "compare_size" ] ); @@ -231,6 +314,7 @@ module.exports = function( grunt ) { "uglify", "remove_map_comment", "dist:*", + "qunit_fixture", "eslint:dist", "test:fast", "compare_size" @@ -323,20 +323,20 @@ fireNative( jQuery("#elem")[0], "click" ); ### Add random number to url to stop caching ### ```js -url( "some/url.php" ); +url( "some/url" ); ``` Example: ```js -url("data/test.html"); +url("index.html"); -=> "data/test.html?10538358428943" +=> "data/index.html?10538358428943" -url("data/test.php?foo=bar"); +url("mock.php?foo=bar"); -=> "data/test.php?foo=bar&10538358345554" +=> "data/mock.php?foo=bar&10538358345554" ``` diff --git a/build/tasks/qunit_fixture.js b/build/tasks/qunit_fixture.js new file mode 100644 index 000000000..ebf0b220c --- /dev/null +++ b/build/tasks/qunit_fixture.js @@ -0,0 +1,22 @@ +var fs = require( "fs" ); + +module.exports = function( grunt ) { + grunt.registerTask( "qunit_fixture", function() { + var dest = "./test/data/qunit-fixture.js"; + fs.writeFileSync( + dest, + "// Generated by build/tasks/qunit_fixture.js\n" + + "QUnit.config.fixture = " + + JSON.stringify( + fs.readFileSync( + "./test/data/qunit-fixture.html", + "utf8" + ).toString() + ) + + ";\n" + + "// Compat with QUnit 1.x:\n" + + "document.getElementById( \"qunit-fixture\" ).innerHTML = QUnit.config.fixture;\n" + ); + grunt.log.ok( "Updated " + dest + "." ); + } ); +}; diff --git a/external/qunit/qunit.css b/external/qunit/qunit.css index a59e2824c..ae68fc412 100644 --- a/external/qunit/qunit.css +++ b/external/qunit/qunit.css @@ -1,12 +1,12 @@ /*! - * QUnit 1.20.0 - * http://qunitjs.com/ + * QUnit 1.23.1 + * https://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://jquery.org/license * - * Date: 2015-10-27T17:53Z + * Date: 2016-04-12T17:29Z */ /** Font Family and Sizes */ @@ -120,6 +120,10 @@ display: list-item; } +#qunit-tests.hidepass { + position: relative; +} + #qunit-tests.hidepass li.running, #qunit-tests.hidepass li.pass { visibility: hidden; diff --git a/external/qunit/qunit.js b/external/qunit/qunit.js index 904943f08..5df0822ea 100644 --- a/external/qunit/qunit.js +++ b/external/qunit/qunit.js @@ -1,15 +1,15 @@ /*! - * QUnit 1.20.0 - * http://qunitjs.com/ + * QUnit 1.23.1 + * https://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://jquery.org/license * - * Date: 2015-10-27T17:53Z + * Date: 2016-04-12T17:29Z */ -(function( global ) { +( function( global ) { var QUnit = {}; @@ -27,7 +27,7 @@ var window = global.window; var defined = { document: window && window.document !== undefined, setTimeout: setTimeout !== undefined, - sessionStorage: (function() { + sessionStorage: ( function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); @@ -46,7 +46,7 @@ var runStarted = false; var toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty; -// returns a new Array with the elements that are in a but not in b +// Returns a new Array with the elements that are in a but not in b function diff( a, b ) { var i, j, result = a.slice(); @@ -63,7 +63,7 @@ function diff( a, b ) { return result; } -// from jquery.js +// From jquery.js function inArray( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); @@ -157,31 +157,6 @@ function is( type, obj ) { return QUnit.objectType( obj ) === type; } -var getUrlParams = function() { - var i, current; - var urlParams = {}; - var location = window.location; - var params = location.search.slice( 1 ).split( "&" ); - var length = params.length; - - if ( params[ 0 ] ) { - for ( i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - if ( urlParams[ current[ 0 ] ] ) { - urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); - } else { - urlParams[ current[ 0 ] ] = current[ 1 ]; - } - } - } - - return urlParams; -}; - // Doesn't support IE6 to IE9, it will return undefined on these browsers // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { @@ -211,12 +186,12 @@ function extractStacktrace( e, offset ) { // Support: Safari <=6 only } else if ( e.sourceURL ) { - // exclude useless self-reference for generated Error objects + // Exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; } - // for actual exceptions, this is useful + // For actual exceptions, this is useful return e.sourceURL + ":" + e.line; } } @@ -243,53 +218,35 @@ function sourceFromStacktrace( offset ) { * `config` initialized at top of scope */ var config = { + // The queue of tests to run queue: [], - // block until document ready + // Block until document ready blocking: true, - // by default, run previously failed tests first + // By default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, - // by default, modify document.title when suite is done + // By default, modify document.title when suite is done altertitle: true, // HTML Reporter: collapse every test except the first failing test // If false, all failing tests will be expanded collapse: true, - // by default, scroll to top of the page when suite is done + // By default, scroll to top of the page when suite is done scrolltop: true, - // depth up-to which object will be dumped + // Depth up-to which object will be dumped maxDepth: 5, - // when enabled, all tests must call expect() + // When enabled, all tests must call expect() requireExpects: false, - // add checkboxes that are persisted in the query-string - // when enabled, the id is set to `true` as a `QUnit.config` property - urlConfig: [ - { - id: "hidepassed", - label: "Hide passed tests", - tooltip: "Only show tests and assertions that fail. Stored as query-strings." - }, - { - id: "noglobals", - label: "Check for Globals", - tooltip: "Enabling this will test if any test introduces new properties on the " + - "global object (`window` in Browsers). Stored as query-strings." - }, - { - id: "notrycatch", - label: "No try-catch", - tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + - "exceptions in IE reasonable. Stored as query-strings." - } - ], + // Placeholder for user-configurable form-exposed URL parameters + urlConfig: [], // Set of all modules. modules: [], @@ -306,27 +263,9 @@ var config = { callbacks: {} }; -var urlParams = defined.document ? getUrlParams() : {}; - // Push a loose unnamed module to the modules collection config.modules.push( config.currentModule ); -if ( urlParams.filter === true ) { - delete urlParams.filter; -} - -// String search anywhere in moduleName+testName -config.filter = urlParams.filter; - -config.testId = []; -if ( urlParams.testId ) { - // Ensure that urlParams.testId is an array - urlParams.testId = decodeURIComponent( urlParams.testId ).split( "," ); - for (var i = 0; i < urlParams.testId.length; i++ ) { - config.testId.push( urlParams.testId[ i ] ); - } -} - var loggingCallbacks = {}; // Register logging callbacks @@ -396,7 +335,7 @@ function verifyLoggingCallbacks() { global.console.warn( "QUnit." + loggingCallback + " was replaced with a new value.\n" + "Please, check out the documentation on how to apply logging callbacks.\n" + - "Reference: http://api.qunitjs.com/category/callbacks/" + "Reference: https://api.qunitjs.com/category/callbacks/" ); } } @@ -430,7 +369,7 @@ function verifyLoggingCallbacks() { } QUnit.pushFailure( error, filePath + ":" + linerNr ); } else { - QUnit.test( "global failure", extend(function() { + QUnit.test( "global failure", extend( function() { QUnit.pushFailure( error, filePath + ":" + linerNr ); }, { validTest: true } ) ); } @@ -439,25 +378,23 @@ function verifyLoggingCallbacks() { return ret; }; -} )(); - -QUnit.urlParams = urlParams; +}() ); // Figure out if we're running the tests from a server or not QUnit.isLocal = !( defined.document && window.location.protocol !== "file:" ); // Expose the current QUnit version -QUnit.version = "1.20.0"; +QUnit.version = "1.23.1"; extend( QUnit, { - // call on start of module test to prepend name to all tests + // Call on start of module test to prepend name to all tests module: function( name, testEnvironment, executeNow ) { var module, moduleFns; var currentModule = config.currentModule; if ( arguments.length === 2 ) { - if ( testEnvironment instanceof Function ) { + if ( objectType( testEnvironment ) === "function" ) { executeNow = testEnvironment; testEnvironment = undefined; } @@ -481,7 +418,7 @@ extend( QUnit, { afterEach: setHook( module, "afterEach" ) }; - if ( executeNow instanceof Function ) { + if ( objectType( executeNow ) === "function" ) { config.moduleStack.push( module ); setCurrentModule( module ); executeNow.call( module.testEnvironment, moduleFns ); @@ -499,7 +436,8 @@ extend( QUnit, { var module = { name: moduleName, parentModule: parentModule, - tests: [] + tests: [], + moduleId: generateHash( moduleName ) }; var env = {}; @@ -572,7 +510,7 @@ extend( QUnit, { return; } - // throw an Error if start is called more often than stop + // Throw an Error if start is called more often than stop if ( config.current.semaphore < 0 ) { config.current.semaphore = 0; @@ -633,7 +571,7 @@ extend( QUnit, { offset = ( offset || 0 ) + 2; return sourceFromStacktrace( offset ); } -}); +} ); registerLoggingCallbacks( QUnit ); @@ -656,17 +594,17 @@ function begin() { // Avoid unnecessary information by not logging modules' test environments for ( i = 0, l = config.modules.length; i < l; i++ ) { - modulesLog.push({ + modulesLog.push( { name: config.modules[ i ].name, tests: config.modules[ i ].tests - }); + } ); } // The test run is officially beginning now runLoggingCallbacks( "begin", { totalTests: Test.count, modules: modulesLog - }); + } ); } config.blocking = false; @@ -705,7 +643,7 @@ function pauseProcessing() { if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); - config.timeout = setTimeout(function() { + config.timeout = setTimeout( function() { if ( config.current ) { config.current.semaphore = 0; QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); @@ -722,7 +660,7 @@ function resumeProcessing() { // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.) if ( defined.setTimeout ) { - setTimeout(function() { + setTimeout( function() { if ( config.current && config.current.semaphore > 0 ) { return; } @@ -751,7 +689,7 @@ function done() { passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started - }); + } ); } delete config.previousModule; @@ -763,7 +701,7 @@ function done() { passed: passed, total: config.stats.all, runtime: runtime - }); + } ); } function setHook( module, hookName ) { @@ -777,6 +715,8 @@ function setHook( module, hookName ) { } var focused = false; +var priorityCount = 0; +var unitSampler; function Test( settings ) { var i, l; @@ -799,10 +739,10 @@ function Test( settings ) { this.testId = generateHash( this.module.name, this.testName ); - this.module.tests.push({ + this.module.tests.push( { name: this.testName, testId: this.testId - }); + } ); if ( settings.skip ) { @@ -838,14 +778,14 @@ Test.prototype = { passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started - }); + } ); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0, started: now() }; runLoggingCallbacks( "moduleStart", { name: this.module.name, tests: this.module.tests - }); + } ); } config.current = this; @@ -861,7 +801,7 @@ Test.prototype = { name: this.testName, module: this.module.name, testId: this.testId - }); + } ); if ( !config.pollution ) { saveGlobal(); @@ -890,7 +830,7 @@ Test.prototype = { this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); - // else next test will carry the responsibility + // Else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking @@ -999,7 +939,7 @@ Test.prototype = { // DEPRECATED: this property will be removed in 2.0.0, use runtime instead duration: this.runtime - }); + } ); // QUnit.reset() is deprecated and will be replaced for a new // fixture reset function on QUnit 2.0/2.1. @@ -1019,8 +959,8 @@ Test.prototype = { function run() { - // each of these can by async - synchronize([ + // Each of these can by async + synchronize( [ function() { test.before(); }, @@ -1038,31 +978,33 @@ Test.prototype = { function() { test.finish(); } - ]); + ] ); } // Prioritize previously failed tests, detected from sessionStorage priority = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName ); - return synchronize( run, priority ); + return synchronize( run, priority, config.seed ); }, - push: function( result, actual, expected, message, negative ) { + pushResult: function( resultInfo ) { + + // Destructure of resultInfo = { result, actual, expected, message, negative } var source, details = { module: this.module.name, name: this.testName, - result: result, - message: message, - actual: actual, - expected: expected, + result: resultInfo.result, + message: resultInfo.message, + actual: resultInfo.actual, + expected: resultInfo.expected, testId: this.testId, - negative: negative || false, + negative: resultInfo.negative || false, runtime: now() - this.started }; - if ( !result ) { + if ( !resultInfo.result ) { source = sourceFromStacktrace(); if ( source ) { @@ -1072,10 +1014,10 @@ Test.prototype = { runLoggingCallbacks( "log", details ); - this.assertions.push({ - result: !!result, - message: message - }); + this.assertions.push( { + result: !!resultInfo.result, + message: resultInfo.message + } ); }, pushFailure: function( message, source, actual ) { @@ -1100,10 +1042,10 @@ Test.prototype = { runLoggingCallbacks( "log", details ); - this.assertions.push({ + this.assertions.push( { result: false, message: message - }); + } ); }, resolvePromise: function( promise, phase ) { @@ -1122,7 +1064,7 @@ Test.prototype = { " " + test.testName + ": " + ( error.message || error ); test.pushFailure( message, extractStacktrace( error, 0 ) ); - // else next test will carry the responsibility + // Else next test will carry the responsibility saveGlobal(); // Unblock @@ -1134,32 +1076,45 @@ Test.prototype = { }, valid: function() { - var include, - filter = config.filter && config.filter.toLowerCase(), - module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(), - fullName = ( this.module.name + ": " + this.testName ).toLowerCase(); + var filter = config.filter, + regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec( filter ), + module = config.module && config.module.toLowerCase(), + fullName = ( this.module.name + ": " + this.testName ); - function testInModuleChain( testModule ) { + function moduleChainNameMatch( testModule ) { var testModuleName = testModule.name ? testModule.name.toLowerCase() : null; if ( testModuleName === module ) { return true; } else if ( testModule.parentModule ) { - return testInModuleChain( testModule.parentModule ); + return moduleChainNameMatch( testModule.parentModule ); } else { return false; } } + function moduleChainIdMatch( testModule ) { + return inArray( testModule.moduleId, config.moduleId ) > -1 || + testModule.parentModule && moduleChainIdMatch( testModule.parentModule ); + } + // Internally-generated tests are always valid if ( this.callback && this.callback.validTest ) { return true; } - if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) { + if ( config.moduleId && config.moduleId.length > 0 && + !moduleChainIdMatch( this.module ) ) { + + return false; + } + + if ( config.testId && config.testId.length > 0 && + inArray( this.testId, config.testId ) < 0 ) { + return false; } - if ( module && !testInModuleChain( this.module ) ) { + if ( module && !moduleChainNameMatch( this.module ) ) { return false; } @@ -1167,7 +1122,23 @@ Test.prototype = { return true; } - include = filter.charAt( 0 ) !== "!"; + return regexFilter ? + this.regexFilter( !!regexFilter[ 1 ], regexFilter[ 2 ], regexFilter[ 3 ], fullName ) : + this.stringFilter( filter, fullName ); + }, + + regexFilter: function( exclude, pattern, flags, fullName ) { + var regex = new RegExp( pattern, flags ); + var match = regex.test( fullName ); + + return match !== exclude; + }, + + stringFilter: function( filter, fullName ) { + filter = filter.toLowerCase(); + fullName = fullName.toLowerCase(); + + var include = filter.charAt( 0 ) !== "!"; if ( !include ) { filter = filter.slice( 1 ); } @@ -1240,8 +1211,9 @@ function generateHash( module, testName ) { return hex.slice( -8 ); } -function synchronize( callback, priority ) { - var last = !priority; +function synchronize( callback, priority, seed ) { + var last = !priority, + index; if ( QUnit.objectType( callback ) === "array" ) { while ( callback.length ) { @@ -1251,7 +1223,15 @@ function synchronize( callback, priority ) { } if ( priority ) { - priorityFill( callback ); + config.queue.splice( priorityCount++, 0, callback ); + } else if ( seed ) { + if ( !unitSampler ) { + unitSampler = unitSamplerGenerator( seed ); + } + + // Insert into a random position after all priority items + index = Math.floor( unitSampler() * ( config.queue.length - priorityCount + 1 ) ); + config.queue.splice( priorityCount + index, 0, callback ); } else { config.queue.push( callback ); } @@ -1261,21 +1241,24 @@ function synchronize( callback, priority ) { } } -// Place previously failed tests on a queue priority line, respecting the order they get assigned. -function priorityFill( callback ) { - var queue, prioritizedQueue; - - queue = config.queue.slice( priorityFill.pos ); - prioritizedQueue = config.queue.slice( 0, -config.queue.length + priorityFill.pos ); +function unitSamplerGenerator( seed ) { - queue.unshift( callback ); - queue.unshift.apply( queue, prioritizedQueue ); + // 32-bit xorshift, requires only a nonzero seed + // http://excamera.com/sphinx/article-xorshift.html + var sample = parseInt( generateHash( seed ), 16 ) || -1; + return function() { + sample ^= sample << 13; + sample ^= sample >>> 17; + sample ^= sample << 5; - config.queue = queue; + // ECMAScript has no unsigned number type + if ( sample < 0 ) { + sample += 0x100000000; + } - priorityFill.pos += 1; + return sample / 0x100000000; + }; } -priorityFill.pos = 0; function saveGlobal() { config.pollution = []; @@ -1284,7 +1267,7 @@ function saveGlobal() { for ( var key in global ) { if ( hasOwn.call( global, key ) ) { - // in Opera sometimes DOM element ids show up here, ignore them + // In Opera sometimes DOM element ids show up here, ignore them if ( /^qunit-test-output/.test( key ) ) { continue; } @@ -1333,12 +1316,12 @@ function test( testName, expected, callback, async ) { expected = null; } - newTest = new Test({ + newTest = new Test( { testName: testName, expected: expected, async: async, callback: callback - }); + } ); newTest.queue(); } @@ -1347,10 +1330,10 @@ function test( testName, expected, callback, async ) { function skip( testName ) { if ( focused ) { return; } - var test = new Test({ + var test = new Test( { testName: testName, skip: true - }); + } ); test.queue(); } @@ -1369,12 +1352,12 @@ function only( testName, expected, callback, async ) { expected = null; } - newTest = new Test({ + newTest = new Test( { testName: testName, expected: expected, async: async, callback: callback - }); + } ); newTest.queue(); } @@ -1430,7 +1413,21 @@ QUnit.assert = Assert.prototype = { }, // Exports test.push() to the user API - push: function( /* result, actual, expected, message, negative */ ) { + // Alias of pushResult. + push: function( result, actual, expected, message, negative ) { + var currentAssert = this instanceof Assert ? this : QUnit.config.current.assert; + return currentAssert.pushResult( { + result: result, + actual: actual, + expected: expected, + message: message, + negative: negative + } ); + }, + + pushResult: function( resultInfo ) { + + // Destructure of resultInfo = { result, actual, expected, message, negative } var assert = this, currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current; @@ -1453,57 +1450,112 @@ QUnit.assert = Assert.prototype = { if ( !( assert instanceof Assert ) ) { assert = currentTest.assert; } - return assert.test.push.apply( assert.test, arguments ); + + return assert.test.pushResult( resultInfo ); }, ok: function( result, message ) { message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + QUnit.dump.parse( result ) ); - this.push( !!result, result, true, message ); + this.pushResult( { + result: !!result, + actual: result, + expected: true, + message: message + } ); }, notOk: function( result, message ) { message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " + QUnit.dump.parse( result ) ); - this.push( !result, result, false, message, true ); + this.pushResult( { + result: !result, + actual: result, + expected: false, + message: message + } ); }, equal: function( actual, expected, message ) { /*jshint eqeqeq:false */ - this.push( expected == actual, actual, expected, message ); + this.pushResult( { + result: expected == actual, + actual: actual, + expected: expected, + message: message + } ); }, notEqual: function( actual, expected, message ) { /*jshint eqeqeq:false */ - this.push( expected != actual, actual, expected, message, true ); + this.pushResult( { + result: expected != actual, + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, propEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); - this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + this.pushResult( { + result: QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message + } ); }, notPropEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); - this.push( !QUnit.equiv( actual, expected ), actual, expected, message, true ); + this.pushResult( { + result: !QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, deepEqual: function( actual, expected, message ) { - this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + this.pushResult( { + result: QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message + } ); }, notDeepEqual: function( actual, expected, message ) { - this.push( !QUnit.equiv( actual, expected ), actual, expected, message, true ); + this.pushResult( { + result: !QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, strictEqual: function( actual, expected, message ) { - this.push( expected === actual, actual, expected, message ); + this.pushResult( { + result: expected === actual, + actual: actual, + expected: expected, + message: message + } ); }, notStrictEqual: function( actual, expected, message ) { - this.push( expected !== actual, actual, expected, message, true ); + this.pushResult( { + result: expected !== actual, + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, "throws": function( block, expected, message ) { @@ -1521,7 +1573,7 @@ QUnit.assert = Assert.prototype = { currentTest.ignoreGlobalErrors = true; try { block.call( currentTest.testEnvironment ); - } catch (e) { + } catch ( e ) { actual = e; } currentTest.ignoreGlobalErrors = false; @@ -1529,46 +1581,51 @@ QUnit.assert = Assert.prototype = { if ( actual ) { expectedType = QUnit.objectType( expected ); - // we don't want to validate thrown error + // We don't want to validate thrown error if ( !expected ) { ok = true; expectedOutput = null; - // expected is a regexp + // Expected is a regexp } else if ( expectedType === "regexp" ) { ok = expected.test( errorString( actual ) ); - // expected is a string + // Expected is a string } else if ( expectedType === "string" ) { ok = expected === errorString( actual ); - // expected is a constructor, maybe an Error constructor + // Expected is a constructor, maybe an Error constructor } else if ( expectedType === "function" && actual instanceof expected ) { ok = true; - // expected is an Error object + // Expected is an Error object } else if ( expectedType === "object" ) { ok = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message; - // expected is a validation function which returns true if validation passed + // Expected is a validation function which returns true if validation passed } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) { expectedOutput = null; ok = true; } } - currentTest.assert.push( ok, actual, expectedOutput, message ); + currentTest.assert.pushResult( { + result: ok, + actual: actual, + expected: expectedOutput, + message: message + } ); } }; // Provide an alternative to assert.throws(), for environments that consider throws a reserved word // Known to us are: Closure Compiler, Narwhal -(function() { +( function() { /*jshint sub:true */ - Assert.prototype.raises = Assert.prototype[ "throws" ]; -}()); + Assert.prototype.raises = Assert.prototype [ "throws" ]; //jscs:ignore requireDotNotation +}() ); function errorString( error ) { var name, message, @@ -1592,7 +1649,7 @@ function errorString( error ) { // Test for equality any JavaScript type. // Author: Philippe Rathé <prathe@gmail.com> -QUnit.equiv = (function() { +QUnit.equiv = ( function() { // Stack to decide between skip/abort functions var callers = []; @@ -1601,26 +1658,28 @@ QUnit.equiv = (function() { var parents = []; var parentsB = []; - function useStrictEquality( b, a ) { + var getProto = Object.getPrototypeOf || function( obj ) { - /*jshint eqeqeq:false */ - if ( b instanceof a.constructor || a instanceof b.constructor ) { + /*jshint proto: true */ + return obj.__proto__; + }; - // To catch short annotation VS 'new' annotation of a declaration. e.g.: - // `var i = 1;` - // `var j = new Number(1);` - return a == b; - } else { - return a === b; + function useStrictEquality( b, a ) { + + // To catch short annotation VS 'new' annotation of a declaration. e.g.: + // `var i = 1;` + // `var j = new Number(1);` + if ( typeof a === "object" ) { + a = a.valueOf(); + } + if ( typeof b === "object" ) { + b = b.valueOf(); } + + return a === b; } function compareConstructors( a, b ) { - var getProto = Object.getPrototypeOf || function( obj ) { - - /*jshint proto: true */ - return obj.__proto__; - }; var protoA = getProto( a ); var protoB = getProto( b ); @@ -1649,6 +1708,10 @@ QUnit.equiv = (function() { return false; } + function getRegExpFlags( regexp ) { + return "flags" in regexp ? regexp.flags : regexp.toString().match( /[gimuy]*$/ )[ 0 ]; + } + var callbacks = { "string": useStrictEquality, "boolean": useStrictEquality, @@ -1656,28 +1719,17 @@ QUnit.equiv = (function() { "null": useStrictEquality, "undefined": useStrictEquality, "symbol": useStrictEquality, + "date": useStrictEquality, - "nan": function( b ) { - return isNaN( b ); - }, - - "date": function( b, a ) { - return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + "nan": function() { + return true; }, "regexp": function( b, a ) { - return QUnit.objectType( b ) === "regexp" && - - // The regex itself - a.source === b.source && - - // And its modifiers - a.global === b.global && + return a.source === b.source && - // (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline && - a.sticky === b.sticky; + // Include flags in the comparison + getRegExpFlags( a ) === getRegExpFlags( b ); }, // - skip when the property is a method of an instance (OOP) @@ -1691,14 +1743,10 @@ QUnit.equiv = (function() { "array": function( b, a ) { var i, j, len, loop, aCircular, bCircular; - // b could be an object literal here - if ( QUnit.objectType( b ) !== "array" ) { - return false; - } - len = a.length; if ( len !== b.length ) { - // safe and faster + + // Safe and faster return false; } @@ -1732,43 +1780,53 @@ QUnit.equiv = (function() { }, "set": function( b, a ) { - var aArray, bArray; + var innerEq, + outerEq = true; - // `b` could be any object here - if ( QUnit.objectType( b ) !== "set" ) { + if ( a.size !== b.size ) { return false; } - aArray = []; - a.forEach( function( v ) { - aArray.push( v ); - }); - bArray = []; - b.forEach( function( v ) { - bArray.push( v ); - }); + a.forEach( function( aVal ) { + innerEq = false; + + b.forEach( function( bVal ) { + if ( innerEquiv( bVal, aVal ) ) { + innerEq = true; + } + } ); + + if ( !innerEq ) { + outerEq = false; + } + } ); - return innerEquiv( bArray, aArray ); + return outerEq; }, "map": function( b, a ) { - var aArray, bArray; + var innerEq, + outerEq = true; - // `b` could be any object here - if ( QUnit.objectType( b ) !== "map" ) { + if ( a.size !== b.size ) { return false; } - aArray = []; - a.forEach( function( v, k ) { - aArray.push( [ k, v ] ); - }); - bArray = []; - b.forEach( function( v, k ) { - bArray.push( [ k, v ] ); - }); + a.forEach( function( aVal, aKey ) { + innerEq = false; + + b.forEach( function( bVal, bKey ) { + if ( innerEquiv( [ bVal, bKey ], [ aVal, aKey ] ) ) { + innerEq = true; + } + } ); - return innerEquiv( bArray, aArray ); + if ( !innerEq ) { + outerEq = false; + } + } ); + + return outerEq; }, "object": function( b, a ) { @@ -1830,45 +1888,31 @@ QUnit.equiv = (function() { }; function typeEquiv( a, b ) { - var prop = QUnit.objectType( a ); - return callbacks[ prop ]( b, a ); + var type = QUnit.objectType( a ); + return QUnit.objectType( b ) === type && callbacks[ type ]( b, a ); } // The real equiv function - function innerEquiv() { - var args = [].slice.apply( arguments ); - if ( args.length < 2 ) { + function innerEquiv( a, b ) { - // End transition + // We're done when there's nothing more to compare + if ( arguments.length < 2 ) { return true; } - return ( (function( a, b ) { - if ( a === b ) { + // Require type-specific equality + return ( a === b || typeEquiv( a, b ) ) && - // Catch the most you can - return true; - } else if ( a === null || b === null || typeof a === "undefined" || - typeof b === "undefined" || - QUnit.objectType( a ) !== QUnit.objectType( b ) ) { - - // Don't lose time with error prone cases - return false; - } else { - return typeEquiv( a, b ); - } - - // Apply transition with (1..n) arguments - }( args[ 0 ], args[ 1 ] ) ) && - innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) ); + // ...across all consecutive argument pairs + ( arguments.length === 2 || innerEquiv.apply( this, [].slice.call( arguments, 1 ) ) ); } return innerEquiv; -}()); +}() ); // Based on jsDump by Ariel Flesler // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html -QUnit.dump = (function() { +QUnit.dump = ( function() { function quote( str ) { return "\"" + str.toString().replace( /\\/g, "\\\\" ).replace( /"/g, "\\\"" ) + "\""; } @@ -1906,7 +1950,7 @@ QUnit.dump = (function() { var reName = /^function (\w+)/, dump = { - // objType is used mostly internally, you can fix a (custom) type in advance + // The objType is used mostly internally, you can fix a (custom) type in advance parse: function( obj, objType, stack ) { stack = stack || []; var res, parser, parserType, @@ -1950,7 +1994,7 @@ QUnit.dump = (function() { type = "node"; } else if ( - // native arrays + // Native arrays toString.call( obj ) === "[object Array]" || // NodeList objects @@ -1966,10 +2010,12 @@ QUnit.dump = (function() { } return type; }, + separator: function() { return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; }, - // extra can be a number, shortcut for increasing-calling-decreasing + + // Extra can be a number, shortcut for increasing-calling-decreasing indent: function( extra ) { if ( !this.multiline ) { return ""; @@ -1989,11 +2035,11 @@ QUnit.dump = (function() { setParser: function( name, parser ) { this.parsers[ name ] = parser; }, + // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, - // depth: 1, maxDepth: QUnit.config.maxDepth, @@ -2010,13 +2056,13 @@ QUnit.dump = (function() { "function": function( fn ) { var ret = "function", - // functions never have name in IE + // Functions never have name in IE name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ]; if ( name ) { ret += " " + name; } - ret += "( "; + ret += "("; ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" ); return join( ret, dump.parse( fn, "functionCode" ), "}" ); @@ -2087,7 +2133,7 @@ QUnit.dump = (function() { return ret + open + "/" + tag + close; }, - // function calls it internally, it's the arguments part of the function + // Function calls it internally, it's the arguments part of the function functionArgs: function( fn ) { var args, l = fn.length; @@ -2104,11 +2150,14 @@ QUnit.dump = (function() { } return " " + args.join( ", " ) + " "; }, - // object calls it internally, the key part of an item in a map + + // Object calls it internally, the key part of an item in a map key: quote, - // function calls it internally, it's the content of the function + + // Function calls it internally, it's the content of the function functionCode: "[code]", - // node calls it internally, it's an html attribute value + + // Node calls it internally, it's a html attribute value attribute: quote, string: quote, date: quote, @@ -2116,42 +2165,45 @@ QUnit.dump = (function() { number: literal, "boolean": literal }, - // if true, entities are escaped ( <, >, \t, space and \n ) + + // If true, entities are escaped ( <, >, \t, space and \n ) HTML: false, - // indentation unit + + // Indentation unit indentChar: " ", - // if true, items in a collection, are separated by a \n, else just a space. + + // If true, items in a collection, are separated by a \n, else just a space. multiline: true }; return dump; -}()); +}() ); -// back compat +// Back compat QUnit.jsDump = QUnit.dump; -// For browser, export only select globals -if ( defined.document ) { +// Deprecated +// Extend assert methods to QUnit for Backwards compatibility +( function() { + var i, + assertions = Assert.prototype; - // Deprecated - // Extend assert methods to QUnit and Global scope through Backwards compatibility - (function() { - var i, - assertions = Assert.prototype; + function applyCurrent( current ) { + return function() { + var assert = new Assert( QUnit.config.current ); + current.apply( assert, arguments ); + }; + } - function applyCurrent( current ) { - return function() { - var assert = new Assert( QUnit.config.current ); - current.apply( assert, arguments ); - }; - } + for ( i in assertions ) { + QUnit[ i ] = applyCurrent( assertions[ i ] ); + } +}() ); - for ( i in assertions ) { - QUnit[ i ] = applyCurrent( assertions[ i ] ); - } - })(); +// For browser, export only select globals +if ( defined.document ) { - (function() { + ( function() { var i, l, keys = [ "test", @@ -2177,7 +2229,7 @@ if ( defined.document ) { for ( i = 0, l = keys.length; i < l; i++ ) { window[ keys[ i ] ] = QUnit[ keys[ i ] ]; } - })(); + }() ); window.QUnit = QUnit; } @@ -2202,6 +2254,916 @@ if ( typeof define === "function" && define.amd ) { QUnit.config.autostart = false; } +// Get a reference to the global object, like window in browsers +}( ( function() { + return this; +}() ) ) ); + +( function() { + +// Only interact with URLs via window.location +var location = typeof window !== "undefined" && window.location; +if ( !location ) { + return; +} + +var urlParams = getUrlParams(); + +QUnit.urlParams = urlParams; + +// Match module/test by inclusion in an array +QUnit.config.moduleId = [].concat( urlParams.moduleId || [] ); +QUnit.config.testId = [].concat( urlParams.testId || [] ); + +// Exact case-insensitive match of the module name +QUnit.config.module = urlParams.module; + +// Regular expression or case-insenstive substring match against "moduleName: testName" +QUnit.config.filter = urlParams.filter; + +// Test order randomization +if ( urlParams.seed === true ) { + + // Generate a random seed if the option is specified without a value + QUnit.config.seed = Math.random().toString( 36 ).slice( 2 ); +} else if ( urlParams.seed ) { + QUnit.config.seed = urlParams.seed; +} + +// Add URL-parameter-mapped config values with UI form rendering data +QUnit.config.urlConfig.push( + { + id: "hidepassed", + label: "Hide passed tests", + tooltip: "Only show tests and assertions that fail. Stored as query-strings." + }, + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the " + + "global object (`window` in Browsers). Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + + "exceptions in IE reasonable. Stored as query-strings." + } +); + +QUnit.begin( function() { + var i, option, + urlConfig = QUnit.config.urlConfig; + + for ( i = 0; i < urlConfig.length; i++ ) { + + // Options can be either strings or objects with nonempty "id" properties + option = QUnit.config.urlConfig[ i ]; + if ( typeof option !== "string" ) { + option = option.id; + } + + if ( QUnit.config[ option ] === undefined ) { + QUnit.config[ option ] = urlParams[ option ]; + } + } +} ); + +function getUrlParams() { + var i, param, name, value; + var urlParams = {}; + var params = location.search.slice( 1 ).split( "&" ); + var length = params.length; + + for ( i = 0; i < length; i++ ) { + if ( params[ i ] ) { + param = params[ i ].split( "=" ); + name = decodeURIComponent( param[ 0 ] ); + + // Allow just a key to turn on a flag, e.g., test.html?noglobals + value = param.length === 1 || + decodeURIComponent( param.slice( 1 ).join( "=" ) ) ; + if ( urlParams[ name ] ) { + urlParams[ name ] = [].concat( urlParams[ name ], value ); + } else { + urlParams[ name ] = value; + } + } + } + + return urlParams; +} + +// Don't load the HTML Reporter on non-browser environments +if ( typeof window === "undefined" || !window.document ) { + return; +} + +// Deprecated QUnit.init - Ref #530 +// Re-initialize the configuration options +QUnit.init = function() { + var config = QUnit.config; + + config.stats = { all: 0, bad: 0 }; + config.moduleStats = { all: 0, bad: 0 }; + config.started = 0; + config.updateRate = 1000; + config.blocking = false; + config.autostart = true; + config.autorun = false; + config.filter = ""; + config.queue = []; + + appendInterface(); +}; + +var config = QUnit.config, + document = window.document, + collapseNext = false, + hasOwn = Object.prototype.hasOwnProperty, + unfilteredUrl = setUrl( { filter: undefined, module: undefined, + moduleId: undefined, testId: undefined } ), + defined = { + sessionStorage: ( function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch ( e ) { + return false; + } + }() ) + }, + modulesList = []; + +/** +* Escape text for attribute or text content. +*/ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch ( s ) { + case "'": + return "'"; + case "\"": + return """; + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + } + } ); +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + if ( elem.addEventListener ) { + + // Standards-based browsers + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + + // Support: IE <9 + elem.attachEvent( "on" + type, function() { + var event = window.event; + if ( !event.target ) { + event.target = event.srcElement || document; + } + + fn.call( elem, event ); + } ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[ i ], type, fn ); + } +} + +function hasClass( elem, name ) { + return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += ( elem.className ? " " : "" ) + name; + } +} + +function toggleClass( elem, name, force ) { + if ( force || typeof force === "undefined" && !hasClass( elem, name ) ) { + addClass( elem, name ); + } else { + removeClass( elem, name ); + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + + // Class name may appear multiple times + while ( set.indexOf( " " + name + " " ) >= 0 ) { + set = set.replace( " " + name + " ", " " ); + } + + // Trim for prettiness + elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); +} + +function id( name ) { + return document.getElementById && document.getElementById( name ); +} + +function getUrlConfigHtml() { + var i, j, val, + escaped, escapedTooltip, + selection = false, + urlConfig = config.urlConfig, + urlConfigHtml = ""; + + for ( i = 0; i < urlConfig.length; i++ ) { + + // Options can be either strings or objects with nonempty "id" properties + val = config.urlConfig[ i ]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val + }; + } + + escaped = escapeText( val.id ); + escapedTooltip = escapeText( val.tooltip ); + + if ( !val.value || typeof val.value === "string" ) { + urlConfigHtml += "<input id='qunit-urlconfig-" + escaped + + "' name='" + escaped + "' type='checkbox'" + + ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) + + ( config[ val.id ] ? " checked='checked'" : "" ) + + " title='" + escapedTooltip + "' /><label for='qunit-urlconfig-" + escaped + + "' title='" + escapedTooltip + "'>" + val.label + "</label>"; + } else { + urlConfigHtml += "<label for='qunit-urlconfig-" + escaped + + "' title='" + escapedTooltip + "'>" + val.label + + ": </label><select id='qunit-urlconfig-" + escaped + + "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>"; + + if ( QUnit.is( "array", val.value ) ) { + for ( j = 0; j < val.value.length; j++ ) { + escaped = escapeText( val.value[ j ] ); + urlConfigHtml += "<option value='" + escaped + "'" + + ( config[ val.id ] === val.value[ j ] ? + ( selection = true ) && " selected='selected'" : "" ) + + ">" + escaped + "</option>"; + } + } else { + for ( j in val.value ) { + if ( hasOwn.call( val.value, j ) ) { + urlConfigHtml += "<option value='" + escapeText( j ) + "'" + + ( config[ val.id ] === j ? + ( selection = true ) && " selected='selected'" : "" ) + + ">" + escapeText( val.value[ j ] ) + "</option>"; + } + } + } + if ( config[ val.id ] && !selection ) { + escaped = escapeText( config[ val.id ] ); + urlConfigHtml += "<option value='" + escaped + + "' selected='selected' disabled='disabled'>" + escaped + "</option>"; + } + urlConfigHtml += "</select>"; + } + } + + return urlConfigHtml; +} + +// Handle "click" events on toolbar checkboxes and "change" for select menus. +// Updates the URL with the new state of `config.urlConfig` values. +function toolbarChanged() { + var updatedUrl, value, tests, + field = this, + params = {}; + + // Detect if field is a select menu or a checkbox + if ( "selectedIndex" in field ) { + value = field.options[ field.selectedIndex ].value || undefined; + } else { + value = field.checked ? ( field.defaultValue || true ) : undefined; + } + + params[ field.name ] = value; + updatedUrl = setUrl( params ); + + // Check if we can apply the change without a page refresh + if ( "hidepassed" === field.name && "replaceState" in window.history ) { + QUnit.urlParams[ field.name ] = value; + config[ field.name ] = value || false; + tests = id( "qunit-tests" ); + if ( tests ) { + toggleClass( tests, "hidepass", value || false ); + } + window.history.replaceState( null, "", updatedUrl ); + } else { + window.location = updatedUrl; + } +} + +function setUrl( params ) { + var key, arrValue, i, + querystring = "?", + location = window.location; + + params = QUnit.extend( QUnit.extend( {}, QUnit.urlParams ), params ); + + for ( key in params ) { + + // Skip inherited or undefined properties + if ( hasOwn.call( params, key ) && params[ key ] !== undefined ) { + + // Output a parameter for each value of this key (but usually just one) + arrValue = [].concat( params[ key ] ); + for ( i = 0; i < arrValue.length; i++ ) { + querystring += encodeURIComponent( key ); + if ( arrValue[ i ] !== true ) { + querystring += "=" + encodeURIComponent( arrValue[ i ] ); + } + querystring += "&"; + } + } + } + return location.protocol + "//" + location.host + + location.pathname + querystring.slice( 0, -1 ); +} + +function applyUrlParams() { + var selectedModule, + modulesList = id( "qunit-modulefilter" ), + filter = id( "qunit-filter-input" ).value; + + selectedModule = modulesList ? + decodeURIComponent( modulesList.options[ modulesList.selectedIndex ].value ) : + undefined; + + window.location = setUrl( { + module: ( selectedModule === "" ) ? undefined : selectedModule, + filter: ( filter === "" ) ? undefined : filter, + + // Remove moduleId and testId filters + moduleId: undefined, + testId: undefined + } ); +} + +function toolbarUrlConfigContainer() { + var urlConfigContainer = document.createElement( "span" ); + + urlConfigContainer.innerHTML = getUrlConfigHtml(); + addClass( urlConfigContainer, "qunit-url-config" ); + + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" for checkboxes + addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged ); + addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged ); + + return urlConfigContainer; +} + +function toolbarLooseFilter() { + var filter = document.createElement( "form" ), + label = document.createElement( "label" ), + input = document.createElement( "input" ), + button = document.createElement( "button" ); + + addClass( filter, "qunit-filter" ); + + label.innerHTML = "Filter: "; + + input.type = "text"; + input.value = config.filter || ""; + input.name = "filter"; + input.id = "qunit-filter-input"; + + button.innerHTML = "Go"; + + label.appendChild( input ); + + filter.appendChild( label ); + filter.appendChild( button ); + addEvent( filter, "submit", function( ev ) { + applyUrlParams(); + + if ( ev && ev.preventDefault ) { + ev.preventDefault(); + } + + return false; + } ); + + return filter; +} + +function toolbarModuleFilterHtml() { + var i, + moduleFilterHtml = ""; + + if ( !modulesList.length ) { + return false; + } + + moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" + + "<select id='qunit-modulefilter' name='modulefilter'><option value='' " + + ( QUnit.urlParams.module === undefined ? "selected='selected'" : "" ) + + ">< All Modules ></option>"; + + for ( i = 0; i < modulesList.length; i++ ) { + moduleFilterHtml += "<option value='" + + escapeText( encodeURIComponent( modulesList[ i ] ) ) + "' " + + ( QUnit.urlParams.module === modulesList[ i ] ? "selected='selected'" : "" ) + + ">" + escapeText( modulesList[ i ] ) + "</option>"; + } + moduleFilterHtml += "</select>"; + + return moduleFilterHtml; +} + +function toolbarModuleFilter() { + var toolbar = id( "qunit-testrunner-toolbar" ), + moduleFilter = document.createElement( "span" ), + moduleFilterHtml = toolbarModuleFilterHtml(); + + if ( !toolbar || !moduleFilterHtml ) { + return false; + } + + moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); + moduleFilter.innerHTML = moduleFilterHtml; + + addEvent( moduleFilter.lastChild, "change", applyUrlParams ); + + toolbar.appendChild( moduleFilter ); +} + +function appendToolbar() { + var toolbar = id( "qunit-testrunner-toolbar" ); + + if ( toolbar ) { + toolbar.appendChild( toolbarUrlConfigContainer() ); + toolbar.appendChild( toolbarLooseFilter() ); + toolbarModuleFilter(); + } +} + +function appendHeader() { + var header = id( "qunit-header" ); + + if ( header ) { + header.innerHTML = "<a href='" + escapeText( unfilteredUrl ) + "'>" + header.innerHTML + + "</a> "; + } +} + +function appendBanner() { + var banner = id( "qunit-banner" ); + + if ( banner ) { + banner.className = ""; + } +} + +function appendTestResults() { + var tests = id( "qunit-tests" ), + result = id( "qunit-testresult" ); + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + tests.innerHTML = ""; + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...<br /> "; + } +} + +function storeFixture() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + config.fixture = fixture.innerHTML; + } +} + +function appendFilteredTest() { + var testId = QUnit.config.testId; + if ( !testId || testId.length <= 0 ) { + return ""; + } + return "<div id='qunit-filteredTest'>Rerunning selected tests: " + + escapeText( testId.join( ", " ) ) + + " <a id='qunit-clearFilter' href='" + + escapeText( unfilteredUrl ) + + "'>Run all tests</a></div>"; +} + +function appendUserAgent() { + var userAgent = id( "qunit-userAgent" ); + + if ( userAgent ) { + userAgent.innerHTML = ""; + userAgent.appendChild( + document.createTextNode( + "QUnit " + QUnit.version + "; " + navigator.userAgent + ) + ); + } +} + +function appendInterface() { + var qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" + + "<h2 id='qunit-banner'></h2>" + + "<div id='qunit-testrunner-toolbar'></div>" + + appendFilteredTest() + + "<h2 id='qunit-userAgent'></h2>" + + "<ol id='qunit-tests'></ol>"; + } + + appendHeader(); + appendBanner(); + appendTestResults(); + appendUserAgent(); + appendToolbar(); +} + +function appendTestsList( modules ) { + var i, l, x, z, test, moduleObj; + + for ( i = 0, l = modules.length; i < l; i++ ) { + moduleObj = modules[ i ]; + + for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) { + test = moduleObj.tests[ x ]; + + appendTest( test.name, test.testId, moduleObj.name ); + } + } +} + +function appendTest( name, testId, moduleName ) { + var title, rerunTrigger, testBlock, assertList, + tests = id( "qunit-tests" ); + + if ( !tests ) { + return; + } + + title = document.createElement( "strong" ); + title.innerHTML = getNameHtml( name, moduleName ); + + rerunTrigger = document.createElement( "a" ); + rerunTrigger.innerHTML = "Rerun"; + rerunTrigger.href = setUrl( { testId: testId } ); + + testBlock = document.createElement( "li" ); + testBlock.appendChild( title ); + testBlock.appendChild( rerunTrigger ); + testBlock.id = "qunit-test-output-" + testId; + + assertList = document.createElement( "ol" ); + assertList.className = "qunit-assert-list"; + + testBlock.appendChild( assertList ); + + tests.appendChild( testBlock ); +} + +// HTML Reporter initialization and load +QUnit.begin( function( details ) { + var i, moduleObj, tests; + + // Sort modules by name for the picker + for ( i = 0; i < details.modules.length; i++ ) { + moduleObj = details.modules[ i ]; + if ( moduleObj.name ) { + modulesList.push( moduleObj.name ); + } + } + modulesList.sort( function( a, b ) { + return a.localeCompare( b ); + } ); + + // Capture fixture HTML from the page + storeFixture(); + + // Initialize QUnit elements + appendInterface(); + appendTestsList( details.modules ); + tests = id( "qunit-tests" ); + if ( tests && config.hidepassed ) { + addClass( tests, "hidepass" ); + } +} ); + +QUnit.done( function( details ) { + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + html = [ + "Tests completed in ", + details.runtime, + " milliseconds.<br />", + "<span class='passed'>", + details.passed, + "</span> assertions of <span class='total'>", + details.total, + "</span> passed, <span class='failed'>", + details.failed, + "</span> failed." + ].join( "" ); + + if ( banner ) { + banner.className = details.failed ? "qunit-fail" : "qunit-pass"; + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && document.title ) { + + // Show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( details.failed ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // Clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && details.failed === 0 ) { + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // Scroll back to top to show results + if ( config.scrolltop && window.scrollTo ) { + window.scrollTo( 0, 0 ); + } +} ); + +function getNameHtml( name, module ) { + var nameHtml = ""; + + if ( module ) { + nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: "; + } + + nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>"; + + return nameHtml; +} + +QUnit.testStart( function( details ) { + var running, testBlock, bad; + + testBlock = id( "qunit-test-output-" + details.testId ); + if ( testBlock ) { + testBlock.className = "running"; + } else { + + // Report later registered tests + appendTest( details.name, details.testId, details.module ); + } + + running = id( "qunit-testresult" ); + if ( running ) { + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name ); + + running.innerHTML = ( bad ? + "Rerunning previously failed test: <br />" : + "Running: <br />" ) + + getNameHtml( details.name, details.module ); + } + +} ); + +function stripHtml( string ) { + + // Strip tags, html entity and whitespaces + return string.replace( /<\/?[^>]+(>|$)/g, "" ).replace( /\"/g, "" ).replace( /\s+/g, "" ); +} + +QUnit.log( function( details ) { + var assertList, assertLi, + message, expected, actual, diff, + showDiff = false, + testItem = id( "qunit-test-output-" + details.testId ); + + if ( !testItem ) { + return; + } + + message = escapeText( details.message ) || ( details.result ? "okay" : "failed" ); + message = "<span class='test-message'>" + message + "</span>"; + message += "<span class='runtime'>@ " + details.runtime + " ms</span>"; + + // The pushFailure doesn't provide details.expected + // when it calls, it's implicit to also not show expected and diff stuff + // Also, we need to check details.expected existence, as it can exist and be undefined + if ( !details.result && hasOwn.call( details, "expected" ) ) { + if ( details.negative ) { + expected = "NOT " + QUnit.dump.parse( details.expected ); + } else { + expected = QUnit.dump.parse( details.expected ); + } + + actual = QUnit.dump.parse( details.actual ); + message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + + escapeText( expected ) + + "</pre></td></tr>"; + + if ( actual !== expected ) { + + message += "<tr class='test-actual'><th>Result: </th><td><pre>" + + escapeText( actual ) + "</pre></td></tr>"; + + // Don't show diff if actual or expected are booleans + if ( !( /^(true|false)$/.test( actual ) ) && + !( /^(true|false)$/.test( expected ) ) ) { + diff = QUnit.diff( expected, actual ); + showDiff = stripHtml( diff ).length !== + stripHtml( expected ).length + + stripHtml( actual ).length; + } + + // Don't show diff if expected and actual are totally different + if ( showDiff ) { + message += "<tr class='test-diff'><th>Diff: </th><td><pre>" + + diff + "</pre></td></tr>"; + } + } else if ( expected.indexOf( "[object Array]" ) !== -1 || + expected.indexOf( "[object Object]" ) !== -1 ) { + message += "<tr class='test-message'><th>Message: </th><td>" + + "Diff suppressed as the depth of object is more than current max depth (" + + QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " + + " run with a higher max depth or <a href='" + + escapeText( setUrl( { maxDepth: -1 } ) ) + "'>" + + "Rerun</a> without max depth.</p></td></tr>"; + } else { + message += "<tr class='test-message'><th>Message: </th><td>" + + "Diff suppressed as the expected and actual results have an equivalent" + + " serialization</td></tr>"; + } + + if ( details.source ) { + message += "<tr class='test-source'><th>Source: </th><td><pre>" + + escapeText( details.source ) + "</pre></td></tr>"; + } + + message += "</table>"; + + // This occurs when pushFailure is set and we have an extracted stack trace + } else if ( !details.result && details.source ) { + message += "<table>" + + "<tr class='test-source'><th>Source: </th><td><pre>" + + escapeText( details.source ) + "</pre></td></tr>" + + "</table>"; + } + + assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; + + assertLi = document.createElement( "li" ); + assertLi.className = details.result ? "pass" : "fail"; + assertLi.innerHTML = message; + assertList.appendChild( assertLi ); +} ); + +QUnit.testDone( function( details ) { + var testTitle, time, testItem, assertList, + good, bad, testCounts, skipped, sourceName, + tests = id( "qunit-tests" ); + + if ( !tests ) { + return; + } + + testItem = id( "qunit-test-output-" + details.testId ); + + assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; + + good = details.passed; + bad = details.failed; + + // Store result when possible + if ( config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name ); + } + } + + if ( bad === 0 ) { + + // Collapse the passing tests + addClass( assertList, "qunit-collapsed" ); + } else if ( bad && config.collapse && !collapseNext ) { + + // Skip collapsing the first failing test + collapseNext = true; + } else { + + // Collapse remaining tests + addClass( assertList, "qunit-collapsed" ); + } + + // The testItem.firstChild is the test name + testTitle = testItem.firstChild; + + testCounts = bad ? + "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " : + ""; + + testTitle.innerHTML += " <b class='counts'>(" + testCounts + + details.assertions.length + ")</b>"; + + if ( details.skipped ) { + testItem.className = "skipped"; + skipped = document.createElement( "em" ); + skipped.className = "qunit-skipped-label"; + skipped.innerHTML = "skipped"; + testItem.insertBefore( skipped, testTitle ); + } else { + addEvent( testTitle, "click", function() { + toggleClass( assertList, "qunit-collapsed" ); + } ); + + testItem.className = bad ? "fail" : "pass"; + + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = details.runtime + " ms"; + testItem.insertBefore( time, assertList ); + } + + // Show the source of the test when showing assertions + if ( details.source ) { + sourceName = document.createElement( "p" ); + sourceName.innerHTML = "<strong>Source: </strong>" + details.source; + addClass( sourceName, "qunit-source" ); + if ( bad === 0 ) { + addClass( sourceName, "qunit-collapsed" ); + } + addEvent( testTitle, "click", function() { + toggleClass( sourceName, "qunit-collapsed" ); + } ); + testItem.appendChild( sourceName ); + } +} ); + +// Avoid readyState issue with phantomjs +// Ref: #818 +var notPhantom = ( function( p ) { + return !( p && p.version && p.version.major > 0 ); +} )( window.phantom ); + +if ( notPhantom && document.readyState === "complete" ) { + QUnit.load(); +} else { + addEvent( window, "load", QUnit.load ); +} + /* * This file is a modified version of google-diff-match-patch's JavaScript implementation * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js), @@ -2210,13 +3172,13 @@ if ( typeof define === "function" && define.amd ) { * The original source of google-diff-match-patch is attributable and licensed as follows: * * Copyright 2006 Google Inc. - * http://code.google.com/p/google-diff-match-patch/ + * https://code.google.com/p/google-diff-match-patch/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -2321,14 +3283,19 @@ QUnit.diff = ( function() { equalitiesLength = 0; // Keeping our own length var is faster in JS. /** @type {?string} */ lastequality = null; + // Always equal to diffs[equalities[equalitiesLength - 1]][1] pointer = 0; // Index of current position. + // Is there an insertion operation before the last equality. preIns = false; + // Is there a deletion operation before the last equality. preDel = false; + // Is there an insertion operation after the last equality. postIns = false; + // Is there a deletion operation after the last equality. postDel = false; while ( pointer < diffs.length ) { @@ -2383,6 +3350,7 @@ QUnit.diff = ( function() { equalitiesLength--; // Throw away the equality we just deleted; lastequality = null; if ( preIns && preDel ) { + // No changes made which could affect previous entry, keep going. postIns = postDel = true; equalitiesLength = 0; @@ -2416,13 +3384,13 @@ QUnit.diff = ( function() { data = diffs[ x ][ 1 ]; // Text of change. switch ( op ) { case DIFF_INSERT: - html[ x ] = "<ins>" + data + "</ins>"; + html[ x ] = "<ins>" + escapeText( data ) + "</ins>"; break; case DIFF_DELETE: - html[ x ] = "<del>" + data + "</del>"; + html[ x ] = "<del>" + escapeText( data ) + "</del>"; break; case DIFF_EQUAL: - html[ x ] = "<span>" + data + "</span>"; + html[ x ] = "<span>" + escapeText( data ) + "</span>"; break; } } @@ -2438,12 +3406,14 @@ QUnit.diff = ( function() { */ DiffMatchPatch.prototype.diffCommonPrefix = function( text1, text2 ) { var pointermid, pointermax, pointermin, pointerstart; + // Quick check for common null cases. if ( !text1 || !text2 || text1.charAt( 0 ) !== text2.charAt( 0 ) ) { return 0; } + // Binary search. - // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + // Performance analysis: https://neil.fraser.name/news/2007/10/09/ pointermin = 0; pointermax = Math.min( text1.length, text2.length ); pointermid = pointermax; @@ -2469,14 +3439,16 @@ QUnit.diff = ( function() { */ DiffMatchPatch.prototype.diffCommonSuffix = function( text1, text2 ) { var pointermid, pointermax, pointermin, pointerend; + // Quick check for common null cases. if ( !text1 || !text2 || text1.charAt( text1.length - 1 ) !== text2.charAt( text2.length - 1 ) ) { return 0; } + // Binary search. - // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + // Performance analysis: https://neil.fraser.name/news/2007/10/09/ pointermin = 0; pointermax = Math.min( text1.length, text2.length ); pointermid = pointermax; @@ -2512,6 +3484,7 @@ QUnit.diff = ( function() { midCommon, diffsA, diffsB; if ( !text1 ) { + // Just add some text (speedup). return [ [ DIFF_INSERT, text2 ] @@ -2519,6 +3492,7 @@ QUnit.diff = ( function() { } if ( !text2 ) { + // Just delete some text (speedup). return [ [ DIFF_DELETE, text1 ] @@ -2529,12 +3503,14 @@ QUnit.diff = ( function() { shorttext = text1.length > text2.length ? text2 : text1; i = longtext.indexOf( shorttext ); if ( i !== -1 ) { + // Shorter text is inside the longer text (speedup). diffs = [ [ DIFF_INSERT, longtext.substring( 0, i ) ], [ DIFF_EQUAL, shorttext ], [ DIFF_INSERT, longtext.substring( i + shorttext.length ) ] ]; + // Swap insertions for deletions if diff is reversed. if ( text1.length > text2.length ) { diffs[ 0 ][ 0 ] = diffs[ 2 ][ 0 ] = DIFF_DELETE; @@ -2543,6 +3519,7 @@ QUnit.diff = ( function() { } if ( shorttext.length === 1 ) { + // Single character string. // After the previous speedup, the character can't be an equality. return [ @@ -2554,15 +3531,18 @@ QUnit.diff = ( function() { // Check to see if the problem can be split in two. hm = this.diffHalfMatch( text1, text2 ); if ( hm ) { + // A half-match was found, sort out the return data. text1A = hm[ 0 ]; text1B = hm[ 1 ]; text2A = hm[ 2 ]; text2B = hm[ 3 ]; midCommon = hm[ 4 ]; + // Send both pairs off for separate processing. diffsA = this.DiffMain( text1A, text2A, checklines, deadline ); diffsB = this.DiffMain( text1B, text2B, checklines, deadline ); + // Merge the results. return diffsA.concat( [ [ DIFF_EQUAL, midCommon ] @@ -2614,6 +3594,7 @@ QUnit.diff = ( function() { function diffHalfMatchI( longtext, shorttext, i ) { var seed, j, bestCommon, prefixLength, suffixLength, bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB; + // Start with a 1/4 length substring at position i as a seed. seed = longtext.substring( i, i + Math.floor( longtext.length / 4 ) ); j = -1; @@ -2644,6 +3625,7 @@ QUnit.diff = ( function() { // First check if the second quarter is the seed for a half-match. hm1 = diffHalfMatchI( longtext, shorttext, Math.ceil( longtext.length / 4 ) ); + // Check again based on the third quarter. hm2 = diffHalfMatchI( longtext, shorttext, Math.ceil( longtext.length / 2 ) ); @@ -2654,6 +3636,7 @@ QUnit.diff = ( function() { } else if ( !hm1 ) { hm = hm2; } else { + // Both matched. Select the longest. hm = hm1[ 4 ].length > hm2[ 4 ].length ? hm1 : hm2; } @@ -2688,6 +3671,7 @@ QUnit.diff = ( function() { DiffMatchPatch.prototype.diffLineMode = function( text1, text2, deadline ) { var a, diffs, linearray, pointer, countInsert, countDelete, textInsert, textDelete, j; + // Scan the text on a line-by-line basis first. a = this.diffLinesToChars( text1, text2 ); text1 = a.chars1; @@ -2698,6 +3682,7 @@ QUnit.diff = ( function() { // Convert the diff back to original text. this.diffCharsToLines( diffs, linearray ); + // Eliminate freak matches (e.g. blank lines) this.diffCleanupSemantic( diffs ); @@ -2720,8 +3705,10 @@ QUnit.diff = ( function() { textDelete += diffs[ pointer ][ 1 ]; break; case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. if ( countDelete >= 1 && countInsert >= 1 ) { + // Delete the offending records and add the merged ones. diffs.splice( pointer - countDelete - countInsert, countDelete + countInsert ); @@ -2759,6 +3746,7 @@ QUnit.diff = ( function() { var text1Length, text2Length, maxD, vOffset, vLength, v1, v2, x, delta, front, k1start, k1end, k2start, k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2; + // Cache the text lengths to prevent multiple calls. text1Length = text1.length; text2Length = text2.length; @@ -2767,6 +3755,7 @@ QUnit.diff = ( function() { vLength = 2 * maxD; v1 = new Array( vLength ); v2 = new Array( vLength ); + // Setting all elements to -1 is faster in Chrome & Firefox than mixing // integers and undefined. for ( x = 0; x < vLength; x++ ) { @@ -2776,9 +3765,11 @@ QUnit.diff = ( function() { v1[ vOffset + 1 ] = 0; v2[ vOffset + 1 ] = 0; delta = text1Length - text2Length; + // If the total number of characters is odd, then the front path will collide // with the reverse path. front = ( delta % 2 !== 0 ); + // Offsets for start and end of k loop. // Prevents mapping of space beyond the grid. k1start = 0; @@ -2786,6 +3777,7 @@ QUnit.diff = ( function() { k2start = 0; k2end = 0; for ( d = 0; d < maxD; d++ ) { + // Bail out if deadline is reached. if ( ( new Date() ).getTime() > deadline ) { break; @@ -2807,17 +3799,21 @@ QUnit.diff = ( function() { } v1[ k1Offset ] = x1; if ( x1 > text1Length ) { + // Ran off the right of the graph. k1end += 2; } else if ( y1 > text2Length ) { + // Ran off the bottom of the graph. k1start += 2; } else if ( front ) { k2Offset = vOffset + delta - k1; if ( k2Offset >= 0 && k2Offset < vLength && v2[ k2Offset ] !== -1 ) { + // Mirror x2 onto top-left coordinate system. x2 = text1Length - v2[ k2Offset ]; if ( x1 >= x2 ) { + // Overlap detected. return this.diffBisectSplit( text1, text2, x1, y1, deadline ); } @@ -2842,9 +3838,11 @@ QUnit.diff = ( function() { } v2[ k2Offset ] = x2; if ( x2 > text1Length ) { + // Ran off the left of the graph. k2end += 2; } else if ( y2 > text2Length ) { + // Ran off the top of the graph. k2start += 2; } else if ( !front ) { @@ -2852,9 +3850,11 @@ QUnit.diff = ( function() { if ( k1Offset >= 0 && k1Offset < vLength && v1[ k1Offset ] !== -1 ) { x1 = v1[ k1Offset ]; y1 = vOffset + x1 - k1Offset; + // Mirror x2 onto top-left coordinate system. x2 = text1Length - x2; if ( x1 >= x2 ) { + // Overlap detected. return this.diffBisectSplit( text1, text2, x1, y1, deadline ); } @@ -2862,6 +3862,7 @@ QUnit.diff = ( function() { } } } + // Diff took too long and hit the deadline or // number of diffs equals number of characters, no commonality at all. return [ @@ -2908,11 +3909,14 @@ QUnit.diff = ( function() { equalitiesLength = 0; // Keeping our own length var is faster in JS. /** @type {?string} */ lastequality = null; + // Always equal to diffs[equalities[equalitiesLength - 1]][1] pointer = 0; // Index of current position. + // Number of characters that changed prior to the equality. lengthInsertions1 = 0; lengthDeletions1 = 0; + // Number of characters that changed after the equality. lengthInsertions2 = 0; lengthDeletions2 = 0; @@ -2930,6 +3934,7 @@ QUnit.diff = ( function() { } else { lengthDeletions2 += diffs[ pointer ][ 1 ].length; } + // Eliminate an equality that is smaller or equal to the edits on both // sides of it. if ( lastequality && ( lastequality.length <= @@ -2988,6 +3993,7 @@ QUnit.diff = ( function() { if ( overlapLength1 >= overlapLength2 ) { if ( overlapLength1 >= deletion.length / 2 || overlapLength1 >= insertion.length / 2 ) { + // Overlap found. Insert an equality and trim the surrounding edits. diffs.splice( pointer, @@ -3037,13 +4043,16 @@ QUnit.diff = ( function() { DiffMatchPatch.prototype.diffCommonOverlap = function( text1, text2 ) { var text1Length, text2Length, textLength, best, length, pattern, found; + // Cache the text lengths to prevent multiple calls. text1Length = text1.length; text2Length = text2.length; + // Eliminate the null case. if ( text1Length === 0 || text2Length === 0 ) { return 0; } + // Truncate the longer string. if ( text1Length > text2Length ) { text1 = text1.substring( text1Length - text2Length ); @@ -3051,6 +4060,7 @@ QUnit.diff = ( function() { text2 = text2.substring( 0, text1Length ); } textLength = Math.min( text1Length, text2Length ); + // Quick check for the worst case. if ( text1 === text2 ) { return textLength; @@ -3058,7 +4068,7 @@ QUnit.diff = ( function() { // Start by looking for a single character match // and increase length until no match is found. - // Performance analysis: http://neil.fraser.name/news/2010/11/04/ + // Performance analysis: https://neil.fraser.name/news/2010/11/04/ best = 0; length = 1; while ( true ) { @@ -3089,8 +4099,8 @@ QUnit.diff = ( function() { */ DiffMatchPatch.prototype.diffLinesToChars = function( text1, text2 ) { var lineArray, lineHash, chars1, chars2; - lineArray = []; // e.g. lineArray[4] === 'Hello\n' - lineHash = {}; // e.g. lineHash['Hello\n'] === 4 + lineArray = []; // E.g. lineArray[4] === 'Hello\n' + lineHash = {}; // E.g. lineHash['Hello\n'] === 4 // '\x00' is a valid character, but various debuggers don't like it. // So we'll insert a junk entry to avoid generating a null character. @@ -3107,11 +4117,13 @@ QUnit.diff = ( function() { function diffLinesToCharsMunge( text ) { var chars, lineStart, lineEnd, lineArrayLength, line; chars = ""; + // Walk the text, pulling out a substring for each line. // text.split('\n') would would temporarily double our memory footprint. // Modifying text would create many large strings to garbage collect. lineStart = 0; lineEnd = -1; + // Keeping our own length variable is faster than looking it up. lineArrayLength = lineArray.length; while ( lineEnd < text.length - 1 ) { @@ -3190,10 +4202,12 @@ QUnit.diff = ( function() { pointer++; break; case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. if ( countDelete + countInsert > 1 ) { if ( countDelete !== 0 && countInsert !== 0 ) { - // Factor out any common prefixies. + + // Factor out any common prefixes. commonlength = this.diffCommonPrefix( textInsert, textDelete ); if ( commonlength !== 0 ) { if ( ( pointer - countDelete - countInsert ) > 0 && @@ -3210,6 +4224,7 @@ QUnit.diff = ( function() { textInsert = textInsert.substring( commonlength ); textDelete = textDelete.substring( commonlength ); } + // Factor out any common suffixies. commonlength = this.diffCommonSuffix( textInsert, textDelete ); if ( commonlength !== 0 ) { @@ -3221,6 +4236,7 @@ QUnit.diff = ( function() { commonlength ); } } + // Delete the offending records and add the merged ones. if ( countDelete === 0 ) { diffs.splice( pointer - countInsert, @@ -3297,6 +4313,7 @@ QUnit.diff = ( function() { } pointer++; } + // If shifts were made, the diff needs reordering and another shift sweep. if ( changes ) { this.diffCleanupMerge( diffs ); @@ -3314,845 +4331,4 @@ QUnit.diff = ( function() { }; }() ); -// Get a reference to the global object, like window in browsers -}( (function() { - return this; -})() )); - -(function() { - -// Don't load the HTML Reporter on non-Browser environments -if ( typeof window === "undefined" || !window.document ) { - return; -} - -// Deprecated QUnit.init - Ref #530 -// Re-initialize the configuration options -QUnit.init = function() { - var tests, banner, result, qunit, - config = QUnit.config; - - config.stats = { all: 0, bad: 0 }; - config.moduleStats = { all: 0, bad: 0 }; - config.started = 0; - config.updateRate = 1000; - config.blocking = false; - config.autostart = true; - config.autorun = false; - config.filter = ""; - config.queue = []; - - // Return on non-browser environments - // This is necessary to not break on node tests - if ( typeof window === "undefined" ) { - return; - } - - qunit = id( "qunit" ); - if ( qunit ) { - qunit.innerHTML = - "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" + - "<h2 id='qunit-banner'></h2>" + - "<div id='qunit-testrunner-toolbar'></div>" + - "<h2 id='qunit-userAgent'></h2>" + - "<ol id='qunit-tests'></ol>"; - } - - tests = id( "qunit-tests" ); - banner = id( "qunit-banner" ); - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...<br /> "; - } -}; - -var config = QUnit.config, - collapseNext = false, - hasOwn = Object.prototype.hasOwnProperty, - defined = { - document: window.document !== undefined, - sessionStorage: (function() { - var x = "qunit-test-string"; - try { - sessionStorage.setItem( x, x ); - sessionStorage.removeItem( x ); - return true; - } catch ( e ) { - return false; - } - }()) - }, - modulesList = []; - -/** -* Escape text for attribute or text content. -*/ -function escapeText( s ) { - if ( !s ) { - return ""; - } - s = s + ""; - - // Both single quotes and double quotes (for attributes) - return s.replace( /['"<>&]/g, function( s ) { - switch ( s ) { - case "'": - return "'"; - case "\"": - return """; - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - } - }); -} - -/** - * @param {HTMLElement} elem - * @param {string} type - * @param {Function} fn - */ -function addEvent( elem, type, fn ) { - if ( elem.addEventListener ) { - - // Standards-based browsers - elem.addEventListener( type, fn, false ); - } else if ( elem.attachEvent ) { - - // support: IE <9 - elem.attachEvent( "on" + type, function() { - var event = window.event; - if ( !event.target ) { - event.target = event.srcElement || document; - } - - fn.call( elem, event ); - }); - } -} - -/** - * @param {Array|NodeList} elems - * @param {string} type - * @param {Function} fn - */ -function addEvents( elems, type, fn ) { - var i = elems.length; - while ( i-- ) { - addEvent( elems[ i ], type, fn ); - } -} - -function hasClass( elem, name ) { - return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0; -} - -function addClass( elem, name ) { - if ( !hasClass( elem, name ) ) { - elem.className += ( elem.className ? " " : "" ) + name; - } -} - -function toggleClass( elem, name ) { - if ( hasClass( elem, name ) ) { - removeClass( elem, name ); - } else { - addClass( elem, name ); - } -} - -function removeClass( elem, name ) { - var set = " " + elem.className + " "; - - // Class name may appear multiple times - while ( set.indexOf( " " + name + " " ) >= 0 ) { - set = set.replace( " " + name + " ", " " ); - } - - // trim for prettiness - elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); -} - -function id( name ) { - return defined.document && document.getElementById && document.getElementById( name ); -} - -function getUrlConfigHtml() { - var i, j, val, - escaped, escapedTooltip, - selection = false, - len = config.urlConfig.length, - urlConfigHtml = ""; - - for ( i = 0; i < len; i++ ) { - val = config.urlConfig[ i ]; - if ( typeof val === "string" ) { - val = { - id: val, - label: val - }; - } - - escaped = escapeText( val.id ); - escapedTooltip = escapeText( val.tooltip ); - - if ( config[ val.id ] === undefined ) { - config[ val.id ] = QUnit.urlParams[ val.id ]; - } - - if ( !val.value || typeof val.value === "string" ) { - urlConfigHtml += "<input id='qunit-urlconfig-" + escaped + - "' name='" + escaped + "' type='checkbox'" + - ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) + - ( config[ val.id ] ? " checked='checked'" : "" ) + - " title='" + escapedTooltip + "' /><label for='qunit-urlconfig-" + escaped + - "' title='" + escapedTooltip + "'>" + val.label + "</label>"; - } else { - urlConfigHtml += "<label for='qunit-urlconfig-" + escaped + - "' title='" + escapedTooltip + "'>" + val.label + - ": </label><select id='qunit-urlconfig-" + escaped + - "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>"; - - if ( QUnit.is( "array", val.value ) ) { - for ( j = 0; j < val.value.length; j++ ) { - escaped = escapeText( val.value[ j ] ); - urlConfigHtml += "<option value='" + escaped + "'" + - ( config[ val.id ] === val.value[ j ] ? - ( selection = true ) && " selected='selected'" : "" ) + - ">" + escaped + "</option>"; - } - } else { - for ( j in val.value ) { - if ( hasOwn.call( val.value, j ) ) { - urlConfigHtml += "<option value='" + escapeText( j ) + "'" + - ( config[ val.id ] === j ? - ( selection = true ) && " selected='selected'" : "" ) + - ">" + escapeText( val.value[ j ] ) + "</option>"; - } - } - } - if ( config[ val.id ] && !selection ) { - escaped = escapeText( config[ val.id ] ); - urlConfigHtml += "<option value='" + escaped + - "' selected='selected' disabled='disabled'>" + escaped + "</option>"; - } - urlConfigHtml += "</select>"; - } - } - - return urlConfigHtml; -} - -// Handle "click" events on toolbar checkboxes and "change" for select menus. -// Updates the URL with the new state of `config.urlConfig` values. -function toolbarChanged() { - var updatedUrl, value, - field = this, - params = {}; - - // Detect if field is a select menu or a checkbox - if ( "selectedIndex" in field ) { - value = field.options[ field.selectedIndex ].value || undefined; - } else { - value = field.checked ? ( field.defaultValue || true ) : undefined; - } - - params[ field.name ] = value; - updatedUrl = setUrl( params ); - - if ( "hidepassed" === field.name && "replaceState" in window.history ) { - config[ field.name ] = value || false; - if ( value ) { - addClass( id( "qunit-tests" ), "hidepass" ); - } else { - removeClass( id( "qunit-tests" ), "hidepass" ); - } - - // It is not necessary to refresh the whole page - window.history.replaceState( null, "", updatedUrl ); - } else { - window.location = updatedUrl; - } -} - -function setUrl( params ) { - var key, - querystring = "?"; - - params = QUnit.extend( QUnit.extend( {}, QUnit.urlParams ), params ); - - for ( key in params ) { - if ( hasOwn.call( params, key ) ) { - if ( params[ key ] === undefined ) { - continue; - } - querystring += encodeURIComponent( key ); - if ( params[ key ] !== true ) { - querystring += "=" + encodeURIComponent( params[ key ] ); - } - querystring += "&"; - } - } - return location.protocol + "//" + location.host + - location.pathname + querystring.slice( 0, -1 ); -} - -function applyUrlParams() { - var selectedModule, - modulesList = id( "qunit-modulefilter" ), - filter = id( "qunit-filter-input" ).value; - - selectedModule = modulesList ? - decodeURIComponent( modulesList.options[ modulesList.selectedIndex ].value ) : - undefined; - - window.location = setUrl({ - module: ( selectedModule === "" ) ? undefined : selectedModule, - filter: ( filter === "" ) ? undefined : filter, - - // Remove testId filter - testId: undefined - }); -} - -function toolbarUrlConfigContainer() { - var urlConfigContainer = document.createElement( "span" ); - - urlConfigContainer.innerHTML = getUrlConfigHtml(); - addClass( urlConfigContainer, "qunit-url-config" ); - - // For oldIE support: - // * Add handlers to the individual elements instead of the container - // * Use "click" instead of "change" for checkboxes - addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged ); - addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged ); - - return urlConfigContainer; -} - -function toolbarLooseFilter() { - var filter = document.createElement( "form" ), - label = document.createElement( "label" ), - input = document.createElement( "input" ), - button = document.createElement( "button" ); - - addClass( filter, "qunit-filter" ); - - label.innerHTML = "Filter: "; - - input.type = "text"; - input.value = config.filter || ""; - input.name = "filter"; - input.id = "qunit-filter-input"; - - button.innerHTML = "Go"; - - label.appendChild( input ); - - filter.appendChild( label ); - filter.appendChild( button ); - addEvent( filter, "submit", function( ev ) { - applyUrlParams(); - - if ( ev && ev.preventDefault ) { - ev.preventDefault(); - } - - return false; - }); - - return filter; -} - -function toolbarModuleFilterHtml() { - var i, - moduleFilterHtml = ""; - - if ( !modulesList.length ) { - return false; - } - - modulesList.sort(function( a, b ) { - return a.localeCompare( b ); - }); - - moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" + - "<select id='qunit-modulefilter' name='modulefilter'><option value='' " + - ( QUnit.urlParams.module === undefined ? "selected='selected'" : "" ) + - ">< All Modules ></option>"; - - for ( i = 0; i < modulesList.length; i++ ) { - moduleFilterHtml += "<option value='" + - escapeText( encodeURIComponent( modulesList[ i ] ) ) + "' " + - ( QUnit.urlParams.module === modulesList[ i ] ? "selected='selected'" : "" ) + - ">" + escapeText( modulesList[ i ] ) + "</option>"; - } - moduleFilterHtml += "</select>"; - - return moduleFilterHtml; -} - -function toolbarModuleFilter() { - var toolbar = id( "qunit-testrunner-toolbar" ), - moduleFilter = document.createElement( "span" ), - moduleFilterHtml = toolbarModuleFilterHtml(); - - if ( !toolbar || !moduleFilterHtml ) { - return false; - } - - moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); - moduleFilter.innerHTML = moduleFilterHtml; - - addEvent( moduleFilter.lastChild, "change", applyUrlParams ); - - toolbar.appendChild( moduleFilter ); -} - -function appendToolbar() { - var toolbar = id( "qunit-testrunner-toolbar" ); - - if ( toolbar ) { - toolbar.appendChild( toolbarUrlConfigContainer() ); - toolbar.appendChild( toolbarLooseFilter() ); - } -} - -function appendHeader() { - var header = id( "qunit-header" ); - - if ( header ) { - header.innerHTML = "<a href='" + - setUrl({ filter: undefined, module: undefined, testId: undefined }) + - "'>" + header.innerHTML + "</a> "; - } -} - -function appendBanner() { - var banner = id( "qunit-banner" ); - - if ( banner ) { - banner.className = ""; - } -} - -function appendTestResults() { - var tests = id( "qunit-tests" ), - result = id( "qunit-testresult" ); - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - tests.innerHTML = ""; - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...<br /> "; - } -} - -function storeFixture() { - var fixture = id( "qunit-fixture" ); - if ( fixture ) { - config.fixture = fixture.innerHTML; - } -} - -function appendFilteredTest() { - var testId = QUnit.config.testId; - if ( !testId || testId.length <= 0 ) { - return ""; - } - return "<div id='qunit-filteredTest'>Rerunning selected tests: " + testId.join(", ") + - " <a id='qunit-clearFilter' href='" + - setUrl({ filter: undefined, module: undefined, testId: undefined }) + - "'>" + "Run all tests" + "</a></div>"; -} - -function appendUserAgent() { - var userAgent = id( "qunit-userAgent" ); - - if ( userAgent ) { - userAgent.innerHTML = ""; - userAgent.appendChild( - document.createTextNode( - "QUnit " + QUnit.version + "; " + navigator.userAgent - ) - ); - } -} - -function appendTestsList( modules ) { - var i, l, x, z, test, moduleObj; - - for ( i = 0, l = modules.length; i < l; i++ ) { - moduleObj = modules[ i ]; - - if ( moduleObj.name ) { - modulesList.push( moduleObj.name ); - } - - for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) { - test = moduleObj.tests[ x ]; - - appendTest( test.name, test.testId, moduleObj.name ); - } - } -} - -function appendTest( name, testId, moduleName ) { - var title, rerunTrigger, testBlock, assertList, - tests = id( "qunit-tests" ); - - if ( !tests ) { - return; - } - - title = document.createElement( "strong" ); - title.innerHTML = getNameHtml( name, moduleName ); - - rerunTrigger = document.createElement( "a" ); - rerunTrigger.innerHTML = "Rerun"; - rerunTrigger.href = setUrl({ testId: testId }); - - testBlock = document.createElement( "li" ); - testBlock.appendChild( title ); - testBlock.appendChild( rerunTrigger ); - testBlock.id = "qunit-test-output-" + testId; - - assertList = document.createElement( "ol" ); - assertList.className = "qunit-assert-list"; - - testBlock.appendChild( assertList ); - - tests.appendChild( testBlock ); -} - -// HTML Reporter initialization and load -QUnit.begin(function( details ) { - var qunit = id( "qunit" ); - - // Fixture is the only one necessary to run without the #qunit element - storeFixture(); - - if ( qunit ) { - qunit.innerHTML = - "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" + - "<h2 id='qunit-banner'></h2>" + - "<div id='qunit-testrunner-toolbar'></div>" + - appendFilteredTest() + - "<h2 id='qunit-userAgent'></h2>" + - "<ol id='qunit-tests'></ol>"; - } - - appendHeader(); - appendBanner(); - appendTestResults(); - appendUserAgent(); - appendToolbar(); - appendTestsList( details.modules ); - toolbarModuleFilter(); - - if ( qunit && config.hidepassed ) { - addClass( qunit.lastChild, "hidepass" ); - } -}); - -QUnit.done(function( details ) { - var i, key, - banner = id( "qunit-banner" ), - tests = id( "qunit-tests" ), - html = [ - "Tests completed in ", - details.runtime, - " milliseconds.<br />", - "<span class='passed'>", - details.passed, - "</span> assertions of <span class='total'>", - details.total, - "</span> passed, <span class='failed'>", - details.failed, - "</span> failed." - ].join( "" ); - - if ( banner ) { - banner.className = details.failed ? "qunit-fail" : "qunit-pass"; - } - - if ( tests ) { - id( "qunit-testresult" ).innerHTML = html; - } - - if ( config.altertitle && defined.document && document.title ) { - - // show ✖ for good, ✔ for bad suite result in title - // use escape sequences in case file gets loaded with non-utf-8-charset - document.title = [ - ( details.failed ? "\u2716" : "\u2714" ), - document.title.replace( /^[\u2714\u2716] /i, "" ) - ].join( " " ); - } - - // clear own sessionStorage items if all tests passed - if ( config.reorder && defined.sessionStorage && details.failed === 0 ) { - for ( i = 0; i < sessionStorage.length; i++ ) { - key = sessionStorage.key( i++ ); - if ( key.indexOf( "qunit-test-" ) === 0 ) { - sessionStorage.removeItem( key ); - } - } - } - - // scroll back to top to show results - if ( config.scrolltop && window.scrollTo ) { - window.scrollTo( 0, 0 ); - } -}); - -function getNameHtml( name, module ) { - var nameHtml = ""; - - if ( module ) { - nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: "; - } - - nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>"; - - return nameHtml; -} - -QUnit.testStart(function( details ) { - var running, testBlock, bad; - - testBlock = id( "qunit-test-output-" + details.testId ); - if ( testBlock ) { - testBlock.className = "running"; - } else { - - // Report later registered tests - appendTest( details.name, details.testId, details.module ); - } - - running = id( "qunit-testresult" ); - if ( running ) { - bad = QUnit.config.reorder && defined.sessionStorage && - +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name ); - - running.innerHTML = ( bad ? - "Rerunning previously failed test: <br />" : - "Running: <br />" ) + - getNameHtml( details.name, details.module ); - } - -}); - -function stripHtml( string ) { - // strip tags, html entity and whitespaces - return string.replace(/<\/?[^>]+(>|$)/g, "").replace(/\"/g, "").replace(/\s+/g, ""); -} - -QUnit.log(function( details ) { - var assertList, assertLi, - message, expected, actual, diff, - showDiff = false, - testItem = id( "qunit-test-output-" + details.testId ); - - if ( !testItem ) { - return; - } - - message = escapeText( details.message ) || ( details.result ? "okay" : "failed" ); - message = "<span class='test-message'>" + message + "</span>"; - message += "<span class='runtime'>@ " + details.runtime + " ms</span>"; - - // pushFailure doesn't provide details.expected - // when it calls, it's implicit to also not show expected and diff stuff - // Also, we need to check details.expected existence, as it can exist and be undefined - if ( !details.result && hasOwn.call( details, "expected" ) ) { - if ( details.negative ) { - expected = escapeText( "NOT " + QUnit.dump.parse( details.expected ) ); - } else { - expected = escapeText( QUnit.dump.parse( details.expected ) ); - } - - actual = escapeText( QUnit.dump.parse( details.actual ) ); - message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + - expected + - "</pre></td></tr>"; - - if ( actual !== expected ) { - - message += "<tr class='test-actual'><th>Result: </th><td><pre>" + - actual + "</pre></td></tr>"; - - // Don't show diff if actual or expected are booleans - if ( !( /^(true|false)$/.test( actual ) ) && - !( /^(true|false)$/.test( expected ) ) ) { - diff = QUnit.diff( expected, actual ); - showDiff = stripHtml( diff ).length !== - stripHtml( expected ).length + - stripHtml( actual ).length; - } - - // Don't show diff if expected and actual are totally different - if ( showDiff ) { - message += "<tr class='test-diff'><th>Diff: </th><td><pre>" + - diff + "</pre></td></tr>"; - } - } else if ( expected.indexOf( "[object Array]" ) !== -1 || - expected.indexOf( "[object Object]" ) !== -1 ) { - message += "<tr class='test-message'><th>Message: </th><td>" + - "Diff suppressed as the depth of object is more than current max depth (" + - QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " + - " run with a higher max depth or <a href='" + setUrl({ maxDepth: -1 }) + "'>" + - "Rerun</a> without max depth.</p></td></tr>"; - } - - if ( details.source ) { - message += "<tr class='test-source'><th>Source: </th><td><pre>" + - escapeText( details.source ) + "</pre></td></tr>"; - } - - message += "</table>"; - - // this occours when pushFailure is set and we have an extracted stack trace - } else if ( !details.result && details.source ) { - message += "<table>" + - "<tr class='test-source'><th>Source: </th><td><pre>" + - escapeText( details.source ) + "</pre></td></tr>" + - "</table>"; - } - - assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; - - assertLi = document.createElement( "li" ); - assertLi.className = details.result ? "pass" : "fail"; - assertLi.innerHTML = message; - assertList.appendChild( assertLi ); -}); - -QUnit.testDone(function( details ) { - var testTitle, time, testItem, assertList, - good, bad, testCounts, skipped, sourceName, - tests = id( "qunit-tests" ); - - if ( !tests ) { - return; - } - - testItem = id( "qunit-test-output-" + details.testId ); - - assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; - - good = details.passed; - bad = details.failed; - - // store result when possible - if ( config.reorder && defined.sessionStorage ) { - if ( bad ) { - sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad ); - } else { - sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name ); - } - } - - if ( bad === 0 ) { - - // Collapse the passing tests - addClass( assertList, "qunit-collapsed" ); - } else if ( bad && config.collapse && !collapseNext ) { - - // Skip collapsing the first failing test - collapseNext = true; - } else { - - // Collapse remaining tests - addClass( assertList, "qunit-collapsed" ); - } - - // testItem.firstChild is the test name - testTitle = testItem.firstChild; - - testCounts = bad ? - "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " : - ""; - - testTitle.innerHTML += " <b class='counts'>(" + testCounts + - details.assertions.length + ")</b>"; - - if ( details.skipped ) { - testItem.className = "skipped"; - skipped = document.createElement( "em" ); - skipped.className = "qunit-skipped-label"; - skipped.innerHTML = "skipped"; - testItem.insertBefore( skipped, testTitle ); - } else { - addEvent( testTitle, "click", function() { - toggleClass( assertList, "qunit-collapsed" ); - }); - - testItem.className = bad ? "fail" : "pass"; - - time = document.createElement( "span" ); - time.className = "runtime"; - time.innerHTML = details.runtime + " ms"; - testItem.insertBefore( time, assertList ); - } - - // Show the source of the test when showing assertions - if ( details.source ) { - sourceName = document.createElement( "p" ); - sourceName.innerHTML = "<strong>Source: </strong>" + details.source; - addClass( sourceName, "qunit-source" ); - if ( bad === 0 ) { - addClass( sourceName, "qunit-collapsed" ); - } - addEvent( testTitle, "click", function() { - toggleClass( sourceName, "qunit-collapsed" ); - }); - testItem.appendChild( sourceName ); - } -}); - -if ( defined.document ) { - - // Avoid readyState issue with phantomjs - // Ref: #818 - var notPhantom = ( function( p ) { - return !( p && p.version && p.version.major > 0 ); - } )( window.phantom ); - - if ( notPhantom && document.readyState === "complete" ) { - QUnit.load(); - } else { - addEvent( window, "load", QUnit.load ); - } -} else { - config.pageLoaded = true; - config.autorun = true; -} - -})(); +}() ); diff --git a/package.json b/package.json index f273608b8..ba9883826 100644 --- a/package.json +++ b/package.json @@ -39,18 +39,25 @@ "grunt-eslint": "20.0.0", "grunt-git-authors": "3.2.0", "grunt-jsonlint": "1.1.0", + "grunt-karma": "2.0.0", "grunt-newer": "1.3.0", "grunt-npmcopy": "0.1.0", "gzip-js": "0.3.2", "husky": "0.14.3", "insight": "0.8.4", "jsdom": "5.6.1", + "karma": "1.7.0", + "karma-browserstack-launcher": "1.3.0", + "karma-chrome-launcher": "2.2.0", + "karma-firefox-launcher": "1.0.1", + "karma-qunit": "1.2.1", "load-grunt-tasks": "3.5.2", "native-promise-only": "0.8.1", "promises-aplus-tests": "2.1.2", "q": "1.5.0", - "qunit-assert-step": "1.1.1", - "qunitjs": "2.4.0", + "qunit-assert-step": "1.0.3", + "qunitjs": "1.23.1", + "raw-body": "2.2.0", "requirejs": "2.3.3", "sinon": "2.3.7", "sizzle": "2.3.3", @@ -61,8 +68,9 @@ "scripts": { "build": "npm install && grunt", "start": "grunt watch", - "test": "grunt && grunt test:slow", - "precommit": "grunt lint:newer", + "test": "grunt && grunt test:slow karma:main", + "jenkins": "grunt && grunt test:slow", + "precommit": "grunt lint:newer qunit_fixture", "commitmsg": "node node_modules/commitplease" }, "commitplease": { diff --git a/test/data/ajax/content-type.php b/test/data/ajax/content-type.php deleted file mode 100644 index 162e3636d..000000000 --- a/test/data/ajax/content-type.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - $type = $_REQUEST['content-type']; - header("Content-type: $type"); - echo $_REQUEST['response'] -?> diff --git a/test/data/ajax/evalScript.php b/test/data/ajax/evalScript.php deleted file mode 100644 index ea9b8c55f..000000000 --- a/test/data/ajax/evalScript.php +++ /dev/null @@ -1 +0,0 @@ -ok( "<?php echo $_SERVER['REQUEST_METHOD'] ?>" === "GET", "request method is <?php echo $_SERVER['REQUEST_METHOD'] ?>" );
\ No newline at end of file diff --git a/test/data/ajax/method.php b/test/data/ajax/method.php deleted file mode 100644 index d76ff964b..000000000 --- a/test/data/ajax/method.php +++ /dev/null @@ -1 +0,0 @@ -<?php echo $_SERVER['REQUEST_METHOD'] ?> diff --git a/test/data/ajax/unreleasedXHR.html b/test/data/ajax/unreleasedXHR.html index 3eedaabf8..51c5b9486 100644 --- a/test/data/ajax/unreleasedXHR.html +++ b/test/data/ajax/unreleasedXHR.html @@ -15,7 +15,7 @@ jQuery(function() { }, 200 ); var number = 50; while( number-- ) { - jQuery.ajax("../name.php?wait=10"); + jQuery.ajax("../mock.php?action=wait&wait=10"); } }); </script> diff --git a/test/data/atom+xml.php b/test/data/atom+xml.php deleted file mode 100644 index 944591abf..000000000 --- a/test/data/atom+xml.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php header("Content-type: atom+xml") ?> -<root> - <element /> -</root>
\ No newline at end of file diff --git a/test/data/core/dont_return.php b/test/data/core/dont_return.php deleted file mode 100644 index 1eef33692..000000000 --- a/test/data/core/dont_return.php +++ /dev/null @@ -1,3 +0,0 @@ -<?php -sleep(30); -?> diff --git a/test/data/core/dynamic_ready.html b/test/data/core/dynamic_ready.html index 1db068b95..e8180cd2b 100644 --- a/test/data/core/dynamic_ready.html +++ b/test/data/core/dynamic_ready.html @@ -7,7 +7,7 @@ <script src="../iframeTest.js"></script> </head> <body> -<iframe id="dont_return" src="dont_return.php"></iframe> +<iframe id="dont_return" src="../mock.php?action=wait&wait=30"></iframe> <script> var timeoutId, $, timeoutFired = false; diff --git a/test/data/csp.include.html b/test/data/csp.include.html new file mode 100644 index 000000000..17e2ef0d8 --- /dev/null +++ b/test/data/csp.include.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>CSP Test Page</title> + <script src="../jquery.js"></script> + <script src="iframeTest.js"></script> + <script src="support/csp.js"></script> + <script src="support/getComputedSupport.js"></script> +</head> +<body> + <p>CSP Test Page</p> +</body> +</html> diff --git a/test/data/echoData.php b/test/data/echoData.php deleted file mode 100644 index a37ba515a..000000000 --- a/test/data/echoData.php +++ /dev/null @@ -1 +0,0 @@ -<?php echo file_get_contents('php://input'); ?> diff --git a/test/data/echoQuery.php b/test/data/echoQuery.php deleted file mode 100644 index b72f329c9..000000000 --- a/test/data/echoQuery.php +++ /dev/null @@ -1 +0,0 @@ -<?php echo $_SERVER['QUERY_STRING']; ?>
\ No newline at end of file diff --git a/test/data/errorWithJSON.php b/test/data/errorWithJSON.php deleted file mode 100644 index 62b187ecc..000000000 --- a/test/data/errorWithJSON.php +++ /dev/null @@ -1,6 +0,0 @@ -<?php - -header("HTTP/1.0 400 Bad Request"); -header("Content-Type: application/json"); - -echo '{ "code": 40, "message": "Bad Request" }';
\ No newline at end of file diff --git a/test/data/errorWithText.php b/test/data/errorWithText.php deleted file mode 100644 index abd873217..000000000 --- a/test/data/errorWithText.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -header("HTTP/1.0 400 Bad Request"); - -echo "plain text message";
\ No newline at end of file diff --git a/test/data/etag.php b/test/data/etag.php deleted file mode 100644 index 66eca4bb1..000000000 --- a/test/data/etag.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -error_reporting(0); - -$ts = $_REQUEST['ts']; -$etag = md5($ts); - -$ifNoneMatch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : ""; -preg_match('/"([^"]+)"/', $ifNoneMatch, $matches); -$ifNoneMatch = isset($matches[1]) ? $matches[1] : false; - -if ($ifNoneMatch == $etag) { - header('HTTP/1.0 304 Not Modified'); - die; // stop processing -} - -header("Etag: W/\"" . $etag . "\""); - -if ( $ifNoneMatch ) { - echo "OK: " . $etag; -} else { - echo "FAIL"; -} - -?> diff --git a/test/data/event/interactiveReady.html b/test/data/event/interactiveReady.html index 3fb25f907..a80b79467 100644 --- a/test/data/event/interactiveReady.html +++ b/test/data/event/interactiveReady.html @@ -18,7 +18,7 @@ jQuery( function () { oldIE into thinking the dom is ready, but it's not... leaving this check here for future trailblazers to attempt fixing this...--> -<script type="text/javascript" src="../longLoadScript.php?sleep=1"></script> +<script type="text/javascript" src="../mock.php?action=wait&wait=1"></script> <div id="container" style="height: 300px"></div> </body> </html> diff --git a/test/data/event/syncReady.html b/test/data/event/syncReady.html index 61a50e423..5aa510459 100644 --- a/test/data/event/syncReady.html +++ b/test/data/event/syncReady.html @@ -18,7 +18,7 @@ jQuery( document ).ready(function () { oldIE into thinking the dom is ready, but it's not... leaving this check here for future trailblazers to attempt fixing this...--> -<script type="text/javascript" src="../longLoadScript.php?sleep=1"></script> +<script type="text/javascript" src="../mock.php?action=wait&wait=1"></script> <div id="container" style="height: 300px"></div> </body> </html> diff --git a/test/data/headers.php b/test/data/headers.php deleted file mode 100644 index 79c183055..000000000 --- a/test/data/headers.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -header( "Sample-Header: Hello World" ); -header( "Empty-Header: " ); -header( "Sample-Header2: Hello World 2" ); - -$headers = array(); - -foreach( $_SERVER as $key => $value ) { - - $key = str_replace( "_" , "-" , substr( $key , 0 , 5 ) == "HTTP_" ? substr( $key , 5 ) : $key ); - $headers[ $key ] = $value; - -} - -foreach( explode( "_" , $_GET[ "keys" ] ) as $key ) { - - // Only echo if key exists in the header - if ( isset( $headers[ strtoupper( $key ) ] ) ) { - echo "$key: " . @$headers[ strtoupper( $key ) ] . "\n"; - } - -} diff --git a/test/data/if_modified_since.php b/test/data/if_modified_since.php deleted file mode 100644 index 098b7da85..000000000 --- a/test/data/if_modified_since.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php -error_reporting(0); - -$ts = $_REQUEST['ts']; - -$ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false; -if ($ifModifiedSince == $ts) { - header('HTTP/1.0 304 Not Modified'); - die; // stop processing -} - -header("Last-Modified: " . $ts); - -if ( $ifModifiedSince ) { - echo "OK: " . $ts; -} else { - echo "FAIL"; -} - -?> diff --git a/test/data/json.php b/test/data/json.php deleted file mode 100644 index d6e0f2fc7..000000000 --- a/test/data/json.php +++ /dev/null @@ -1,13 +0,0 @@ -<?php -error_reporting(0); -if ( $_REQUEST['header'] ) { - header("Content-type: application/json"); -} - -$json = $_REQUEST['json']; -if($json) { - echo '[ {"name": "John", "age": 21}, {"name": "Peter", "age": 25 } ]'; -} else { - echo '{ "data": {"lang": "en", "length": 25} }'; -} -?> diff --git a/test/data/jsonp.php b/test/data/jsonp.php deleted file mode 100644 index 6c13d72e9..000000000 --- a/test/data/jsonp.php +++ /dev/null @@ -1,14 +0,0 @@ -<?php -error_reporting(0); -$callback = $_REQUEST['callback']; -if ( ! $callback ) { - $callback = explode("?",end(explode("/",$_SERVER['REQUEST_URI']))); - $callback = $callback[0]; -} -$json = $_REQUEST['json']; -if($json) { - echo $callback . '([ {"name": "John", "age": 21}, {"name": "Peter", "age": 25 } ])'; -} else { - echo $callback . '({ "data": {"lang": "en", "length": 25} })'; -} -?> diff --git a/test/data/longLoadScript.php b/test/data/longLoadScript.php deleted file mode 100644 index ba47168b4..000000000 --- a/test/data/longLoadScript.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php -sleep((int)$_GET['sleep']); -header('Content-type: text/javascript'); -?>
\ No newline at end of file diff --git a/test/data/mock.php b/test/data/mock.php new file mode 100644 index 000000000..692c417e8 --- /dev/null +++ b/test/data/mock.php @@ -0,0 +1,244 @@ +<?php +/** + * Keep in sync with /test/middleware-mockserver.js + */ +class MockServer { + protected function contentType( $req ) { + $type = $req->query['contentType']; + header("Content-type: $type"); + echo $req->query['response']; + } + + protected function wait( $req ) { + $wait = (int) $req->query['wait']; + sleep( $wait ); + if ( isset( $req->query['script'] ) ) { + header( 'Content-type: text/javascript' ); + } else { + header( 'Content-type: text/html' ); + echo 'ERROR <script>ok( true, "mock executed" );</script>'; + } + } + + protected function name( $req ) { + if ( $req->query['name'] === 'foo' ) { + echo 'bar'; + } elseif ( $_POST['name'] === 'peter' ) { + echo 'pan'; + } else { + echo 'ERROR'; + } + } + + protected function xml( $req ) { + header( 'Content-type: text/xml' ); + if ( $req->query['cal'] !== '5-2' && $_POST['cal'] !== '5-2' ) { + echo '<error>ERROR</error>'; + return; + } + echo "<math><calculation>5-2</calculation><result>3</result></math>\n"; + } + + protected function atom( $req ) { + header( 'Content-type: atom+xml' ); + echo '<root><element /></root>'; + } + + protected function script( $req ) { + if ( isset( $req->query['header'] ) ) { + if ( $req->query['header'] === 'ecma' ) { + header( 'Content-type: application/ecmascript' ); + } else { + header( 'Content-type: text/javascript' ); + } + } else { + header( 'Content-type: text/html' ); + } + echo 'ok( true, "mock executed" );'; + } + + // Used to be in test.js, but was renamed to testbar.php + // https://github.com/jquery/jquery/commit/d89c278a33#commitcomment-23423165 + protected function testbar( $req ) { + echo 'this.testBar = "bar"; +jQuery("#ap").html("bar"); +ok( true, "mock executed");'; + } + + protected function json( $req ) { + if ( isset( $req->query['header'] ) ) { + header( 'Content-type: application/json' ); + } + + if ( isset( $req->query['array'] ) ) { + echo '[ {"name": "John", "age": 21}, {"name": "Peter", "age": 25 } ]'; + } else { + echo '{ "data": {"lang": "en", "length": 25} }'; + } + } + + protected function jsonp( $req ) { + if ( isset( $req->query['callback'] ) ) { + $callback = $req->query['callback']; + } elseif ( $req->method === 'GET' ) { + // Try REST-like path + preg_match( '/\/([^\/?]+)\?.+$/', $req->url, $m ); + $callback = $m[1]; + } else { + $callback = $_POST['callback']; + } + if ( isset( $req->query['array'] ) ) { + echo $callback . '([ {"name": "John", "age": 21}, {"name": "Peter", "age": 25 } ])'; + } else { + echo $callback . '({ "data": {"lang": "en", "length": 25} })'; + } + } + + protected function xmlOverJsonp( $req ) { + $callback = $_REQUEST['callback']; + $text = json_encode( file_get_contents( __DIR__ . '/with_fries.xml' ) ); + echo "$callback($text)\n"; + } + + protected function error( $req ) { + header( 'HTTP/1.0 400 Bad Request' ); + if ( isset( $req->query['json'] ) ) { + header( 'Content-Type: application/json' ); + echo '{ "code": 40, "message": "Bad Request" }'; + } else { + echo 'plain text message'; + } + } + + protected function headers( $req ) { + header( 'Sample-Header: Hello World' ); + header( 'Empty-Header: ' ); + header( 'Sample-Header2: Hello World 2' ); + + foreach ( explode( '|' , $req->query[ 'keys' ] ) as $key ) { + // Only echo if key exists in the header + if ( isset( $req->headers[ strtoupper( $key ) ] ) ) { + echo "$key: " . $req->headers[ strtoupper( $key ) ] . "\n"; + } + } + + } + + protected function echoData( $req ) { + echo file_get_contents('php://input'); + } + + protected function echoQuery( $req ) { + echo $_SERVER['QUERY_STRING']; + } + + protected function echoMethod( $req ) { + echo $req->method; + } + + protected function echoHtml( $req ) { + header( 'Content-type: text/html' ); + echo '<div id="method">' . $req->method . '</div>'; + echo '<div id="query">' . $_SERVER['QUERY_STRING'] . '</div>'; + echo '<div id="data">' . file_get_contents('php://input') . '</div>'; + } + + protected function etag( $req ) { + $hash = md5( $req->query['ts'] ); + $etag = 'W/"' . $hash . '"'; + + $ifNoneMatch = isset( $req->headers['IF-NONE-MATCH'] ) ? $req->headers['IF-NONE-MATCH'] : ''; + if ($ifNoneMatch === $etag) { + header('HTTP/1.0 304 Not Modified'); + return; + } + + header("Etag: $etag"); + echo "ETag: $etag\n"; + if ( $ifNoneMatch ) { + echo "If-None-Match: $ifNoneMatch\n"; + } + } + + protected function ims( $req ) { + $ts = $req->query['ts']; + + $ims = isset( $req->headers['IF-MODIFIED-SINCE'] ) ? $req->headers['IF-MODIFIED-SINCE'] : ''; + if ($ims === $ts) { + header('HTTP/1.0 304 Not Modified'); + return; + } + + header("Last-Modified: $ts"); + echo "Last-Modified: $ts\n"; + if ( $ims ) { + echo "If-Modified-Since: $ims\n"; + } + } + + protected function status( $req ) { + header( "HTTP/1.0 {$req->query['code']} {$req->query['text']}" ); + } + + protected function testHTML( $req ) { + header( 'Content-type: text/html' ); + $html = file_get_contents( __DIR__ . '/test.include.html' ); + $html = str_replace( '{{baseURL}}', $req->query['baseURL'], $html ); + echo $html; + } + + protected function cspFrame( $req ) { + // This is CSP only for browsers with "Content-Security-Policy" header support + // i.e. no old WebKit or old Firefox + header( "Content-Security-Policy: default-src 'self'; report-uri ./mock.php?action=cspLog" ); + header( 'Content-type: text/html' ); + echo file_get_contents( __DIR__ . '/csp.include.html' ); + } + + protected function cspLog( $req ) { + file_put_contents( $this->cspFile, 'error' ); + } + + protected function cspClean( $req ) { + file_put_contents( $this->cspFile, '' ); + unlink( $this->cspFile ); + } + + public function __construct() { + $this->cspFile = __DIR__ . '/support/csp.log'; + } + + public function respond( stdClass $req ) { + if ( !isset( $req->query['action'] ) || !method_exists( $this, $req->query['action'] ) ) { + header( "HTTP/1.0 400 Bad Request" ); + echo "Invalid action query.\n"; + return; + } + $this->{$req->query['action']}( $req ); + } +} + +// Don't include PHP errors in http response +error_reporting( 0 ); + +// Collect headers +$headers = array(); +foreach ( $_SERVER as $name => $value ) { + if ( substr( $name, 0, 5 ) === 'HTTP_' ) { + $name = str_replace( '_', '-', substr( $name, 5 ) ); + $headers[$name] = $value; + } elseif ( $name === 'CONTENT_LENGTH' ) { + $headers['CONTENT-LENGTH'] = $value; + } elseif ( $name === 'CONTENT_TYPE' ) { + $headers['CONTENT-TYPE'] = $value; + } +} + +$mock = new MockServer(); +$req = (object) array( + 'query' => $_GET, + 'headers' => $headers, + 'method' => $_SERVER['REQUEST_METHOD'], + 'url' => $_SERVER['REQUEST_URI'], +); +$mock->respond( $req ); diff --git a/test/data/name.php b/test/data/name.php deleted file mode 100644 index 64028585d..000000000 --- a/test/data/name.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -error_reporting(0); -$wait = $_REQUEST['wait']; -if($wait) { - sleep($wait); -} -$xml = $_REQUEST['xml']; -if($xml) { - header("Content-type: text/xml"); - $result = ($xml == "5-2") ? "3" : "?"; - echo "<math><calculation>$xml</calculation><result>$result</result></math>"; - die(); -} -$name = $_REQUEST['name']; -if($name == 'foo') { - echo "bar"; - die(); -} else if($name == 'peter') { - echo "pan"; - die(); -} - -echo 'ERROR <script type="text/javascript">ok( true, "name.php executed" );</script>'; -?>
\ No newline at end of file diff --git a/test/data/nocontent.php b/test/data/nocontent.php deleted file mode 100644 index 9c8431bd7..000000000 --- a/test/data/nocontent.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -header('HTTP/1.0 204 No Content'); - -?>
\ No newline at end of file diff --git a/test/data/params_html.php b/test/data/params_html.php deleted file mode 100644 index e88ef1521..000000000 --- a/test/data/params_html.php +++ /dev/null @@ -1,12 +0,0 @@ -<div id="post"> -<?php - foreach( $_POST as $key=>$value ) - echo "<b id='$key'>$value</b>"; -?> -</div> -<div id="get"> -<?php - foreach( $_GET as $key=>$value ) - echo "<b id='$key'>$value</b>"; -?> -</div>
\ No newline at end of file diff --git a/test/data/qunit-fixture.html b/test/data/qunit-fixture.html new file mode 100644 index 000000000..e0fd3e60e --- /dev/null +++ b/test/data/qunit-fixture.html @@ -0,0 +1,237 @@ +<p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p> +<p id="ap"> + Here are some links in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>, + <a id="groups" href="http://groups.google.com/" class="GROUPS">Google Groups (Link)</a>. + This link has <code><a href="http://smin" id="anchor1">class="blog"</a></code>: + <a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a> + +</p> +<div id="foo"> + <p id="sndp">Everything inside the red border is inside a div with <code>id="foo"</code>.</p> + <p lang="en" id="en">This is a normal link: <a id="yahoo" href="http://www.yahoo.com/" class="blogTest">Yahoo</a></p> + <p id="sap">This link has <code><a href="#2" id="anchor2">class="blog"</a></code>: <a href="http://simon.incutio.com/" class="blog link" id="simon">Simon Willison's Weblog</a></p> + +</div> +<div id="nothiddendiv" style="height:1px;background:white;" class="nothiddendiv"> + <div id="nothiddendivchild"></div> +</div> +<span id="name+value"></span> +<p id="first">Try them out:</p> +<ul id="firstUL"></ul> +<ol id="empty"></ol> +<form id="form" action="formaction"> + <label for="action" id="label-for">Action:</label> + <input type="text" name="action" value="Test" id="text1" maxlength="30"/> + <input type="text" name="text2" value="Test" id="text2" disabled="disabled"/> + <input type="radio" name="radio1" id="radio1" value="on"/> + + <input type="radio" name="radio2" id="radio2" checked="checked"/> + <input type="checkbox" name="check" id="check1" checked="checked"/> + <input type="checkbox" id="check2" value="on"/> + + <input type="hidden" name="hidden" id="hidden1"/> + <input type="text" style="display:none;" name="foo[bar]" id="hidden2"/> + + <input type="text" id="name" name="name" value="name" /> + <input type="search" id="search" name="search" value="search" /> + + <button id="button" name="button" type="button">Button</button> + + <textarea id="area1" maxlength="30">foobar</textarea> + + <select name="select1" id="select1"> + <option id="option1a" class="emptyopt" value="">Nothing</option> + <option id="option1b" value="1">1</option> + <option id="option1c" value="2">2</option> + <option id="option1d" value="3">3</option> + </select> + <select name="select2" id="select2"> + <option id="option2a" class="emptyopt" value="">Nothing</option> + <option id="option2b" value="1">1</option> + <option id="option2c" value="2">2</option> + <option id="option2d" selected="selected" value="3">3</option> + </select> + <select name="select3" id="select3" multiple="multiple"> + <option id="option3a" class="emptyopt" value="">Nothing</option> + <option id="option3b" selected="selected" value="1">1</option> + <option id="option3c" selected="selected" value="2">2</option> + <option id="option3d" value="3">3</option> + <option id="option3e">no value</option> + </select> + <select name="select4" id="select4" multiple="multiple"> + <optgroup disabled="disabled"> + <option id="option4a" class="emptyopt" value="">Nothing</option> + <option id="option4b" disabled="disabled" selected="selected" value="1">1</option> + <option id="option4c" selected="selected" value="2">2</option> + </optgroup> + <option selected="selected" disabled="disabled" id="option4d" value="3">3</option> + <option id="option4e">no value</option> + </select> + <select name="select5" id="select5"> + <option id="option5a" value="3">1</option> + <option id="option5b" value="2">2</option> + <option id="option5c" value="1" data-attr="">3</option> + </select> + + <object id="object1" codebase="stupid"> + <param name="p1" value="x1" /> + <param name="p2" value="x2" /> + </object> + + <span id="台北Táiběi"></span> + <span id="台北" lang="中文"></span> + <span id="utf8class1" class="台北Táiběi 台北"></span> + <span id="utf8class2" class="台北"></span> + <span id="foo:bar" class="foo:bar"></span> + <span id="test.foo[5]bar" class="test.foo[5]bar"></span> + + <foo_bar id="foobar">test element</foo_bar> +</form> +<b id="floatTest">Float test.</b> +<iframe id="iframe" name="iframe"></iframe> +<form id="lengthtest"> + <input type="text" id="length" name="test"/> + <input type="text" id="idTest" name="id"/> +</form> +<table id="table"></table> + +<form id="name-tests"> + <!-- Inputs with a grouped name attribute. --> + <input name="types[]" id="types_all" type="checkbox" value="all" /> + <input name="types[]" id="types_anime" type="checkbox" value="anime" /> + <input name="types[]" id="types_movie" type="checkbox" value="movie" /> +</form> + +<form id="testForm" action="#" method="get"> + <textarea name="T3" rows="2" cols="15">? +Z</textarea> + <input type="hidden" name="H1" value="x" /> + <input type="hidden" name="H2" /> + <input name="PWD" type="password" value="" /> + <input name="T1" type="text" /> + <input name="T2" type="text" value="YES" readonly="readonly" /> + <input type="checkbox" name="C1" value="1" /> + <input type="checkbox" name="C2" /> + <input type="radio" name="R1" value="1" /> + <input type="radio" name="R1" value="2" /> + <input type="text" name="My Name" value="me" /> + <input type="reset" name="reset" value="NO" /> + <select name="S1"> + <option value="abc">ABC</option> + <option value="abc">ABC</option> + <option value="abc">ABC</option> + </select> + <select name="S2" multiple="multiple" size="3"> + <option value="abc">ABC</option> + <option value="abc">ABC</option> + <option value="abc">ABC</option> + </select> + <select name="S3"> + <option selected="selected">YES</option> + </select> + <select name="S4"> + <option value="" selected="selected">NO</option> + </select> + <input type="submit" name="sub1" value="NO" /> + <input type="submit" name="sub2" value="NO" /> + <input type="image" name="sub3" value="NO" /> + <button name="sub4" type="submit" value="NO">NO</button> + <input name="D1" type="text" value="NO" disabled="disabled" /> + <input type="checkbox" checked="checked" disabled="disabled" name="D2" value="NO" /> + <input type="radio" name="D3" value="NO" checked="checked" disabled="disabled" /> + <select name="D4" disabled="disabled"> + <option selected="selected" value="NO">NO</option> + </select> + <input id="list-test" type="text" /> + <datalist id="datalist"> + <option value="option"></option> + </datalist> +</form> +<div id="moretests"> + <form> + <div id="checkedtest" style="display:none;"> + <input type="radio" name="checkedtestradios" checked="checked"/> + <input type="radio" name="checkedtestradios" value="on"/> + <input type="checkbox" name="checkedtestcheckboxes" checked="checked"/> + <input type="checkbox" name="checkedtestcheckboxes" /> + </div> + </form> + <div id="nonnodes"><span id="nonnodesElement">hi</span> there <!-- mon ami --></div> + <div id="t2037"> + <div><div class="hidden">hidden</div></div> + </div> + <div id="t6652"> + <div></div> + </div> + <div id="no-clone-exception"><object><embed></embed></object></div> +</div> + +<div id="tabindex-tests"> + <ol id="listWithTabIndex" tabindex="5"> + <li id="foodWithNegativeTabIndex" tabindex="-1">Rice</li> + <li id="foodNoTabIndex">Beans</li> + <li>Blinis</li> + <li>Tofu</li> + </ol> + + <div id="divWithNoTabIndex">I'm hungry. I should...</div> + <span>...</span><a href="#" id="linkWithNoTabIndex">Eat lots of food</a><span>...</span> | + <span>...</span><a href="#" id="linkWithTabIndex" tabindex="2">Eat a little food</a><span>...</span> | + <span>...</span><a href="#" id="linkWithNegativeTabIndex" tabindex="-1">Eat no food</a><span>...</span> + <span>...</span><a id="linkWithNoHrefWithNoTabIndex">Eat a burger</a><span>...</span> + <span>...</span><a id="linkWithNoHrefWithTabIndex" tabindex="1">Eat some funyuns</a><span>...</span> + <span>...</span><a id="linkWithNoHrefWithNegativeTabIndex" tabindex="-1">Eat some funyuns</a><span>...</span> + <input id="inputWithoutTabIndex"/> + <button id="buttonWithoutTabIndex"></button> + <textarea id="textareaWithoutTabIndex"></textarea> + <menu type="popup"> + <menuitem id="menuitemWithoutTabIndex" command="submitbutton" default/> + </menu> +</div> + +<div id="liveHandlerOrder"> + <span id="liveSpan1"><a href="#" id="liveLink1"></a></span> + <span id="liveSpan2"><a href="#" id="liveLink2"></a></span> +</div> + +<div id="siblingTest"> + <em id="siblingfirst">1</em> + <em id="siblingnext">2</em> + <em id="siblingthird"> + <em id="siblingchild"> + <em id="siblinggrandchild"> + <em id="siblinggreatgrandchild"></em> + </em> + </em> + </em> + <span id="siblingspan"></span> +</div> +<div id="fx-test-group" style="position: absolute; width: 1px; height: 1px; overflow: hidden;"> + <div id="fx-queue" name="test"> + <div id="fadein" class='chain-test' name='div'>fadeIn<div>fadeIn</div></div> + <div id="fadeout" class='chain-test chain-test-out'>fadeOut<div>fadeOut</div></div> + + <div id="show" class='chain-test'>show<div>show</div></div> + <div id="hide" class='chain-test chain-test-out'>hide<div>hide</div></div> + <div id="easehide" class='chain-test chain-test-out'>hide<div>hide</div></div> + + <div id="togglein" class='chain-test'>togglein<div>togglein</div></div> + <div id="toggleout" class='chain-test chain-test-out'>toggleout<div>toggleout</div></div> + <div id="easetoggleout" class='chain-test chain-test-out'>toggleout<div>toggleout</div></div> + + <div id="slideup" class='chain-test'>slideUp<div>slideUp</div></div> + <div id="slidedown" class='chain-test chain-test-out'>slideDown<div>slideDown</div></div> + <div id="easeslideup" class='chain-test'>slideUp<div>slideUp</div></div> + + <div id="slidetogglein" class='chain-test'>slideToggleIn<div>slideToggleIn</div></div> + <div id="slidetoggleout" class='chain-test chain-test-out'>slideToggleOut<div>slideToggleOut</div></div> + + <div id="fadetogglein" class='chain-test'>fadeToggleIn<div>fadeToggleIn</div></div> + <div id="fadetoggleout" class='chain-test chain-test-out'>fadeToggleOut<div>fadeToggleOut</div></div> + + <div id="fadeto" class='chain-test'>fadeTo<div>fadeTo</div></div> + </div> + + <div id="fx-tests"></div> + <span id="display"></span> +</div> diff --git a/test/data/qunit-fixture.js b/test/data/qunit-fixture.js new file mode 100644 index 000000000..6ea2f3b3d --- /dev/null +++ b/test/data/qunit-fixture.js @@ -0,0 +1,4 @@ +// Generated by build/tasks/qunit_fixture.js +QUnit.config.fixture = "<p id=\"firstp\">See <a id=\"simon1\" href=\"http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector\" rel=\"bookmark\">this blog entry</a> for more information.</p>\n<p id=\"ap\">\n\tHere are some links in a normal paragraph: <a id=\"google\" href=\"http://www.google.com/\" title=\"Google!\">Google</a>,\n\t<a id=\"groups\" href=\"http://groups.google.com/\" class=\"GROUPS\">Google Groups (Link)</a>.\n\tThis link has <code><a href=\"http://smin\" id=\"anchor1\">class=\"blog\"</a></code>:\n\t<a href=\"http://diveintomark.org/\" class=\"blog\" hreflang=\"en\" id=\"mark\">diveintomark</a>\n\n</p>\n<div id=\"foo\">\n\t<p id=\"sndp\">Everything inside the red border is inside a div with <code>id=\"foo\"</code>.</p>\n\t<p lang=\"en\" id=\"en\">This is a normal link: <a id=\"yahoo\" href=\"http://www.yahoo.com/\" class=\"blogTest\">Yahoo</a></p>\n\t<p id=\"sap\">This link has <code><a href=\"#2\" id=\"anchor2\">class=\"blog\"</a></code>: <a href=\"http://simon.incutio.com/\" class=\"blog link\" id=\"simon\">Simon Willison's Weblog</a></p>\n\n</div>\n<div id=\"nothiddendiv\" style=\"height:1px;background:white;\" class=\"nothiddendiv\">\n\t<div id=\"nothiddendivchild\"></div>\n</div>\n<span id=\"name+value\"></span>\n<p id=\"first\">Try them out:</p>\n<ul id=\"firstUL\"></ul>\n<ol id=\"empty\"></ol>\n<form id=\"form\" action=\"formaction\">\n\t<label for=\"action\" id=\"label-for\">Action:</label>\n\t<input type=\"text\" name=\"action\" value=\"Test\" id=\"text1\" maxlength=\"30\"/>\n\t<input type=\"text\" name=\"text2\" value=\"Test\" id=\"text2\" disabled=\"disabled\"/>\n\t<input type=\"radio\" name=\"radio1\" id=\"radio1\" value=\"on\"/>\n\n\t<input type=\"radio\" name=\"radio2\" id=\"radio2\" checked=\"checked\"/>\n\t<input type=\"checkbox\" name=\"check\" id=\"check1\" checked=\"checked\"/>\n\t<input type=\"checkbox\" id=\"check2\" value=\"on\"/>\n\n\t<input type=\"hidden\" name=\"hidden\" id=\"hidden1\"/>\n\t<input type=\"text\" style=\"display:none;\" name=\"foo[bar]\" id=\"hidden2\"/>\n\n\t<input type=\"text\" id=\"name\" name=\"name\" value=\"name\" />\n\t<input type=\"search\" id=\"search\" name=\"search\" value=\"search\" />\n\n\t<button id=\"button\" name=\"button\" type=\"button\">Button</button>\n\n\t<textarea id=\"area1\" maxlength=\"30\">foobar</textarea>\n\n\t<select name=\"select1\" id=\"select1\">\n\t\t<option id=\"option1a\" class=\"emptyopt\" value=\"\">Nothing</option>\n\t\t<option id=\"option1b\" value=\"1\">1</option>\n\t\t<option id=\"option1c\" value=\"2\">2</option>\n\t\t<option id=\"option1d\" value=\"3\">3</option>\n\t</select>\n\t<select name=\"select2\" id=\"select2\">\n\t\t<option id=\"option2a\" class=\"emptyopt\" value=\"\">Nothing</option>\n\t\t<option id=\"option2b\" value=\"1\">1</option>\n\t\t<option id=\"option2c\" value=\"2\">2</option>\n\t\t<option id=\"option2d\" selected=\"selected\" value=\"3\">3</option>\n\t</select>\n\t<select name=\"select3\" id=\"select3\" multiple=\"multiple\">\n\t\t<option id=\"option3a\" class=\"emptyopt\" value=\"\">Nothing</option>\n\t\t<option id=\"option3b\" selected=\"selected\" value=\"1\">1</option>\n\t\t<option id=\"option3c\" selected=\"selected\" value=\"2\">2</option>\n\t\t<option id=\"option3d\" value=\"3\">3</option>\n\t\t<option id=\"option3e\">no value</option>\n\t</select>\n\t<select name=\"select4\" id=\"select4\" multiple=\"multiple\">\n\t\t<optgroup disabled=\"disabled\">\n\t\t\t<option id=\"option4a\" class=\"emptyopt\" value=\"\">Nothing</option>\n\t\t\t<option id=\"option4b\" disabled=\"disabled\" selected=\"selected\" value=\"1\">1</option>\n\t\t\t<option id=\"option4c\" selected=\"selected\" value=\"2\">2</option>\n\t\t</optgroup>\n\t\t<option selected=\"selected\" disabled=\"disabled\" id=\"option4d\" value=\"3\">3</option>\n\t\t<option id=\"option4e\">no value</option>\n\t</select>\n\t<select name=\"select5\" id=\"select5\">\n\t\t<option id=\"option5a\" value=\"3\">1</option>\n\t\t<option id=\"option5b\" value=\"2\">2</option>\n\t\t<option id=\"option5c\" value=\"1\" data-attr=\"\">3</option>\n\t</select>\n\n\t<object id=\"object1\" codebase=\"stupid\">\n\t\t<param name=\"p1\" value=\"x1\" />\n\t\t<param name=\"p2\" value=\"x2\" />\n\t</object>\n\n\t<span id=\"台北Táiběi\"></span>\n\t<span id=\"台北\" lang=\"中文\"></span>\n\t<span id=\"utf8class1\" class=\"台北Táiběi 台北\"></span>\n\t<span id=\"utf8class2\" class=\"台北\"></span>\n\t<span id=\"foo:bar\" class=\"foo:bar\"></span>\n\t<span id=\"test.foo[5]bar\" class=\"test.foo[5]bar\"></span>\n\n\t<foo_bar id=\"foobar\">test element</foo_bar>\n</form>\n<b id=\"floatTest\">Float test.</b>\n<iframe id=\"iframe\" name=\"iframe\"></iframe>\n<form id=\"lengthtest\">\n\t<input type=\"text\" id=\"length\" name=\"test\"/>\n\t<input type=\"text\" id=\"idTest\" name=\"id\"/>\n</form>\n<table id=\"table\"></table>\n\n<form id=\"name-tests\">\n\t<!-- Inputs with a grouped name attribute. -->\n\t<input name=\"types[]\" id=\"types_all\" type=\"checkbox\" value=\"all\" />\n\t<input name=\"types[]\" id=\"types_anime\" type=\"checkbox\" value=\"anime\" />\n\t<input name=\"types[]\" id=\"types_movie\" type=\"checkbox\" value=\"movie\" />\n</form>\n\n<form id=\"testForm\" action=\"#\" method=\"get\">\n\t<textarea name=\"T3\" rows=\"2\" cols=\"15\">?\nZ</textarea>\n\t<input type=\"hidden\" name=\"H1\" value=\"x\" />\n\t<input type=\"hidden\" name=\"H2\" />\n\t<input name=\"PWD\" type=\"password\" value=\"\" />\n\t<input name=\"T1\" type=\"text\" />\n\t<input name=\"T2\" type=\"text\" value=\"YES\" readonly=\"readonly\" />\n\t<input type=\"checkbox\" name=\"C1\" value=\"1\" />\n\t<input type=\"checkbox\" name=\"C2\" />\n\t<input type=\"radio\" name=\"R1\" value=\"1\" />\n\t<input type=\"radio\" name=\"R1\" value=\"2\" />\n\t<input type=\"text\" name=\"My Name\" value=\"me\" />\n\t<input type=\"reset\" name=\"reset\" value=\"NO\" />\n\t<select name=\"S1\">\n\t\t<option value=\"abc\">ABC</option>\n\t\t<option value=\"abc\">ABC</option>\n\t\t<option value=\"abc\">ABC</option>\n\t</select>\n\t<select name=\"S2\" multiple=\"multiple\" size=\"3\">\n\t\t<option value=\"abc\">ABC</option>\n\t\t<option value=\"abc\">ABC</option>\n\t\t<option value=\"abc\">ABC</option>\n\t</select>\n\t<select name=\"S3\">\n\t\t<option selected=\"selected\">YES</option>\n\t</select>\n\t<select name=\"S4\">\n\t\t<option value=\"\" selected=\"selected\">NO</option>\n\t</select>\n\t<input type=\"submit\" name=\"sub1\" value=\"NO\" />\n\t<input type=\"submit\" name=\"sub2\" value=\"NO\" />\n\t<input type=\"image\" name=\"sub3\" value=\"NO\" />\n\t<button name=\"sub4\" type=\"submit\" value=\"NO\">NO</button>\n\t<input name=\"D1\" type=\"text\" value=\"NO\" disabled=\"disabled\" />\n\t<input type=\"checkbox\" checked=\"checked\" disabled=\"disabled\" name=\"D2\" value=\"NO\" />\n\t<input type=\"radio\" name=\"D3\" value=\"NO\" checked=\"checked\" disabled=\"disabled\" />\n\t<select name=\"D4\" disabled=\"disabled\">\n\t\t<option selected=\"selected\" value=\"NO\">NO</option>\n\t</select>\n\t<input id=\"list-test\" type=\"text\" />\n\t<datalist id=\"datalist\">\n\t\t<option value=\"option\"></option>\n\t</datalist>\n</form>\n<div id=\"moretests\">\n\t<form>\n\t\t<div id=\"checkedtest\" style=\"display:none;\">\n\t\t\t<input type=\"radio\" name=\"checkedtestradios\" checked=\"checked\"/>\n\t\t\t<input type=\"radio\" name=\"checkedtestradios\" value=\"on\"/>\n\t\t\t<input type=\"checkbox\" name=\"checkedtestcheckboxes\" checked=\"checked\"/>\n\t\t\t<input type=\"checkbox\" name=\"checkedtestcheckboxes\" />\n\t\t</div>\n\t</form>\n\t<div id=\"nonnodes\"><span id=\"nonnodesElement\">hi</span> there <!-- mon ami --></div>\n\t<div id=\"t2037\">\n\t\t<div><div class=\"hidden\">hidden</div></div>\n\t</div>\n\t<div id=\"t6652\">\n\t\t<div></div>\n\t</div>\n\t<div id=\"no-clone-exception\"><object><embed></embed></object></div>\n</div>\n\n<div id=\"tabindex-tests\">\n\t<ol id=\"listWithTabIndex\" tabindex=\"5\">\n\t\t<li id=\"foodWithNegativeTabIndex\" tabindex=\"-1\">Rice</li>\n\t\t<li id=\"foodNoTabIndex\">Beans</li>\n\t\t<li>Blinis</li>\n\t\t<li>Tofu</li>\n\t</ol>\n\n\t<div id=\"divWithNoTabIndex\">I'm hungry. I should...</div>\n\t<span>...</span><a href=\"#\" id=\"linkWithNoTabIndex\">Eat lots of food</a><span>...</span> |\n\t<span>...</span><a href=\"#\" id=\"linkWithTabIndex\" tabindex=\"2\">Eat a little food</a><span>...</span> |\n\t<span>...</span><a href=\"#\" id=\"linkWithNegativeTabIndex\" tabindex=\"-1\">Eat no food</a><span>...</span>\n\t<span>...</span><a id=\"linkWithNoHrefWithNoTabIndex\">Eat a burger</a><span>...</span>\n\t<span>...</span><a id=\"linkWithNoHrefWithTabIndex\" tabindex=\"1\">Eat some funyuns</a><span>...</span>\n\t<span>...</span><a id=\"linkWithNoHrefWithNegativeTabIndex\" tabindex=\"-1\">Eat some funyuns</a><span>...</span>\n\t<input id=\"inputWithoutTabIndex\"/>\n\t<button id=\"buttonWithoutTabIndex\"></button>\n\t<textarea id=\"textareaWithoutTabIndex\"></textarea>\n\t<menu type=\"popup\">\n\t\t<menuitem id=\"menuitemWithoutTabIndex\" command=\"submitbutton\" default/>\n\t</menu>\n</div>\n\n<div id=\"liveHandlerOrder\">\n\t<span id=\"liveSpan1\"><a href=\"#\" id=\"liveLink1\"></a></span>\n\t<span id=\"liveSpan2\"><a href=\"#\" id=\"liveLink2\"></a></span>\n</div>\n\n<div id=\"siblingTest\">\n\t<em id=\"siblingfirst\">1</em>\n\t<em id=\"siblingnext\">2</em>\n\t<em id=\"siblingthird\">\n\t\t<em id=\"siblingchild\">\n\t\t\t<em id=\"siblinggrandchild\">\n\t\t\t\t<em id=\"siblinggreatgrandchild\"></em>\n\t\t\t</em>\n\t\t</em>\n\t</em>\n\t<span id=\"siblingspan\"></span>\n</div>\n<div id=\"fx-test-group\" style=\"position: absolute; width: 1px; height: 1px; overflow: hidden;\">\n\t<div id=\"fx-queue\" name=\"test\">\n\t\t<div id=\"fadein\" class='chain-test' name='div'>fadeIn<div>fadeIn</div></div>\n\t\t<div id=\"fadeout\" class='chain-test chain-test-out'>fadeOut<div>fadeOut</div></div>\n\n\t\t<div id=\"show\" class='chain-test'>show<div>show</div></div>\n\t\t<div id=\"hide\" class='chain-test chain-test-out'>hide<div>hide</div></div>\n\t\t<div id=\"easehide\" class='chain-test chain-test-out'>hide<div>hide</div></div>\n\n\t\t<div id=\"togglein\" class='chain-test'>togglein<div>togglein</div></div>\n\t\t<div id=\"toggleout\" class='chain-test chain-test-out'>toggleout<div>toggleout</div></div>\n\t\t<div id=\"easetoggleout\" class='chain-test chain-test-out'>toggleout<div>toggleout</div></div>\n\n\t\t<div id=\"slideup\" class='chain-test'>slideUp<div>slideUp</div></div>\n\t\t<div id=\"slidedown\" class='chain-test chain-test-out'>slideDown<div>slideDown</div></div>\n\t\t<div id=\"easeslideup\" class='chain-test'>slideUp<div>slideUp</div></div>\n\n\t\t<div id=\"slidetogglein\" class='chain-test'>slideToggleIn<div>slideToggleIn</div></div>\n\t\t<div id=\"slidetoggleout\" class='chain-test chain-test-out'>slideToggleOut<div>slideToggleOut</div></div>\n\n\t\t<div id=\"fadetogglein\" class='chain-test'>fadeToggleIn<div>fadeToggleIn</div></div>\n\t\t<div id=\"fadetoggleout\" class='chain-test chain-test-out'>fadeToggleOut<div>fadeToggleOut</div></div>\n\n\t\t<div id=\"fadeto\" class='chain-test'>fadeTo<div>fadeTo</div></div>\n\t</div>\n\n\t<div id=\"fx-tests\"></div>\n\t<span id=\"display\"></span>\n</div>\n"; +// Compat with QUnit 1.x: +document.getElementById( "qunit-fixture" ).innerHTML = QUnit.config.fixture; diff --git a/test/data/script.php b/test/data/script.php deleted file mode 100644 index fb7110491..000000000 --- a/test/data/script.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php -error_reporting(0); -if ( $_REQUEST['header'] ) { - if ( $_REQUEST['header'] == "ecma" ) { - header("Content-type: application/ecmascript"); - } else { - header("Content-type: text/javascript"); - } -} -?> -ok( true, "Script executed correctly." ); diff --git a/test/data/statusText.php b/test/data/statusText.php deleted file mode 100644 index daf58ce3f..000000000 --- a/test/data/statusText.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -header( "HTTP/1.0 $_GET[status] $_GET[text]" ); - -?>
\ No newline at end of file diff --git a/test/data/support/csp-clean.php b/test/data/support/csp-clean.php deleted file mode 100644 index e16d047a3..000000000 --- a/test/data/support/csp-clean.php +++ /dev/null @@ -1,3 +0,0 @@ -<?php - file_put_contents("csp.log", "", LOCK_EX); -?> diff --git a/test/data/support/csp-log.php b/test/data/support/csp-log.php deleted file mode 100644 index efbb9d7bc..000000000 --- a/test/data/support/csp-log.php +++ /dev/null @@ -1,3 +0,0 @@ -<?php - file_put_contents("csp.log", "error", LOCK_EX); -?> diff --git a/test/data/support/csp.php b/test/data/support/csp.php deleted file mode 100644 index 446000239..000000000 --- a/test/data/support/csp.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - # This test page checks CSP only for browsers with "Content-Security-Policy" header support - # i.e. no old WebKit or old Firefox - header("Content-Security-Policy: default-src 'self'; report-uri csp-log.php"); -?> -<!DOCTYPE html> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title>CSP Test Page</title> - <script src="../../jquery.js"></script> - <script src="../iframeTest.js"></script> - <script src="csp.js"></script> - <script src="getComputedSupport.js"></script> -</head> -<body> - <p>CSP Test Page</p> -</body> -</html> diff --git a/test/data/test.html b/test/data/test.include.html index f5bc2199f..73299db07 100644 --- a/test/data/test.html +++ b/test/data/test.include.html @@ -1,7 +1,7 @@ html text<br/> <script type="text/javascript">/* <![CDATA[ */ testFoo = "foo"; jQuery('#foo').html('foo'); -ok( true, "test.html executed" ); +ok( true, "test.include.html executed" ); /* ]]> */</script> -<script src="data/testbar.php"></script> +<script src="{{baseURL}}mock.php?action=testbar"></script> blabla diff --git a/test/data/test.php b/test/data/test.php deleted file mode 100644 index d93dafad8..000000000 --- a/test/data/test.php +++ /dev/null @@ -1,7 +0,0 @@ -html text<br/> -<script type="text/javascript">/* <![CDATA[ */ -testFoo = "foo"; jQuery('#foo').html('foo'); -ok( true, "test.php executed" ); -/* ]]> */</script> -<script src="data/testbar.php?<?php srand(); echo time() . '' . rand(); ?>"></script> -blabla diff --git a/test/data/testbar.php b/test/data/testbar.php deleted file mode 100644 index 21aa6882b..000000000 --- a/test/data/testbar.php +++ /dev/null @@ -1,3 +0,0 @@ -this.testBar = "bar"; -jQuery("#ap").html("bar"); -ok( true, "testbar.php executed"); diff --git a/test/data/testinit.js b/test/data/testinit.js index 1aa9a65da..d6c0236e6 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -1,6 +1,11 @@ /* eslint no-multi-str: "off" */ -var baseURL = "", +// baseURL is intentionally set to "data/" instead of "". +// This is not just for convenience (since most files are in data/) +// but also to ensure that urls without prefix fail. +// Otherwise it's easy to write tests that pass on test/index.html +// but fail in Karma runner (where the baseURL is different). +var baseURL = "data/", supportjQuery = this.jQuery, // see RFC 2606 @@ -148,11 +153,13 @@ window.fireNative = document.createEvent ? /** * Add random number to url to stop caching * - * @example url("data/test.html") - * @result "data/test.html?10538358428943" + * Also prefixes with baseURL automatically. * - * @example url("data/test.php?foo=bar") - * @result "data/test.php?foo=bar&10538358345554" + * @example url("index.html") + * @result "data/index.html?10538358428943" + * + * @example url("mock.php?foo=bar") + * @result "data/mock.php?foo=bar&10538358345554" */ function url( value ) { return baseURL + value + ( /\?/.test( value ) ? "&" : "?" ) + @@ -239,7 +246,7 @@ this.testIframe = function( title, fileName, func, wrapper ) { var done = assert.async(), $iframe = supportjQuery( "<iframe/>" ) .css( { position: "absolute", top: "0", left: "-600px", width: "500px" } ) - .attr( { id: "qunit-fixture-iframe", src: url( "./data/" + fileName ) } ); + .attr( { id: "qunit-fixture-iframe", src: url( fileName ) } ); // Test iframes are expected to invoke this via startIframeTest (cf. iframeTest.js) window.iframeCallback = function() { @@ -264,14 +271,20 @@ this.testIframe = function( title, fileName, func, wrapper ) { }; this.iframeCallback = undefined; -// Tests are always loaded async -QUnit.config.autostart = false; -this.loadTests = function() { +if ( window.__karma__ ) { + // In Karma, files are served from /base + baseURL = "base/test/data/"; +} else { + // Tests are always loaded async + // except when running tests in Karma (See Gruntfile) + QUnit.config.autostart = false; +} - // Leverage QUnit URL parsing to detect testSwarm environment and "basic" testing mode - QUnit.isSwarm = ( QUnit.urlParams.swarmURL + "" ).indexOf( "http" ) === 0; - QUnit.basicTests = ( QUnit.urlParams.module + "" ) === "basic"; +// Leverage QUnit URL parsing to detect testSwarm environment and "basic" testing mode +QUnit.isSwarm = ( QUnit.urlParams.swarmURL + "" ).indexOf( "http" ) === 0; +QUnit.basicTests = ( QUnit.urlParams.module + "" ) === "basic"; +this.loadTests = function() { // Get testSubproject from testrunner first require( [ "data/testrunner.js" ], function() { var i = 0, diff --git a/test/data/text.php b/test/data/text.txt index b9df4cf3b..b9df4cf3b 100644 --- a/test/data/text.php +++ b/test/data/text.txt diff --git a/test/data/with_fries_over_jsonp.php b/test/data/with_fries_over_jsonp.php deleted file mode 100644 index 456aeb3bd..000000000 --- a/test/data/with_fries_over_jsonp.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php -error_reporting(0); -$callback = $_REQUEST['callback']; -$json = $_REQUEST['json']; -$text = json_encode(file_get_contents(dirname(__FILE__)."/with_fries.xml")); -echo "$callback($text)"; -?> diff --git a/test/index.html b/test/index.html index bf117b858..ce5892859 100644 --- a/test/index.html +++ b/test/index.html @@ -42,250 +42,7 @@ <!-- Test HTML --> <!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves --> <iframe id="loadediframe" name="loadediframe" style="display:none;" src="data/iframe.html"></iframe> - <dl id="dl" style="position:absolute;top:-32767px;left:-32767px;width:1px;"> - <div id="qunit-fixture"> - <p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p> - <p id="ap"> - Here are some links in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>, - <a id="groups" href="http://groups.google.com/" class="GROUPS">Google Groups (Link)</a>. - This link has <code><a href="http://smin" id="anchor1">class="blog"</a></code>: - <a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a> - - </p> - <div id="foo"> - <p id="sndp">Everything inside the red border is inside a div with <code>id="foo"</code>.</p> - <p lang="en" id="en">This is a normal link: <a id="yahoo" href="http://www.yahoo.com/" class="blogTest">Yahoo</a></p> - <p id="sap">This link has <code><a href="#2" id="anchor2">class="blog"</a></code>: <a href="http://simon.incutio.com/" class="blog link" id="simon">Simon Willison's Weblog</a></p> - - </div> - <div id="nothiddendiv" style="height:1px;background:white;" class="nothiddendiv"> - <div id="nothiddendivchild"></div> - </div> - <span id="name+value"></span> - <p id="first">Try them out:</p> - <ul id="firstUL"></ul> - <ol id="empty"></ol> - <form id="form" action="formaction"> - <label for="action" id="label-for">Action:</label> - <input type="text" name="action" value="Test" id="text1" maxlength="30"/> - <input type="text" name="text2" value="Test" id="text2" disabled="disabled"/> - <input type="radio" name="radio1" id="radio1" value="on"/> - - <input type="radio" name="radio2" id="radio2" checked="checked"/> - <input type="checkbox" name="check" id="check1" checked="checked"/> - <input type="checkbox" id="check2" value="on"/> - - <input type="hidden" name="hidden" id="hidden1"/> - <input type="text" style="display:none;" name="foo[bar]" id="hidden2"/> - - <input type="text" id="name" name="name" value="name" /> - <input type="search" id="search" name="search" value="search" /> - - <button id="button" name="button" type="button">Button</button> - - <textarea id="area1" maxlength="30">foobar</textarea> - - <select name="select1" id="select1"> - <option id="option1a" class="emptyopt" value="">Nothing</option> - <option id="option1b" value="1">1</option> - <option id="option1c" value="2">2</option> - <option id="option1d" value="3">3</option> - </select> - <select name="select2" id="select2"> - <option id="option2a" class="emptyopt" value="">Nothing</option> - <option id="option2b" value="1">1</option> - <option id="option2c" value="2">2</option> - <option id="option2d" selected="selected" value="3">3</option> - </select> - <select name="select3" id="select3" multiple="multiple"> - <option id="option3a" class="emptyopt" value="">Nothing</option> - <option id="option3b" selected="selected" value="1">1</option> - <option id="option3c" selected="selected" value="2">2</option> - <option id="option3d" value="3">3</option> - <option id="option3e">no value</option> - </select> - <select name="select4" id="select4" multiple="multiple"> - <optgroup disabled="disabled"> - <option id="option4a" class="emptyopt" value="">Nothing</option> - <option id="option4b" disabled="disabled" selected="selected" value="1">1</option> - <option id="option4c" selected="selected" value="2">2</option> - </optgroup> - <option selected="selected" disabled="disabled" id="option4d" value="3">3</option> - <option id="option4e">no value</option> - </select> - <select name="select5" id="select5"> - <option id="option5a" value="3">1</option> - <option id="option5b" value="2">2</option> - <option id="option5c" value="1" data-attr="">3</option> - </select> - - <object id="object1" codebase="stupid"> - <param name="p1" value="x1" /> - <param name="p2" value="x2" /> - </object> - - <span id="台北Táiběi"></span> - <span id="台北" lang="中文"></span> - <span id="utf8class1" class="台北Táiběi 台北"></span> - <span id="utf8class2" class="台北"></span> - <span id="foo:bar" class="foo:bar"></span> - <span id="test.foo[5]bar" class="test.foo[5]bar"></span> - - <foo_bar id="foobar">test element</foo_bar> - </form> - <b id="floatTest">Float test.</b> - <iframe id="iframe" name="iframe"></iframe> - <form id="lengthtest"> - <input type="text" id="length" name="test"/> - <input type="text" id="idTest" name="id"/> - </form> - <table id="table"></table> - - <form id="name-tests"> - <!-- Inputs with a grouped name attribute. --> - <input name="types[]" id="types_all" type="checkbox" value="all" /> - <input name="types[]" id="types_anime" type="checkbox" value="anime" /> - <input name="types[]" id="types_movie" type="checkbox" value="movie" /> - </form> - - <form id="testForm" action="#" method="get"> - <textarea name="T3" rows="2" cols="15">? -Z</textarea> - <input type="hidden" name="H1" value="x" /> - <input type="hidden" name="H2" /> - <input name="PWD" type="password" value="" /> - <input name="T1" type="text" /> - <input name="T2" type="text" value="YES" readonly="readonly" /> - <input type="checkbox" name="C1" value="1" /> - <input type="checkbox" name="C2" /> - <input type="radio" name="R1" value="1" /> - <input type="radio" name="R1" value="2" /> - <input type="text" name="My Name" value="me" /> - <input type="reset" name="reset" value="NO" /> - <select name="S1"> - <option value="abc">ABC</option> - <option value="abc">ABC</option> - <option value="abc">ABC</option> - </select> - <select name="S2" multiple="multiple" size="3"> - <option value="abc">ABC</option> - <option value="abc">ABC</option> - <option value="abc">ABC</option> - </select> - <select name="S3"> - <option selected="selected">YES</option> - </select> - <select name="S4"> - <option value="" selected="selected">NO</option> - </select> - <input type="submit" name="sub1" value="NO" /> - <input type="submit" name="sub2" value="NO" /> - <input type="image" name="sub3" value="NO" /> - <button name="sub4" type="submit" value="NO">NO</button> - <input name="D1" type="text" value="NO" disabled="disabled" /> - <input type="checkbox" checked="checked" disabled="disabled" name="D2" value="NO" /> - <input type="radio" name="D3" value="NO" checked="checked" disabled="disabled" /> - <select name="D4" disabled="disabled"> - <option selected="selected" value="NO">NO</option> - </select> - <input id="list-test" type="text" /> - <datalist id="datalist"> - <option value="option"></option> - </datalist> - </form> - <div id="moretests"> - <form> - <div id="checkedtest" style="display:none;"> - <input type="radio" name="checkedtestradios" checked="checked"/> - <input type="radio" name="checkedtestradios" value="on"/> - <input type="checkbox" name="checkedtestcheckboxes" checked="checked"/> - <input type="checkbox" name="checkedtestcheckboxes" /> - </div> - </form> - <div id="nonnodes"><span id="nonnodesElement">hi</span> there <!-- mon ami --></div> - <div id="t2037"> - <div><div class="hidden">hidden</div></div> - </div> - <div id="t6652"> - <div></div> - </div> - <div id="no-clone-exception"><object><embed></embed></object></div> - </div> - - <div id="tabindex-tests"> - <ol id="listWithTabIndex" tabindex="5"> - <li id="foodWithNegativeTabIndex" tabindex="-1">Rice</li> - <li id="foodNoTabIndex">Beans</li> - <li>Blinis</li> - <li>Tofu</li> - </ol> - - <div id="divWithNoTabIndex">I'm hungry. I should...</div> - <span>...</span><a href="#" id="linkWithNoTabIndex">Eat lots of food</a><span>...</span> | - <span>...</span><a href="#" id="linkWithTabIndex" tabindex="2">Eat a little food</a><span>...</span> | - <span>...</span><a href="#" id="linkWithNegativeTabIndex" tabindex="-1">Eat no food</a><span>...</span> - <span>...</span><a id="linkWithNoHrefWithNoTabIndex">Eat a burger</a><span>...</span> - <span>...</span><a id="linkWithNoHrefWithTabIndex" tabindex="1">Eat some funyuns</a><span>...</span> - <span>...</span><a id="linkWithNoHrefWithNegativeTabIndex" tabindex="-1">Eat some funyuns</a><span>...</span> - <input id="inputWithoutTabIndex"/> - <button id="buttonWithoutTabIndex"></button> - <textarea id="textareaWithoutTabIndex"></textarea> - <menu type="popup"> - <menuitem id="menuitemWithoutTabIndex" command="submitbutton" default/> - </menu> - </div> - - <div id="liveHandlerOrder"> - <span id="liveSpan1"><a href="#" id="liveLink1"></a></span> - <span id="liveSpan2"><a href="#" id="liveLink2"></a></span> - </div> - - <div id="siblingTest"> - <em id="siblingfirst">1</em> - <em id="siblingnext">2</em> - <em id="siblingthird"> - <em id="siblingchild"> - <em id="siblinggrandchild"> - <em id="siblinggreatgrandchild"></em> - </em> - </em> - </em> - <span id="siblingspan"></span> - </div> - <div id="fx-test-group" style="position: absolute; width: 1px; height: 1px; overflow: hidden;"> - <div id="fx-queue" name="test"> - <div id="fadein" class='chain-test' name='div'>fadeIn<div>fadeIn</div></div> - <div id="fadeout" class='chain-test chain-test-out'>fadeOut<div>fadeOut</div></div> - - <div id="show" class='chain-test'>show<div>show</div></div> - <div id="hide" class='chain-test chain-test-out'>hide<div>hide</div></div> - <div id="easehide" class='chain-test chain-test-out'>hide<div>hide</div></div> - - <div id="togglein" class='chain-test'>togglein<div>togglein</div></div> - <div id="toggleout" class='chain-test chain-test-out'>toggleout<div>toggleout</div></div> - <div id="easetoggleout" class='chain-test chain-test-out'>toggleout<div>toggleout</div></div> - - <div id="slideup" class='chain-test'>slideUp<div>slideUp</div></div> - <div id="slidedown" class='chain-test chain-test-out'>slideDown<div>slideDown</div></div> - <div id="easeslideup" class='chain-test'>slideUp<div>slideUp</div></div> - - <div id="slidetogglein" class='chain-test'>slideToggleIn<div>slideToggleIn</div></div> - <div id="slidetoggleout" class='chain-test chain-test-out'>slideToggleOut<div>slideToggleOut</div></div> - - <div id="fadetogglein" class='chain-test'>fadeToggleIn<div>fadeToggleIn</div></div> - <div id="fadetoggleout" class='chain-test chain-test-out'>fadeToggleOut<div>fadeToggleOut</div></div> - - <div id="fadeto" class='chain-test'>fadeTo<div>fadeTo</div></div> - </div> - - <div id="fx-tests"></div> - <span id="display"></span> - </div> - </div> - </dl> - <map name="imgmap" id="imgmap"> - <area shape="rect" coords="0,0,200,50"> - </map> - + <div id="qunit-fixture"></div> + <script src="data/qunit-fixture.js"></script> </body> </html> diff --git a/test/karma.context.html b/test/karma.context.html new file mode 100644 index 000000000..e4f8a4f88 --- /dev/null +++ b/test/karma.context.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html lang="en" id="html"> +<head> + <meta charset="utf-8"> + <title>CONTEXT</title> + <!-- Karma serves this page from /context.html. Other files are served from /base --> + <link rel="stylesheet" href="/base/test/data/testsuite.css" /> +</head> +<body id="body"> + <div id="qunit"></div> + + <!-- Start: jQuery Test HTML --> + <!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves --> + <iframe id="loadediframe" name="loadediframe" style="display:none;" src="/base/test/data/iframe.html"></iframe> + <div id="qunit-fixture"></div> + <!-- End: jQuery Test HTML --> + + <!-- Start: Karma boilerplate --> + <script src="/context.js"></script> + <script> + %CLIENT_CONFIG% + window.__karma__.setupContext(window); + + %MAPPINGS% + </script> + %SCRIPTS% + <!-- End: Karma boilerplate --> + + <script src="/base/test/data/qunit-fixture.js"></script> + <script> + // Workaround: Remove call to window.__karma__.loaded() + // in favour of calling window.__karma__.start() at window.onload + // because tests such as unit/ready.js should run after document ready + window.addEventListener('load', function() { + window.__karma__.start(); + + // Workaround: https://github.com/karma-runner/karma-qunit/issues/92 + QUnit.testStart(function () { + // Restore content + document.getElementById("qunit-fixture").innerHTML = QUnit.config.fixture; + }); + }); + </script> +</body> +</html> diff --git a/test/karma.debug.html b/test/karma.debug.html new file mode 100644 index 000000000..950064db7 --- /dev/null +++ b/test/karma.debug.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html lang="en" id="html"> +<head> +%X_UA_COMPATIBLE% + <title>DEBUG</title> + <meta charset="utf-8"> + <!-- Karma serves this page from /context.html. Other files are served from /base --> + <link rel="stylesheet" href="/base/external/qunit/qunit.css" /> + <link rel="stylesheet" href="/base/test/data/testsuite.css" /> +</head> +<body id="body"> + <div id="qunit"></div> + + <!-- Start: jQuery Test HTML --> + <!-- this iframe is outside the #qunit-fixture so it won't waste time by constantly reloading; the tests are "safe" and clean up after themselves --> + <iframe id="loadediframe" name="loadediframe" style="display:none;" src="/base/test/data/iframe.html"></iframe> + <div id="qunit-fixture"></div> + <!-- End: jQuery Test HTML --> + + <!-- Start: Karma boilerplate --> + <script src="/context.js"></script> + <script src="/debug.js"></script> + <script> + %CLIENT_CONFIG% + + %MAPPINGS% + </script> + %SCRIPTS% + <!-- End: Karma boilerplate --> + + <script src="/base/test/data/qunit-fixture.js"></script> + <script> + // Workaround: Remove call to window.__karma__.loaded() + // in favour of calling window.__karma__.start() at window.onload + // because tests such as unit/ready.js should run after document ready + window.addEventListener('load', function() { + window.__karma__.start(); + + // Workaround: https://github.com/karma-runner/karma-qunit/issues/92 + QUnit.testStart(function () { + // Restore content + document.getElementById("qunit-fixture").innerHTML = QUnit.config.fixture; + }); + }); + </script> +</body> +</html> diff --git a/test/middleware-mockserver.js b/test/middleware-mockserver.js new file mode 100644 index 000000000..35623761d --- /dev/null +++ b/test/middleware-mockserver.js @@ -0,0 +1,284 @@ +/* eslint-env node */ +var url = require( "url" ); +var fs = require( "fs" ); +var getRawBody = require( "raw-body" ); + +var cspLog = ""; +/** + * Keep in sync with /test/mock.php + */ +var mocks = { + contentType: function( req, resp ) { + resp.writeHead( 200, { + "content-type": req.query.contentType + } ); + resp.end( req.query.response ); + }, + wait: function( req, resp ) { + var wait = Number( req.query.wait ) * 1000; + setTimeout( function() { + if ( req.query.script ) { + resp.writeHead( 200, { "content-type": "text/javascript" } ); + } else { + resp.writeHead( 200, { "content-type": "text/html" } ); + resp.end( "ERROR <script>ok( true, \"mock executed\" );</script>" ); + } + }, wait ); + }, + name: function( req, resp, next ) { + resp.writeHead( 200 ); + if ( req.query.name === "foo" ) { + resp.end( "bar" ); + return; + } + getBody( req ).then( function( body ) { + if ( body === "name=peter" ) { + resp.end( "pan" ); + } else { + resp.end( "ERROR" ); + } + }, next ); + }, + xml: function( req, resp, next ) { + var content = "<math><calculation>5-2</calculation><result>3</result></math>"; + resp.writeHead( 200, { "content-type": "text/xml" } ); + + if ( req.query.cal === "5-2" ) { + resp.end( content ); + return; + } + getBody( req ).then( function( body ) { + if ( body === "cal=5-2" ) { + resp.end( content ); + } else { + resp.end( "<error>ERROR</error>" ); + } + }, next ); + }, + atom: function( req, resp, next ) { + resp.writeHead( 200, { "content-type": "atom+xml" } ); + resp.end( "<root><element /></root>" ); + }, + script: function( req, resp ) { + if ( req.query.header === "ecma" ) { + resp.writeHead( 200, { "content-type": "application/ecmascript" } ); + } else if ( req.query.header ) { + resp.writeHead( 200, { "content-type": "text/javascript" } ); + } else { + resp.writeHead( 200, { "content-type": "text/html" } ); + } + resp.end( "ok( true, \"mock executed\" );" ); + }, + testbar: function( req, resp ) { + resp.writeHead( 200 ); + resp.end( + "this.testBar = 'bar'; " + + "jQuery('#ap').html('bar'); " + + "ok( true, 'mock executed');" + ); + }, + json: function( req, resp ) { + if ( req.query.header ) { + resp.writeHead( 200, { "content-type": "application/json" } ); + } + if ( req.query.array ) { + resp.end( JSON.stringify( + [ { name: "John", age: 21 }, { name: "Peter", age: 25 } ] + ) ); + } else { + resp.end( JSON.stringify( + { data: { lang: "en", length: 25 } } + ) ); + } + }, + jsonp: function( req, resp, next ) { + var callback; + if ( req.query.callback ) { + callback = Promise.resolve( req.query.callback ); + } else if ( req.method === "GET" ) { + callback = Promise.resolve( req.url.match( /^.+\/([^\/?.]+)\?.+$/ )[ 1 ] ); + } else { + callback = getBody( req ).then( function( body ) { + return body.trim().replace( "callback=", "" ); + } ); + } + var json = req.query.array ? + JSON.stringify( + [ { name: "John", age: 21 }, { name: "Peter", age: 25 } ] + ) : + JSON.stringify( + { data: { lang: "en", length: 25 } } + ); + callback.then( function( cb ) { + resp.end( cb + "(" + json + ")" ); + }, next ); + }, + xmlOverJsonp: function( req, resp ) { + var callback = req.query.callback; + var body = fs.readFileSync( __dirname + "/data/with_fries.xml" ).toString(); + resp.writeHead( 200 ); + resp.end( callback + "(" + JSON.stringify( body ) + ")\n" ); + }, + error: function( req, resp ) { + if ( req.query.json ) { + resp.writeHead( 400, { "content-type": "application/json" } ); + resp.end( "{ \"code\": 40, \"message\": \"Bad Request\" }" ); + } else { + resp.writeHead( 400 ); + resp.end( "plain text message" ); + } + }, + headers: function( req, resp ) { + resp.writeHead( 200, { + "Sample-Header": "Hello World", + "Empty-Header": "", + "Sample-Header2": "Hello World 2" + } ); + req.query.keys.split( "|" ).forEach( function( key ) { + if ( req.headers[ key.toLowerCase() ] ) { + resp.write( key + ": " + req.headers[ key.toLowerCase() ] + "\n" ); + } + } ); + resp.end(); + }, + echoData: function( req, resp, next ) { + getBody( req ).then( function( body ) { + resp.end( body ); + }, next ); + }, + echoQuery: function( req, resp ) { + resp.end( req.parsed.search.slice( 1 ) ); + }, + echoMethod: function( req, resp ) { + resp.end( req.method ); + }, + echoHtml: function( req, resp, next ) { + resp.writeHead( 200, { "Content-Type": "text/html" } ); + resp.write( "<div id='method'>" + req.method + "</div>" ); + resp.write( "<div id='query'>" + req.parsed.search.slice( 1 ) + "</div>" ); + getBody( req ).then( function( body ) { + resp.write( "<div id='data'>" + body + "</div>" ); + resp.end( body ); + }, next ); + }, + etag: function( req, resp ) { + var hash = Number( req.query.ts ).toString( 36 ); + var etag = "W/\"" + hash + "\""; + if ( req.headers[ "if-none-match" ] === etag ) { + resp.writeHead( 304 ); + resp.end(); + return; + } + resp.writeHead( 200, { + "Etag": etag + } ); + resp.end(); + }, + ims: function( req, resp, next ) { + var ts = req.query.ts; + if ( req.headers[ "if-modified-since" ] === ts ) { + resp.writeHead( 304 ); + resp.end(); + return; + } + resp.writeHead( 200, { + "Last-Modified": ts + } ); + resp.end(); + }, + status: function( req, resp, next ) { + resp.writeHead( Number( req.query.code ) ); + resp.end(); + }, + testHTML: function( req, resp ) { + resp.writeHead( 200, { "Content-Type": "text/html" } ); + var body = fs.readFileSync( __dirname + "/data/test.include.html" ).toString(); + body = body.replace( /{{baseURL}}/g, req.query.baseURL ); + resp.end( body ); + }, + cspFrame: function( req, resp ) { + resp.writeHead( 200, { + "Content-Type": "text/html", + "Content-Security-Policy": "default-src 'self'; report-uri /base/test/data/mock.php?action=cspLog" + } ); + var body = fs.readFileSync( __dirname + "/data/csp.include.html" ).toString(); + resp.end( body ); + }, + cspLog: function( req, resp ) { + cspLog = "error"; + resp.writeHead( 200 ); + resp.end(); + }, + cspClean: function( req, resp ) { + cspLog = ""; + resp.writeHead( 200 ); + resp.end(); + } +}; +var handlers = { + "test/data/mock.php": function( req, resp, next ) { + if ( !mocks[ req.query.action ] ) { + resp.writeHead( 400 ); + resp.end( "Invalid action query.\n" ); + console.log( "Invalid action query:", req.method, req.url ); + return; + } + mocks[ req.query.action ]( req, resp, next ); + }, + "test/data/support/csp.log": function( req, resp ) { + resp.writeHead( 200 ); + resp.end( cspLog ); + }, + "test/data/404.txt": function( req, resp ) { + resp.writeHead( 404 ); + resp.end( "" ); + } +}; + +/** + * Connect-compatible middleware factory for mocking server responses. + * Used by Ajax unit tests when run via Karma. + * + * Despite Karma using Express, it uses Connect to deal with custom middleware, + * which passes the raw Node Request and Response objects instead of the + * Express versions of these (e.g. no req.path, req.query, resp.set). + */ +function MockserverMiddlewareFactory() { + /** + * @param {http.IncomingMessage} req + * @param {http.ServerResponse} resp + * @param {Function} next Continue request handling + */ + return function( req, resp, next ) { + var method = req.method, + parsed = url.parse( req.url, /* parseQuery */ true ), + path = parsed.pathname.replace( /^\/base\//, "" ), + query = parsed.query, + subReq = Object.assign( Object.create( req ), { + query: query, + parsed: parsed + } ); + + if ( /^test\/data\/mock.php\//.test( path ) ) { + // Support REST-like Apache PathInfo + path = "test\/data\/mock.php"; + } + + if ( !handlers[ path ] ) { + next(); + return; + } + + handlers[ path ]( subReq, resp, next ); + }; +} + +function getBody( req ) { + return req.method !== "POST" ? + Promise.resolve( "" ) : + getRawBody( req, { + encoding: true + } ); +} + +module.exports = MockserverMiddlewareFactory; diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 4dc7b9d3a..a8fd3a075 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -40,7 +40,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - success callbacks", 8, function( assert ) { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function() { assert.ok( true, "beforeSend" ); }, @@ -57,7 +57,7 @@ QUnit.module( "ajax", { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), create: function( options ) { - return jQuery.ajax( url( "data/name.html" ), options ); + return jQuery.ajax( url( "name.html" ), options ); }, beforeSend: function() { assert.ok( true, "beforeSend" ); @@ -77,7 +77,7 @@ QUnit.module( "ajax", { create: function( options ) { options.crossDomain = true; options.dataType = "script"; - return jQuery.ajax( url( "data/script.php?header=ecma" ), options ); + return jQuery.ajax( url( "mock.php?action=script&header=ecma" ), options ); }, success: function() { assert.ok( true, "success" ); @@ -93,7 +93,7 @@ QUnit.module( "ajax", { return { create: function( options ) { options.crossDomain = true; - return jQuery.ajax( url( "data/script.php" ), options ); + return jQuery.ajax( url( "mock.php?action=script" ), options ); }, success: function() { assert.ok( true, "success" ); @@ -112,7 +112,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - success callbacks (late binding)", 8, function( assert ) { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function() { assert.ok( true, "beforeSend" ); }, @@ -132,7 +132,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - success callbacks (oncomplete binding)", 8, function( assert ) { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function() { assert.ok( true, "beforeSend" ); }, @@ -152,7 +152,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - error callbacks", 8, function( assert ) { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError", assert ), - url: url( "data/name.php?wait=5" ), + url: url( "mock.php?action=wait&wait=5" ), beforeSend: function() { assert.ok( true, "beforeSend" ); }, @@ -170,7 +170,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - textStatus and errorThrown values", 4, function( assert ) { return [ { - url: url( "data/name.php?wait=5" ), + url: url( "mock.php?action=wait&wait=5" ), error: function( _, textStatus, errorThrown ) { assert.strictEqual( textStatus, "abort", "textStatus is 'abort' for abort" ); assert.strictEqual( errorThrown, "abort", "errorThrown is 'abort' for abort" ); @@ -180,7 +180,7 @@ QUnit.module( "ajax", { } }, { - url: url( "data/name.php?wait=5" ), + url: url( "mock.php?action=wait&wait=5" ), error: function( _, textStatus, errorThrown ) { assert.strictEqual( textStatus, "mystatus", "textStatus is 'mystatus' for abort('mystatus')" ); assert.strictEqual( errorThrown, "mystatus", "errorThrown is 'mystatus' for abort('mystatus')" ); @@ -193,7 +193,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - responseText on error", 1, function( assert ) { return { - url: url( "data/errorWithText.php" ), + url: url( "mock.php?action=error" ), error: function( xhr ) { assert.strictEqual( xhr.responseText, "plain text message", "Test jqXHR.responseText is filled for HTTP errors" ); } @@ -204,7 +204,7 @@ QUnit.module( "ajax", { var previousUrl, firstTime = true; jQuery.ajax( { - url: url( "data/errorWithText.php" ), + url: url( "mock.php?action=error" ), error: function() { if ( firstTime ) { firstTime = false; @@ -212,10 +212,7 @@ QUnit.module( "ajax", { } else { assert.ok( true, "Test retrying with jQuery.ajax(this) works" ); jQuery.ajax( { - url: url( "data/errorWithText.php" ), - data: { - "x": 1 - }, + url: url( "mock.php?action=error&x=2" ), beforeSend: function() { if ( !previousUrl ) { previousUrl = this.url; @@ -241,7 +238,7 @@ QUnit.module( "ajax", { xhr.setRequestHeader( "ajax-send", "test" ); } ); }, - url: url( "data/headers.php?keys=siMPle_SometHing-elsE_OthEr_Nullable_undefined_Empty_ajax-send" ), + url: url( "mock.php?action=headers&keys=siMPle|SometHing-elsE|OthEr|Nullable|undefined|Empty|ajax-send" ), headers: { "siMPle": "value", "SometHing-elsE": "other value", @@ -281,7 +278,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - Accept header", 1, function( assert ) { return { - url: url( "data/headers.php?keys=accept" ), + url: url( "mock.php?action=headers&keys=accept" ), headers: { Accept: "very wrong accept value" }, @@ -297,14 +294,14 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - contentType", 2, function( assert ) { return [ { - url: url( "data/headers.php?keys=content-type" ), + url: url( "mock.php?action=headers&keys=content-type" ), contentType: "test", success: function( data ) { assert.strictEqual( data, "content-type: test\n", "Test content-type is sent when options.contentType is set" ); } }, { - url: url( "data/headers.php?keys=content-type" ), + url: url( "mock.php?action=headers&keys=content-type" ), contentType: false, success: function( data ) { @@ -330,34 +327,34 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - hash", 4, function( assert ) { return [ { - url: "data/name.html#foo", + url: baseURL + "name.html#foo", beforeSend: function( xhr, settings ) { - assert.equal( settings.url, "data/name.html#foo", "Make sure that the URL has its hash." ); + assert.equal( settings.url, baseURL + "name.html#foo", "Make sure that the URL has its hash." ); return false; }, error: true }, { - url: "data/name.html?abc#foo", + url: baseURL + "name.html?abc#foo", beforeSend: function( xhr, settings ) { - assert.equal( settings.url, "data/name.html?abc#foo", "Make sure that the URL has its hash." ); + assert.equal( settings.url, baseURL + "name.html?abc#foo", "Make sure that the URL has its hash." ); return false; }, error: true }, { - url: "data/name.html?abc#foo", + url: baseURL + "name.html?abc#foo", data: { "test": 123 }, beforeSend: function( xhr, settings ) { - assert.equal( settings.url, "data/name.html?abc&test=123#foo", "Make sure that the URL has its hash." ); + assert.equal( settings.url, baseURL + "name.html?abc&test=123#foo", "Make sure that the URL has its hash." ); return false; }, error: true }, { - url: "data/name.html?abc#brownies", + url: baseURL + "name.html?abc#brownies", data: { "devo": "hat" }, @@ -365,7 +362,7 @@ QUnit.module( "ajax", { beforeSend: function( xhr, settings ) { // Remove the random number, but ensure the cache-buster param is there var url = settings.url.replace( /\d+/, "" ); - assert.equal( url, "data/name.html?abc&devo=hat&_=#brownies", "Make sure that the URL has its hash." ); + assert.equal( url, baseURL + "name.html?abc&devo=hat&_=#brownies", "Make sure that the URL has its hash." ); return false; }, error: true @@ -492,7 +489,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - abort", 9, function( assert ) { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxError ajaxComplete", assert ), - url: url( "data/name.php?wait=5" ), + url: url( "mock.php?action=wait&wait=5" ), beforeSend: function() { assert.ok( true, "beforeSend" ); }, @@ -510,7 +507,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - native abort", 2, function( assert ) { return { - url: url( "data/name.php?wait=1" ), + url: url( "mock.php?action=wait&wait=1" ), xhr: function() { var xhr = new window.XMLHttpRequest(); setTimeout( function() { @@ -529,7 +526,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - native timeout", 2, function( assert ) { return { - url: url( "data/name.php?wait=1" ), + url: url( "mock.php?action=wait&wait=1" ), xhr: function() { var xhr = new window.XMLHttpRequest(); xhr.timeout = 1; @@ -566,13 +563,13 @@ QUnit.module( "ajax", { .ajaxSuccess( event ); }, requests: [ { - url: url( "data/name.html" ), + url: url( "name.html" ), context: context, beforeSend: callback( "beforeSend" ), success: callback( "success" ), complete: callback( "complete" ) }, { - url: url( "data/404.html" ), + url: url( "404.txt" ), context: context, beforeSend: callback( "beforeSend" ), error: callback( "error" ), @@ -588,7 +585,7 @@ QUnit.module( "ajax", { }; } return { - url: url( "data/404.html" ), + url: url( "404.txt" ), beforeSend: nocallback( "beforeSend" ), error: nocallback( "error" ), complete: nocallback( "complete" ) @@ -598,7 +595,7 @@ QUnit.module( "ajax", { ajaxTest( "#15118 - jQuery.ajax() - function without jQuery.event", 1, function( assert ) { var holder; return { - url: url( "data/json.php" ), + url: url( "mock.php?action=json" ), setup: function() { holder = jQuery.event; delete jQuery.event; @@ -622,7 +619,7 @@ QUnit.module( "ajax", { assert.equal( jqXHR.statusText, "abort", "jqXHR.statusText equals abort on global ajaxComplete and ajaxError events" ); } ); }, - url: url( "data/name.html" ), + url: url( "name.html" ), error: true, complete: function() { assert.ok( true, "complete" ); @@ -632,7 +629,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - context modification", 1, function( assert ) { return { - url: url( "data/name.html" ), + url: url( "name.html" ), context: {}, beforeSend: function() { this.test = "foo"; @@ -654,12 +651,12 @@ QUnit.module( "ajax", { assert.strictEqual( jQuery.ajaxSettings.context, obj, "Make sure the context is properly set in ajaxSettings." ); }, requests: [ { - url: url( "data/name.html" ), + url: url( "name.html" ), success: function() { assert.strictEqual( this, obj, "Make sure the original object is maintained." ); } }, { - url: url( "data/name.html" ), + url: url( "name.html" ), context: {}, success: function() { assert.ok( this !== obj, "Make sure overriding context is possible." ); @@ -672,7 +669,7 @@ QUnit.module( "ajax", { return { setup: addGlobalEvents( "", assert ), global: false, - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function() { assert.ok( true, "beforeSend" ); }, @@ -687,7 +684,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - xml: non-namespace elements inside namespaced elements", 3, function( assert ) { return { - url: url( "data/with_fries.xml" ), + url: url( "with_fries.xml" ), dataType: "xml", success: function( resp ) { assert.equal( jQuery( "properties", resp ).length, 1, "properties in responseXML" ); @@ -699,7 +696,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - xml: non-namespace elements inside namespaced elements (over JSONP)", 3, function( assert ) { return { - url: url( "data/with_fries_over_jsonp.php" ), + url: url( "mock.php?action=xmlOverJsonp" ), dataType: "jsonp xml", success: function( resp ) { assert.equal( jQuery( "properties", resp ).length, 1, "properties in responseXML" ); @@ -712,14 +709,14 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - HEAD requests", 2, function( assert ) { return [ { - url: url( "data/name.html" ), + url: url( "name.html" ), type: "HEAD", success: function( data, status, xhr ) { assert.ok( /Date/i.test( xhr.getAllResponseHeaders() ), "No Date in HEAD response" ); } }, { - url: url( "data/name.html" ), + url: url( "name.html" ), data: { "whip_it": "good" }, @@ -733,7 +730,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - beforeSend", 1, function( assert ) { return { - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function() { this.check = true; }, @@ -747,7 +744,7 @@ QUnit.module( "ajax", { return { create: function() { return jQuery.ajax( { - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function( xhr ) { assert.ok( true, "beforeSend got called, canceling" ); xhr.abort(); @@ -776,7 +773,7 @@ QUnit.module( "ajax", { Globals.register( "testBar" ); }, dataType: "html", - url: url( "data/test.html" ), + url: url( "mock.php?action=testHTML&baseURL=" + baseURL ), success: function( data ) { assert.ok( data.match( /^html text/ ), "Check content for datatype html" ); jQuery( "#ap" ).html( data ); @@ -788,7 +785,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - synchronous request", 1, function( assert ) { return { - url: url( "data/json_obj.js" ), + url: url( "json_obj.js" ), dataType: "text", async: false, success: true, @@ -800,7 +797,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - synchronous request with callbacks", 2, function( assert ) { return { - url: url( "data/json_obj.js" ), + url: url( "json_obj.js" ), async: false, dataType: "text", success: true, @@ -816,7 +813,7 @@ QUnit.module( "ajax", { } ); QUnit.asyncTest( "jQuery.ajax(), jQuery.get[Script|JSON](), jQuery.post(), pass-through request object", 8, function( assert ) { - var target = "data/name.html", + var target = "name.html", successCount = 0, errorCount = 0, errorEx = "", @@ -837,8 +834,8 @@ QUnit.module( "ajax", { assert.ok( jQuery.get( url( target ), success ), "get" ); assert.ok( jQuery.post( url( target ), success ), "post" ); - assert.ok( jQuery.getScript( url( "data/testbar.php" ), success ), "script" ); - assert.ok( jQuery.getJSON( url( "data/json_obj.js" ), success ), "json" ); + assert.ok( jQuery.getScript( url( "mock.php?action=testbar" ), success ), "script" ); + assert.ok( jQuery.getJSON( url( "json_obj.js" ), success ), "json" ); assert.ok( jQuery.ajax( { url: url( target ), success: success @@ -847,7 +844,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - cache", 28, function( assert ) { var re = /_=(.*?)(&|$)/g, - rootUrl = "data/text.php"; + rootUrl = baseURL + "text.txt"; function request( url, title ) { return { @@ -908,7 +905,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - JSONP - Query String (?n)" + label, 4, function( assert ) { return [ { - url: "data/jsonp.php?callback=?", + url: baseURL + "mock.php?action=jsonp&callback=?", dataType: "jsonp", crossDomain: crossDomain, success: function( data ) { @@ -916,7 +913,7 @@ QUnit.module( "ajax", { } }, { - url: "data/jsonp.php?callback=??", + url: baseURL + "mock.php?action=jsonp&callback=??", dataType: "jsonp", crossDomain: crossDomain, success: function( data ) { @@ -924,7 +921,7 @@ QUnit.module( "ajax", { } }, { - url: "data/jsonp.php/??", + url: baseURL + "mock.php/???action=jsonp", dataType: "jsonp", crossDomain: crossDomain, success: function( data ) { @@ -932,7 +929,7 @@ QUnit.module( "ajax", { } }, { - url: "data/jsonp.php/???json=1", + url: baseURL + "mock.php/???action=jsonp&array=1", dataType: "jsonp", crossDomain: crossDomain, success: function( data ) { @@ -953,7 +950,7 @@ QUnit.module( "ajax", { }; }, requests: [ { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, jsonp: "callback", @@ -961,7 +958,7 @@ QUnit.module( "ajax", { assert.ok( data[ "data" ], "JSON results returned (GET, data obj callback)" ); } }, { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, jsonpCallback: "jsonpResults", @@ -974,7 +971,7 @@ QUnit.module( "ajax", { assert.ok( data.data, "JSON results returned (GET, custom callback name)" ); } }, { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, jsonpCallback: "functionToCleanUp", @@ -983,7 +980,7 @@ QUnit.module( "ajax", { assert.strictEqual( window[ "functionToCleanUp" ], true, "Callback was removed (GET, custom callback name to be cleaned up)" ); var xhr; jQuery.ajax( { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, jsonpCallback: "functionToCleanUp", @@ -998,13 +995,13 @@ QUnit.module( "ajax", { } ); } }, { - url: "data/jsonp.php?callback=XXX", + url: baseURL + "mock.php?action=jsonp&callback=XXX", dataType: "jsonp", jsonp: false, jsonpCallback: "XXX", crossDomain: crossDomain, beforeSend: function() { - assert.ok( /^data\/jsonp.php\?callback=XXX&_=\d+$/.test( this.url ), "The URL wasn't messed with (GET, custom callback name with no url manipulation)" ); + assert.ok( /action=jsonp&callback=XXX&_=\d+$/.test( this.url ), "The URL wasn't messed with (GET, custom callback name with no url manipulation)" ); }, success: function( data ) { assert.ok( data[ "data" ], "JSON results returned (GET, custom callback name with no url manipulation)" ); @@ -1016,7 +1013,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - JSONP - Callback in data" + label, 2, function( assert ) { return [ { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, data: "callback=?", @@ -1025,7 +1022,7 @@ QUnit.module( "ajax", { } }, { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, data: "callback=??", @@ -1040,7 +1037,7 @@ QUnit.module( "ajax", { return [ { type: "POST", - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, success: function( data ) { @@ -1049,7 +1046,7 @@ QUnit.module( "ajax", { }, { type: "POST", - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", data: "callback=?", dataType: "jsonp", crossDomain: crossDomain, @@ -1059,7 +1056,7 @@ QUnit.module( "ajax", { }, { type: "POST", - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", jsonp: "callback", dataType: "jsonp", crossDomain: crossDomain, @@ -1073,7 +1070,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - JSONP" + label, 3, function( assert ) { return [ { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, success: function( data ) { @@ -1094,7 +1091,7 @@ QUnit.module( "ajax", { promise.abort = request.abort; return promise; }, - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, success: true @@ -1109,7 +1106,7 @@ QUnit.module( "ajax", { setup: function() { Globals.register( "testBar" ); }, - url: window.location.href.replace( /[^\/]*$/, "" ) + "data/testbar.php", + url: window.location.href.replace( /[^\/]*$/, "" ) + baseURL + "mock.php?action=testbar", dataType: "script", success: function() { assert.strictEqual( window[ "testBar" ], "bar", "Script results returned (GET, no callback)" ); @@ -1122,7 +1119,7 @@ QUnit.module( "ajax", { setup: function() { Globals.register( "testBar" ); }, - url: window.location.href.replace( /[^\/]*$/, "" ) + "data/testbar.php", + url: window.location.href.replace( /[^\/]*$/, "" ) + baseURL + "mock.php?action=testbar", type: "POST", dataType: "script", success: function( data, status ) { @@ -1137,7 +1134,7 @@ QUnit.module( "ajax", { setup: function() { Globals.register( "testBar" ); }, - url: window.location.href.replace( /[^\/]*$/, "" ).replace( /^.*?\/\//, "//" ) + "data/testbar.php", + url: window.location.href.replace( /[^\/]*$/, "" ).replace( /^.*?\/\//, "//" ) + baseURL + "mock.php?action=testbar", dataType: "script", success: function() { assert.strictEqual( window[ "testBar" ], "bar", "Script results returned (GET, no callback)" ); @@ -1147,7 +1144,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - malformed JSON", 2, function( assert ) { return { - url: "data/badjson.js", + url: baseURL + "badjson.js", dataType: "json", error: function( xhr, msg, detailedMsg ) { assert.strictEqual( msg, "parsererror", "A parse error occurred." ); @@ -1159,14 +1156,14 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - script by content-type", 2, function() { return [ { - url: "data/script.php", + url: baseURL + "mock.php?action=script", data: { "header": "script" }, success: true }, { - url: "data/script.php", + url: baseURL + "mock.php?action=script", data: { "header": "ecma" }, @@ -1177,10 +1174,10 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - JSON by content-type", 5, function( assert ) { return { - url: "data/json.php", + url: baseURL + "mock.php?action=json", data: { "header": "json", - "json": "array" + "array": "1" }, success: function( json ) { assert.ok( json.length >= 2, "Check length" ); @@ -1194,10 +1191,10 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - JSON by content-type disabled with options", 6, function( assert ) { return { - url: url( "data/json.php" ), + url: url( "mock.php?action=json" ), data: { "header": "json", - "json": "array" + "array": "1" }, contents: { "json": false @@ -1217,7 +1214,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - simple get", 1, function( assert ) { return { type: "GET", - url: url( "data/name.php?name=foo" ), + url: url( "mock.php?action=name&name=foo" ), success: function( msg ) { assert.strictEqual( msg, "bar", "Check for GET" ); } @@ -1227,7 +1224,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - simple post", 1, function( assert ) { return { type: "POST", - url: url( "data/name.php" ), + url: url( "mock.php?action=name" ), data: "name=peter", success: function( msg ) { assert.strictEqual( msg, "pan", "Check for POST" ); @@ -1237,7 +1234,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - data option - empty bodies for non-GET requests", 1, function( assert ) { return { - url: "data/echoData.php", + url: baseURL + "mock.php?action=echoData", data: undefined, type: "post", success: function( result ) { @@ -1299,11 +1296,11 @@ QUnit.module( "ajax", { function( label, cache ) { jQuery.each( { - "If-Modified-Since": "if_modified_since.php", - "Etag": "etag.php" + "If-Modified-Since": "mock.php?action=ims", + "Etag": "mock.php?action=etag" }, function( type, url ) { - url = "data/" + url + "?ts=" + ifModifiedNow++; + url = baseURL + url + "&ts=" + ifModifiedNow++; QUnit.asyncTest( "jQuery.ajax() - " + type + " support" + label, 4, function( assert ) { jQuery.ajax( { url: url, @@ -1355,7 +1352,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - atom+xml", 1, function( assert ) { return { - url: url( "data/atom+xml.php" ), + url: url( "mock.php?action=atom" ), success: function() { assert.ok( true, "success" ); } @@ -1363,10 +1360,10 @@ QUnit.module( "ajax", { } ); QUnit.asyncTest( "jQuery.ajax() - statusText", 3, function( assert ) { - jQuery.ajax( url( "data/statusText.php?status=200&text=Hello" ) ).done( function( _, statusText, jqXHR ) { + jQuery.ajax( url( "mock.php?action=status&code=200&text=Hello" ) ).done( function( _, statusText, jqXHR ) { assert.strictEqual( statusText, "success", "callback status text ok for success" ); assert.ok( jqXHR.statusText === "Hello" || jqXHR.statusText === "OK", "jqXHR status text ok for success (" + jqXHR.statusText + ")" ); - jQuery.ajax( url( "data/statusText.php?status=404&text=World" ) ).fail( function( jqXHR, statusText ) { + jQuery.ajax( url( "mock.php?action=status&code=404&text=World" ) ).fail( function( jqXHR, statusText ) { assert.strictEqual( statusText, "error", "callback status text ok for error" ); QUnit.start(); } ); @@ -1398,11 +1395,10 @@ QUnit.module( "ajax", { jQuery.each( /* jQuery.each arguments start */ { - "data/name.html": true, - "data/someFileThatDoesNotExist.html": false + "name.html": true, + "404.txt": false }, function( uri, isSuccess ) { - jQuery.ajax( url( uri ), { statusCode: createStatusCodes( "in options", isSuccess ), complete: countComplete @@ -1478,7 +1474,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - transitive conversions", 8, function( assert ) { return [ { - url: url( "data/json.php" ), + url: url( "mock.php?action=json" ), converters: { "json myJson": function( data ) { assert.ok( true, "converter called" ); @@ -1493,7 +1489,7 @@ QUnit.module( "ajax", { } }, { - url: url( "data/json.php" ), + url: url( "mock.php?action=json" ), converters: { "json myJson": function( data ) { assert.ok( true, "converter called (*)" ); @@ -1514,7 +1510,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - overrideMimeType", 2, function( assert ) { return [ { - url: url( "data/json.php" ), + url: url( "mock.php?action=json" ), beforeSend: function( xhr ) { xhr.overrideMimeType( "application/json" ); }, @@ -1523,7 +1519,7 @@ QUnit.module( "ajax", { } }, { - url: url( "data/json.php" ), + url: url( "mock.php?action=json" ), mimeType: "application/json", success: function( json ) { assert.ok( json.data, "Mimetype overridden using mimeType option" ); @@ -1534,7 +1530,7 @@ QUnit.module( "ajax", { ajaxTest( "jQuery.ajax() - empty json gets to error callback instead of success callback.", 1, function( assert ) { return { - url: url( "data/echoData.php" ), + url: url( "mock.php?action=echoData" ), error: function( _, __, error ) { assert.equal( typeof error === "object", true, "Didn't get back error object for empty json response" ); }, @@ -1546,7 +1542,7 @@ QUnit.module( "ajax", { return { create: function() { return jQuery.ajax( { - url: url( "data/name.html" ), + url: url( "name.html" ), beforeSend: function() { assert.ok( true, "beforeSend got called, canceling" ); return false; @@ -1570,14 +1566,14 @@ QUnit.module( "ajax", { ajaxTest( "#2806 - jQuery.ajax() - data option - evaluate function values", 1, function( assert ) { return { - url: "data/echoQuery.php", + url: baseURL + "mock.php?action=echoQuery", data: { key: function() { return "value"; } }, success: function( result ) { - assert.strictEqual( result, "key=value" ); + assert.strictEqual( result, "action=echoQuery&key=value" ); } }; } ); @@ -1602,7 +1598,7 @@ QUnit.module( "ajax", { jQuery.each( [ " - Same Domain", " - Cross Domain" ], function( crossDomain, label ) { ajaxTest( "#7578 - jQuery.ajax() - JSONP - default for cache option" + label, 1, function( assert ) { return { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, beforeSend: function() { @@ -1626,7 +1622,7 @@ QUnit.module( "ajax", { }, { create: function() { - return jQuery.ajax( "data/name.html" ); + return jQuery.ajax( baseURL + "name.html" ); }, done: function() { assert.ok( true, "With only string URL argument" ); @@ -1634,7 +1630,7 @@ QUnit.module( "ajax", { }, { create: function() { - return jQuery.ajax( "data/name.html", {} ); + return jQuery.ajax( baseURL + "name.html", {} ); }, done: function() { assert.ok( true, "With string URL param and map" ); @@ -1644,7 +1640,7 @@ QUnit.module( "ajax", { create: function( options ) { return jQuery.ajax( options ); }, - url: "data/name.html", + url: baseURL + "name.html", success: function() { assert.ok( true, "With only map" ); } @@ -1655,7 +1651,7 @@ QUnit.module( "ajax", { jQuery.each( [ " - Same Domain", " - Cross Domain" ], function( crossDomain, label ) { ajaxTest( "#8205 - jQuery.ajax() - JSONP - re-use callbacks name" + label, 4, function( assert ) { return { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, beforeSend: function( jqXHR, s ) { @@ -1678,7 +1674,7 @@ QUnit.module( "ajax", { ); jQuery.ajax( { - url: "data/jsonp.php", + url: baseURL + "mock.php?action=jsonp", dataType: "jsonp", crossDomain: crossDomain, beforeSend: function() { @@ -1737,7 +1733,7 @@ QUnit.module( "ajax", { ajaxTest( "#11151 - jQuery.ajax() - parse error body", 2, function( assert ) { return { - url: url( "data/errorWithJSON.php" ), + url: url( "mock.php?action=error&json=1" ), dataFilter: function( string ) { assert.ok( false, "dataFilter called" ); return string; @@ -1751,7 +1747,7 @@ QUnit.module( "ajax", { ajaxTest( "#11426 - jQuery.ajax() - loading binary data shouldn't throw an exception in IE", 1, function( assert ) { return { - url: url( "data/1x1.jpg" ), + url: url( "1x1.jpg" ), success: function( data ) { assert.ok( data === undefined || /JFIF/.test( data ), "success callback reached" ); } @@ -1772,7 +1768,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2498 - jQuery.ajax() - binary data shouldn't throw an exception", 2, function( assert ) { return { - url: url( "data/1x1.jpg" ), + url: url( "1x1.jpg" ), dataType: "arraybuffer", success: function( data, s, jqxhr ) { assert.ok( data instanceof window.ArrayBuffer, "correct data type" ); @@ -1790,7 +1786,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.start(); }; jQuery.ajax( { - url: "data/badjson.js", + url: baseURL + "badjson.js", dataType: "script", throws: true } ); @@ -1799,7 +1795,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.each( [ "method", "type" ], function( _, globalOption ) { function request( assert, option ) { var options = { - url: url( "data/echoData.php" ), + url: url( "mock.php?action=echoData" ), data: "hello", success: function( msg ) { assert.strictEqual( msg, "hello", "Check for POST (no override)" ); @@ -1836,7 +1832,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "#13276 - jQuery.ajax() - compatibility between XML documents from ajax requests and parsed string", 1, function( assert ) { return { - url: "data/dashboard.xml", + url: baseURL + "dashboard.xml", dataType: "xml", success: function( ajaxXML ) { var parsedXML = jQuery( jQuery.parseXML( "<tab title=\"Added\">blibli</tab>" ) ).find( "tab" ); @@ -1854,7 +1850,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "#13292 - jQuery.ajax() - converter is bypassed for 204 requests", 3, function( assert ) { return { - url: "data/nocontent.php", + url: baseURL + "mock.php?action=status&code=204&text=No+Content", dataType: "testing", converters: { "* testing": function() { @@ -1876,7 +1872,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "#13388 - jQuery.ajax() - responseXML", 3, function( assert ) { return { - url: url( "data/with_fries.xml" ), + url: url( "with_fries.xml" ), dataType: "xml", success: function( resp, _, jqXHR ) { assert.notStrictEqual( resp, undefined, "XML document exists" ); @@ -1888,7 +1884,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "#13922 - jQuery.ajax() - converter is bypassed for HEAD requests", 3, function( assert ) { return { - url: "data/json.php", + url: baseURL + "mock.php?action=json", method: "HEAD", data: { header: "yes" @@ -1922,7 +1918,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "#14683 - jQuery.ajax() - Exceptions thrown synchronously by xhr.send should be caught", 4, function( assert ) { return [ { - url: "data/params_html.php", + url: baseURL + "mock.php?action=echoData", method: "POST", data: { toString: function() { @@ -1951,9 +1947,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2587 - when content-type not xml, but looks like one", 1, function( assert ) { return { - url: url( "data/ajax/content-type.php" ), + url: url( "mock.php?action=contentType" ), data: { - "content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "response": "<test/>" }, success: function( result ) { @@ -1968,9 +1964,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2587 - when content-type not xml, but looks like one", 1, function( assert ) { return { - url: url( "data/ajax/content-type.php" ), + url: url( "mock.php?action=contentType" ), data: { - "content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "response": "<test/>" }, success: function( result ) { @@ -1985,9 +1981,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2587 - when content-type not json, but looks like one", 1, function( assert ) { return { - url: url( "data/ajax/content-type.php" ), + url: url( "mock.php?action=contentType" ), data: { - "content-type": "test/jsontest", + contentType: "test/jsontest", "response": JSON.stringify( { test: "test" } ) }, success: function( result ) { @@ -2002,9 +1998,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2587 - when content-type not html, but looks like one", 1, function( assert ) { return { - url: url( "data/ajax/content-type.php" ), + url: url( "mock.php?action=contentType" ), data: { - "content-type": "test/htmltest", + contentType: "test/htmltest", "response": "<p>test</p>" }, success: function( result ) { @@ -2019,9 +2015,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2587 - when content-type not javascript, but looks like one", 1, function( assert ) { return { - url: url( "data/ajax/content-type.php" ), + url: url( "mock.php?action=contentType" ), data: { - "content-type": "test/testjavascript", + contentType: "test/testjavascript", "response": "alert(1)" }, success: function( result ) { @@ -2036,9 +2032,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ajaxTest( "gh-2587 - when content-type not ecmascript, but looks like one", 1, function( assert ) { return { - url: url( "data/ajax/content-type.php" ), + url: url( "mock.php?action=contentType" ), data: { - "content-type": "test/testjavascript", + contentType: "test/testjavascript", "response": "alert(1)" }, success: function( result ) { @@ -2079,7 +2075,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.asyncTest( "jQuery.ajaxSetup()", 1, function( assert ) { jQuery.ajaxSetup( { - url: url( "data/name.php?name=foo" ), + url: url( "mock.php?action=name&name=foo" ), success: function( msg ) { assert.strictEqual( msg, "bar", "Check for GET" ); QUnit.start(); @@ -2110,7 +2106,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.ajax( { type: "GET", - url: url( "data/name.php?wait=5" ), + url: url( "mock.php?action=wait&wait=5" ), error: pass, success: fail } ); @@ -2123,7 +2119,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.ajax( { type: "GET", timeout: 15000, - url: url( "data/name.php?wait=1" ), + url: url( "mock.php?action=wait&wait=1" ), error: function() { assert.ok( false, "Check for local timeout failed" ); QUnit.start(); @@ -2148,7 +2144,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re assert.ok( false, "Global event triggered" ); } ); - jQuery( "#qunit-fixture" ).append( "<script src='data/ajax/evalScript.php'></script>" ); + jQuery( "#qunit-fixture" ).append( "<script src='" + baseURL + "mock.php?action=script'></script>" ); jQuery( document ).off( "ajaxStart ajaxStop" ); } ); @@ -2162,7 +2158,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re type: "POST" } ); - jQuery( "#qunit-fixture" ).load( "data/ajax/method.php", function( method ) { + jQuery( "#qunit-fixture" ).load( baseURL + "mock.php?action=echoMethod", function( method ) { assert.equal( method, "GET" ); done(); } ); @@ -2178,7 +2174,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re ps.appendTo( "#qunit-fixture" ); - ps.load( "data/ajax/method.php", function() { + ps.load( baseURL + "mock.php?action=echoMethod", function() { assert.strictEqual( this, ps[ i++ ] ); if ( i === 2 ) { @@ -2191,14 +2187,14 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.test( "#11402 - jQuery.domManip() - script in comments are properly evaluated", 2, function( assert ) { - jQuery( "#qunit-fixture" ).load( "data/cleanScript.html", assert.async() ); + jQuery( "#qunit-fixture" ).load( baseURL + "cleanScript.html", assert.async() ); } ); //----------- jQuery.get() QUnit.asyncTest( "jQuery.get( String, Hash, Function ) - parse xml and use text() on nodes", 2, function( assert ) { - jQuery.get( url( "data/dashboard.xml" ), function( xml ) { + jQuery.get( url( "dashboard.xml" ), function( xml ) { var content = []; jQuery( "tab", xml ).each( function() { content.push( jQuery( this ).text() ); @@ -2213,7 +2209,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.ajaxSetup( { data: "helloworld" } ); - jQuery.get( url( "data/echoQuery.php" ), function( data ) { + jQuery.get( url( "mock.php?action=echoQuery" ), function( data ) { assert.ok( /helloworld$/.test( data ), "Data from ajaxSettings was used" ); QUnit.start(); } ); @@ -2223,9 +2219,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.asyncTest( "jQuery.getJSON( String, Hash, Function ) - JSON array", 5, function( assert ) { jQuery.getJSON( - url( "data/json.php" ), + url( "mock.php?action=json" ), { - "json": "array" + "array": "1" }, function( json ) { assert.ok( json.length >= 2, "Check length" ); @@ -2239,7 +2235,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } ); QUnit.asyncTest( "jQuery.getJSON( String, Function ) - JSON object", 2, function( assert ) { - jQuery.getJSON( url( "data/json.php" ), function( json ) { + jQuery.getJSON( url( "mock.php?action=json" ), function( json ) { if ( json && json[ "data" ] ) { assert.strictEqual( json[ "data" ][ "lang" ], "en", "Check JSON: lang" ); assert.strictEqual( json[ "data" ].length, 25, "Check JSON: length" ); @@ -2249,7 +2245,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } ); QUnit.asyncTest( "jQuery.getJSON( String, Function ) - JSON object with absolute url to local content", 2, function( assert ) { - jQuery.getJSON( url( window.location.href.replace( /[^\/]*$/, "" ) + "data/json.php" ), function( json ) { + jQuery.getJSON( window.location.href.replace( /[^\/]*$/, "" ) + url( "mock.php?action=json" ), function( json ) { assert.strictEqual( json.data.lang, "en", "Check JSON: lang" ); assert.strictEqual( json.data.length, 25, "Check JSON: length" ); QUnit.start(); @@ -2263,7 +2259,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re var done = assert.async(); Globals.register( "testBar" ); - jQuery.getScript( url( "data/testbar.php" ), function() { + jQuery.getScript( url( "mock.php?action=testbar" ), function() { assert.strictEqual( window[ "testBar" ], "bar", "Check if script was evaluated" ); done(); } ); @@ -2272,14 +2268,14 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.test( "jQuery.getScript( String, Function ) - no callback", 1, function( assert ) { Globals.register( "testBar" ); - jQuery.getScript( url( "data/testbar.php" ) ).done( assert.async() ); + jQuery.getScript( url( "mock.php?action=testbar" ) ).done( assert.async() ); } ); QUnit.test( "#8082 - jQuery.getScript( String, Function ) - source as responseText", 2, function( assert ) { var done = assert.async(); Globals.register( "testBar" ); - jQuery.getScript( url( "data/testbar.php" ), function( data, _, jqXHR ) { + jQuery.getScript( url( "mock.php?action=testbar" ), function( data, _, jqXHR ) { assert.strictEqual( data, jqXHR.responseText, "Same-domain script requests returns the source of the script" ); done(); } ); @@ -2294,7 +2290,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re assert.strictEqual( this.type, "GET", "no data means GET request" ); } } ); - jQuery( "#first" ).load( "data/name.html", assert.async() ); + jQuery( "#first" ).load( baseURL + "name.html", assert.async() ); } ); QUnit.test( "jQuery.fn.load() - 404 error callbacks", function( assert ) { @@ -2303,7 +2299,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError", assert )(); jQuery( document ).ajaxStop( done ); - jQuery( "<div/>" ).load( "data/404.html", function() { + jQuery( "<div/>" ).load( baseURL + "404.txt", function() { assert.ok( true, "complete" ); } ); } ); @@ -2315,7 +2311,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re assert.strictEqual( this.type, "GET", "no data means GET request" ); } } ); - jQuery( "#first" ).load( "data/name.html", null, assert.async() ); + jQuery( "#first" ).load( baseURL + "name.html", null, assert.async() ); } ); // check if load can be called with url and undefined data @@ -2325,12 +2321,12 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re assert.strictEqual( this.type, "GET", "no data means GET request" ); } } ); - jQuery( "#first" ).load( "data/name.html", undefined, assert.async() ); + jQuery( "#first" ).load( baseURL + "name.html", undefined, assert.async() ); } ); // check if load can be called with only url QUnit.asyncTest( "jQuery.fn.load( URL_SELECTOR )", 1, function( assert ) { - jQuery( "#first" ).load( "data/test3.html div.user", function() { + jQuery( "#first" ).load( baseURL + "test3.html div.user", function() { assert.strictEqual( jQuery( this ).children( "div" ).length, 2, "Verify that specific elements were injected" ); QUnit.start(); } ); @@ -2338,7 +2334,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re // Selector should be trimmed to avoid leading spaces (#14773) QUnit.asyncTest( "jQuery.fn.load( URL_SELECTOR with spaces )", 1, function( assert ) { - jQuery( "#first" ).load( "data/test3.html #superuser ", function() { + jQuery( "#first" ).load( baseURL + "test3.html #superuser ", function() { assert.strictEqual( jQuery( this ).children( "div" ).length, 1, "Verify that specific elements were injected" ); QUnit.start(); } ); @@ -2349,14 +2345,14 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.test( "jQuery.fn.load( URL_SELECTOR with non-HTML whitespace(#3003) )", function( assert ) { assert.expect( 1 ); var done = assert.async(); - jQuery( "#first" ).load( "data/test3.html #whitespace\\\\xA0 ", function() { + jQuery( "#first" ).load( baseURL + "test3.html #whitespace\\\\xA0 ", function() { assert.strictEqual( jQuery( this ).children( "div" ).length, 1, "Verify that specific elements were injected" ); done(); } ); } ); QUnit.asyncTest( "jQuery.fn.load( String, Function ) - simple: inject text into DOM", 2, function( assert ) { - jQuery( "#first" ).load( url( "data/name.html" ), function() { + jQuery( "#first" ).load( url( "name.html" ), function() { assert.ok( /^ERROR/.test( jQuery( "#first" ).text() ), "Check if content was injected into the DOM" ); QUnit.start(); } ); @@ -2372,7 +2368,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re Globals.register( "testFoo" ); Globals.register( "testBar" ); - jQuery( "#first" ).load( url( "data/test.html" ), function() { + jQuery( "#first" ).load( url( "mock.php?action=testHTML&baseURL=" + baseURL ), function() { assert.ok( jQuery( "#first" ).html().match( /^html text/ ), "Check content after loading html" ); assert.strictEqual( jQuery( "#foo" ).html(), "foo", "Check if script evaluation has modified DOM" ); assert.strictEqual( window[ "testFoo" ], "foo", "Check if script was evaluated after load" ); @@ -2383,7 +2379,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.asyncTest( "jQuery.fn.load( String, Function ) - check file with only a script tag", 3, function( assert ) { Globals.register( "testFoo" ); - jQuery( "#first" ).load( url( "data/test2.html" ), function() { + jQuery( "#first" ).load( url( "test2.html" ), function() { assert.strictEqual( jQuery( "#foo" ).html(), "foo", "Check if script evaluation has modified DOM" ); assert.strictEqual( window[ "testFoo" ], "foo", "Check if script was evaluated after load" ); QUnit.start(); @@ -2396,7 +2392,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re return "Hello World"; } } ); - jQuery( "<div/>" ).load( url( "data/name.html" ), function( responseText ) { + jQuery( "<div/>" ).load( url( "name.html" ), function( responseText ) { assert.strictEqual( jQuery( this ).html(), "Hello World", "Test div was filled with filtered data" ); assert.strictEqual( responseText, "Hello World", "Test callback receives filtered data" ); QUnit.start(); @@ -2404,13 +2400,12 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } ); QUnit.asyncTest( "jQuery.fn.load( String, Object, Function )", 2, function( assert ) { - jQuery( "<div />" ).load( url( "data/params_html.php" ), { - "foo": 3, + jQuery( "<div />" ).load( url( "mock.php?action=echoHtml" ), { "bar": "ok" }, function() { - var $post = jQuery( this ).find( "#post" ); - assert.strictEqual( $post.find( "#foo" ).text(), "3", "Check if a hash of data is passed correctly" ); - assert.strictEqual( $post.find( "#bar" ).text(), "ok", "Check if a hash of data is passed correctly" ); + var $node = jQuery( this ); + assert.strictEqual( $node.find( "#method" ).text(), "POST", "Check method" ); + assert.strictEqual( $node.find( "#data" ).text(), "bar=ok", "Check if data is passed correctly" ); QUnit.start(); } ); } ); @@ -2418,10 +2413,10 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re QUnit.test( "jQuery.fn.load( String, String, Function )", 2, function( assert ) { var done = assert.async(); - jQuery( "<div />" ).load( url( "data/params_html.php" ), "foo=3&bar=ok", function() { - var $get = jQuery( this ).find( "#get" ); - assert.strictEqual( $get.find( "#foo" ).text(), "3", "Check if a string of data is passed correctly" ); - assert.strictEqual( $get.find( "#bar" ).text(), "ok", "Check if a of data is passed correctly" ); + jQuery( "<div />" ).load( url( "mock.php?action=echoHtml" ), "foo=3&bar=ok", function() { + var $node = jQuery( this ); + assert.strictEqual( $node.find( "#method" ).text(), "GET", "Check method" ); + assert.ok( $node.find( "#query" ).text().match( /foo=3&bar=ok/ ), "Check if a string of data is passed correctly" ); done(); } ); } ); @@ -2444,11 +2439,11 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.map( [ { type: "success", - url: "data/echoQuery.php?arg=pop" + url: baseURL + "mock.php?action=echoQuery&arg=pop" }, { type: "error", - url: "data/404.php" + url: baseURL + "404.txt" } ], function( options ) { @@ -2477,7 +2472,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery( document ).off( "ajaxComplete" ); done(); } ); - jQuery( "#first" ).load( "data/test3.html" ); + jQuery( "#first" ).load( baseURL + "test3.html" ); } ); QUnit.test( "#10524 - jQuery.fn.load() - data specified in ajaxSettings is merged in", 1, function( assert ) { @@ -2491,7 +2486,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re "foo": "bar" } } ); - jQuery( "#foo" ).load( "data/echoQuery.php", data ); + jQuery( "#foo" ).load( baseURL + "mock.php?action=echoQuery", data ); jQuery( document ).ajaxComplete( function( event, jqXHR, options ) { assert.ok( ~options.data.indexOf( "foo=bar" ), "Data from ajaxSettings was used" ); done(); @@ -2505,10 +2500,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.when( jQuery.post( - url( "data/name.php" ), + url( "mock.php?action=xml" ), { - xml: "5-2", - length: 3 + cal: "5-2" }, function( xml ) { jQuery( "math", xml ).each( function() { @@ -2518,7 +2512,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } ), jQuery.ajax( { - url: url( "data/echoData.php" ), + url: url( "mock.php?action=echoData" ), type: "POST", data: { "test": { @@ -2530,9 +2524,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re assert.strictEqual( data, "test%5Blength%5D=7&test%5Bfoo%5D=bar", "Check if a sub-object with a length param is serialized correctly" ); } } ) - ).always( function() { - done(); - } ); + ).always( done ); } ); QUnit.test( "jQuery.post( String, Hash, Function ) - simple with xml", 4, function( assert ) { @@ -2540,9 +2532,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.when( jQuery.post( - url( "data/name.php" ), + url( "mock.php?action=xml" ), { - "xml": "5-2" + cal: "5-2" }, function( xml ) { jQuery( "math", xml ).each( function() { @@ -2551,7 +2543,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } ); } ), - jQuery.post( url( "data/name.php?xml=5-2" ), {}, function( xml ) { + jQuery.post( url( "mock.php?action=xml&cal=5-2" ), {}, function( xml ) { jQuery( "math", xml ).each( function() { assert.strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); assert.strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); @@ -2568,9 +2560,9 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.when.apply( jQuery, jQuery.map( [ "get", "post" ], function( method ) { return jQuery[ method ]( { - url: url( "data/name.php" ), + url: url( "mock.php?action=xml" ), data: { - "xml": "5-2" + cal: "5-2" }, success: function( xml ) { jQuery( "math", xml ).each( function() { diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 1284ffd18..3ab023eaf 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -127,7 +127,7 @@ QUnit.test( "attr(String)", function( assert ) { assert.equal( jQuery( option ).prop( "selected" ), true, "Make sure that a single option is selected, even when in an optgroup." ); - $img = jQuery( "<img style='display:none' width='215' height='53' src='data/1x1.jpg'/>" ).appendTo( "body" ); + $img = jQuery( "<img style='display:none' width='215' height='53' src='" + baseURL + "1x1.jpg'/>" ).appendTo( "body" ); assert.equal( $img.attr( "width" ), "215", "Retrieve width attribute on an element with display:none." ); assert.equal( $img.attr( "height" ), "53", "Retrieve height attribute on an element with display:none." ); @@ -780,7 +780,7 @@ QUnit.test( "prop('tabindex')", function( assert ) { QUnit.test( "image.prop( 'tabIndex' )", function( assert ) { assert.expect( 1 ); - var image = jQuery( "<img src='data/1x1.jpg' />" ) + var image = jQuery( "<img src='" + baseURL + "1x1.jpg' />" ) .appendTo( "#qunit-fixture" ); assert.equal( image.prop( "tabIndex" ), -1, "tabIndex on image" ); } ); diff --git a/test/unit/basic.js b/test/unit/basic.js index 15bca8ff6..b46a04c28 100644 --- a/test/unit/basic.js +++ b/test/unit/basic.js @@ -8,7 +8,7 @@ QUnit.test( "ajax", function( assert ) { jQuery.ajax( { type: "GET", - url: url( "data/name.php?name=foo" ), + url: url( "mock.php?action=name&name=foo" ), success: function( msg ) { assert.strictEqual( msg, "bar", "Check for GET" ); done.pop()(); @@ -17,7 +17,7 @@ QUnit.test( "ajax", function( assert ) { jQuery.ajax( { type: "POST", - url: url( "data/name.php" ), + url: url( "mock.php?action=name" ), data: "name=peter", success: function( msg ) { assert.strictEqual( msg, "pan", "Check for POST" ); @@ -25,7 +25,7 @@ QUnit.test( "ajax", function( assert ) { } } ); - jQuery( "#first" ).load( url( "data/name.html" ), function() { + jQuery( "#first" ).load( url( "name.html" ), function() { assert.ok( /^ERROR/.test( jQuery( "#first" ).text() ), "Check if content was injected into the DOM" ); done.pop()(); diff --git a/test/unit/core.js b/test/unit/core.js index 322b21dc6..3229f78d5 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -188,7 +188,7 @@ QUnit.test( "globalEval execution after script injection (#7862)", function( ass var now, script = document.createElement( "script" ); - script.src = "data/longLoadScript.php?sleep=2"; + script.src = baseURL + "mock.php?action=wait&wait=2&script=1"; now = jQuery.now(); document.body.appendChild( script ); @@ -1627,10 +1627,10 @@ QUnit.test( "jQuery.parseHTML", function( assert ) { QUnit.test( "jQuery.parseHTML(<a href>) - gh-2965", function( assert ) { assert.expect( 1 ); - var html = "<a href='test.html'></a>", + var html = "<a href='example.html'></a>", href = jQuery.parseHTML( html )[ 0 ].href; - assert.ok( /\/test\.html$/.test( href ), "href is not lost after parsing anchor" ); + assert.ok( /\/example\.html$/.test( href ), "href is not lost after parsing anchor" ); } ); if ( jQuery.support.createHTMLDocument ) { diff --git a/test/unit/css.js b/test/unit/css.js index 2ca72c1aa..20f8195aa 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1066,7 +1066,7 @@ QUnit.test( "can't get css for disconnected in IE<9, see #10254 and #8388", func assert.expect( 2 ); var span, div; - span = jQuery( "<span/>" ).css( "background-image", "url(data/1x1.jpg)" ); + span = jQuery( "<span/>" ).css( "background-image", "url(" + baseURL + "1x1.jpg)" ); assert.notEqual( span.css( "background-image" ), null, "can't get background-image in IE<9, see #10254" ); div = jQuery( "<div/>" ).css( "top", 10 ); @@ -1374,7 +1374,6 @@ QUnit.test( "Clearing a Cloned Element's Style Shouldn't Clear the Original Element's Style (#8908)", 24, function( assert ) { - var baseUrl = document.location.href.replace( /([^\/]*)$/, "" ); var done = assert.async(); var styles = [ { name: "backgroundAttachment", @@ -1388,7 +1387,7 @@ QUnit.test( // Firefox returns auto's value name: "backgroundImage", - value: [ "url('test.png')", "url(" + baseUrl + "test.png)", "url(\"" + baseUrl + "test.png\")" ], + value: [ "url('test.png')", "url(" + baseURL + "test.png)", "url(\"" + baseURL + "test.png\")" ], expected: [ "none", "url(\"http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif\")" ] }, { name: "backgroundPosition", diff --git a/test/unit/data.js b/test/unit/data.js index 0eb1d5149..248878eda 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -777,7 +777,7 @@ QUnit.test( ".removeData should not throw exceptions. (#10080)", function( asser } ); // change the url to trigger unload - frame.attr( "src", "data/iframe.html?param=true" ); + frame.attr( "src", baseURL + "iframe.html?param=true" ); } ); QUnit.test( ".data only checks element attributes once. #8909", function( assert ) { diff --git a/test/unit/effects.js b/test/unit/effects.js index ec1669f54..c5f8d53c3 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -33,7 +33,7 @@ QUnit.module( "effects", { QUnit[ jQuery.find.compile ? "test" : "skip" ]( "sanity check", function( assert ) { assert.expect( 1 ); - assert.equal( jQuery( "#dl:visible, #qunit-fixture:visible, #foo:visible" ).length, 3, "QUnit state is correct for testing effects" ); + assert.equal( jQuery( "#qunit-fixture:visible, #foo:visible" ).length, 2, "QUnit state is correct for testing effects" ); } ); QUnit.test( "show() basic", function( assert ) { diff --git a/test/unit/event.js b/test/unit/event.js index d7290a6a4..ccaf72514 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -1281,8 +1281,7 @@ QUnit.test( ".trigger() doesn't bubble load event (#10717)", function( assert ) assert.ok( false, "load fired on window" ); } ); - // It's not an image, but as long as it fires load... - jQuery( "<img src='index.html' />" ) + jQuery( "<img src='" + baseURL + "1x1.jpg' />" ) .appendTo( "body" ) .on( "load", function() { assert.ok( true, "load fired on img" ); @@ -1443,7 +1442,7 @@ QUnit.test( "Submit event can be stopped (#11049)", function( assert ) { // handler making it impossible to feature-detect the support. QUnit[ /(ipad|iphone|ipod)/i.test( navigator.userAgent ) ? "skip" : "test" ]( "on(beforeunload)", 1, function( assert ) { - var iframe = jQuery( jQuery.parseHTML( "<iframe src='data/event/onbeforeunload.html'><iframe>" ) ); + var iframe = jQuery( jQuery.parseHTML( "<iframe src='" + baseURL + "event/onbeforeunload.html'><iframe>" ) ); var done = assert.async(); window.onmessage = function( event ) { diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 4ad65ccb7..528a192ce 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2377,7 +2377,7 @@ QUnit.asyncTest( "html() - script exceptions bubble (#11743)", 2, function( asse assert.ok( true, "Exception thrown in remote script" ); }; - jQuery( "#qunit-fixture" ).html( "<script src='data/badcall.js'></script>" ); + jQuery( "#qunit-fixture" ).html( "<script src='" + baseURL + "badcall.js'></script>" ); assert.ok( true, "Exception ignored" ); } else { assert.ok( true, "No jQuery.ajax" ); @@ -2463,7 +2463,7 @@ QUnit.test( "script evaluation (#11795)", function( assert ) { if ( jQuery.ajax ) { Globals.register( "testBar" ); - jQuery( "#qunit-fixture" ).append( "<script src='" + url( "data/testbar.php" ) + "'/>" ); + jQuery( "#qunit-fixture" ).append( "<script src='" + url( "mock.php?action=testbar" ) + "'/>" ); assert.strictEqual( window.testBar, "bar", "Global script evaluation" ); } else { assert.ok( true, "No jQuery.ajax" ); diff --git a/test/unit/offset.js b/test/unit/offset.js index 8e0cd7275..61f762eea 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -771,12 +771,12 @@ QUnit.test( "offsetParent", function( assert ) { assert.equal( div[ 0 ], document.documentElement, "The html element is the offsetParent of the body." ); assert.equal( div[ 1 ], jQuery( "#nothiddendiv" )[ 0 ], "The div is the offsetParent." ); - area = jQuery( "#imgmap area" ).offsetParent(); - assert.equal( area[ 0 ], document.documentElement, "The html element is the offsetParent of the body." ); + area = jQuery( "<map name=\"imgmap\"><area shape=\"rect\" coords=\"0,0,200,50\"></map>" ).appendTo( "body" ).find( "area" ); + assert.equal( area.offsetParent()[ 0 ], document.documentElement, "The html element is the offsetParent of a map area." ); + area.remove(); div = jQuery( "<div>" ).css( { "position": "absolute" } ).appendTo( "body" ); assert.equal( div.offsetParent()[ 0 ], document.documentElement, "Absolutely positioned div returns html as offset parent, see #12139" ); - div.remove(); } ); diff --git a/test/unit/support.js b/test/unit/support.js index 312173207..a42a129f1 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -39,7 +39,7 @@ if ( jQuery.css ) { // i.e. no old WebKit or old Firefox testIframe( "Check CSP (https://developer.mozilla.org/en-US/docs/Security/CSP) restrictions", - "support/csp.php", + "mock.php?action=cspFrame", function( assert, jQuery, window, document, support ) { var done = assert.async(); @@ -47,9 +47,9 @@ testIframe( assert.deepEqual( jQuery.extend( {}, support ), computedSupport, "No violations of CSP polices" ); - supportjQuery.get( "data/support/csp.log" ).done( function( data ) { + supportjQuery.get( baseURL + "support/csp.log" ).done( function( data ) { assert.equal( data, "", "No log request should be sent" ); - supportjQuery.get( "data/support/csp-clean.php" ).done( done ); + supportjQuery.get( baseURL + "mock.php?action=cspClean" ).done( done ); } ); } ); diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 83c267a27..eeda204a5 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -608,7 +608,7 @@ QUnit.test( "parents([String])", function( assert ) { assert.equal( jQuery( "#groups" ).parents( "p" )[ 0 ].id, "ap", "Filtered parents check" ); assert.equal( jQuery( "#groups" ).parents( "div" )[ 0 ].id, "qunit-fixture", "Filtered parents check2" ); assert.deepEqual( jQuery( "#groups" ).parents( "p, div" ).get(), q( "ap", "qunit-fixture" ), "Check for multiple filters" ); - assert.deepEqual( jQuery( "#en, #sndp" ).parents().get(), q( "foo", "qunit-fixture", "dl", "body", "html" ), "Check for unique results from parents" ); + assert.deepEqual( jQuery( "#en, #sndp" ).parents().get(), q( "foo", "qunit-fixture", "body", "html" ), "Check for unique results from parents" ); } ); QUnit.test( "parentsUntil([String])", function( assert ) { @@ -621,11 +621,11 @@ QUnit.test( "parentsUntil([String])", function( assert ) { assert.deepEqual( jQuery( "#groups" ).parentsUntil( "#html" ).get(), parents.slice( 0, -1 ).get(), "Simple parentsUntil check" ); assert.equal( jQuery( "#groups" ).parentsUntil( "#ap" ).length, 0, "Simple parentsUntil check" ); assert.deepEqual( jQuery( "#nonnodes" ).contents().eq( 1 ).parentsUntil( "#html" ).eq( 0 ).get(), q( "nonnodes" ), "Text node parentsUntil check" ); - assert.deepEqual( jQuery( "#groups" ).parentsUntil( "#html, #body" ).get(), parents.slice( 0, 3 ).get(), "Less simple parentsUntil check" ); + assert.deepEqual( jQuery( "#groups" ).parentsUntil( "#html, #body" ).get(), parents.slice( 0, 2 ).get(), "Less simple parentsUntil check" ); assert.deepEqual( jQuery( "#groups" ).parentsUntil( "#html", "div" ).get(), jQuery( "#qunit-fixture" ).get(), "Filtered parentsUntil check" ); - assert.deepEqual( jQuery( "#groups" ).parentsUntil( "#html", "p,div,dl" ).get(), parents.slice( 0, 3 ).get(), "Multiple-filtered parentsUntil check" ); + assert.deepEqual( jQuery( "#groups" ).parentsUntil( "#html", "p,div" ).get(), parents.slice( 0, 2 ).get(), "Multiple-filtered parentsUntil check" ); assert.equal( jQuery( "#groups" ).parentsUntil( "#html", "span" ).length, 0, "Filtered parentsUntil check, no match" ); - assert.deepEqual( jQuery( "#groups, #ap" ).parentsUntil( "#html", "p,div,dl" ).get(), parents.slice( 0, 3 ).get(), "Multi-source, multiple-filtered parentsUntil check" ); + assert.deepEqual( jQuery( "#groups, #ap" ).parentsUntil( "#html", "p,div" ).get(), parents.slice( 0, 2 ).get(), "Multi-source, multiple-filtered parentsUntil check" ); } ); QUnit.test( "next([String])", function( assert ) { @@ -784,7 +784,7 @@ QUnit[ "content" in document.createElement( "template" ) ? "test" : "skip" ]( jQuery( "#qunit-fixture" ).append( "<template id='template'>" + " <script>testScript = 1;</script>" + - " <img src='data/1x1.jpg' onload='testImgOnload = 1' >" + + " <img src='" + baseURL + "1x1.jpg' onload='testImgOnload = 1' >" + "</template>" ); |