From 04ec688e806660107a0b5823fabe2fe213f63b92 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 28 Jul 2015 12:58:44 +0200 Subject: [PATCH] Core: Support non-browser environments Fixes gh-2133 Fixes gh-2501 Closes gh-2504 Refs gh-1950 Refs gh-1949 Refs gh-2397 Refs gh-1537 Refs gh-2504 Refs 842958e7aecd0d75a7ee9e2aaec83457701aa2f3 --- .gitignore | 2 ++ .jscsrc | 3 +- .jshintignore | 1 + Gruntfile.js | 18 ++++++++--- build/tasks/install_jsdom.js | 27 ++++++++++++++++ build/tasks/lib/spawn_test.js | 16 ++++++++++ build/tasks/node_smoke_tests.js | 32 +++++++++++++++++++ build/tasks/promises_aplus_tests.js | 13 ++++++++ package.json | 9 +++++- src/.jshintrc | 4 +-- src/ajax.js | 8 +++-- src/ajax/parseXML.js | 4 +-- src/ajax/script.js | 3 +- src/ajax/var/location.js | 3 ++ src/ajax/xhr.js | 3 +- src/attributes/support.js | 24 ++++++++------ src/core.js | 4 ++- src/core/init.js | 6 ++-- src/core/parseHTML.js | 3 +- src/core/ready.js | 7 ++-- src/core/support.js | 3 +- src/css.js | 7 ++-- src/css/curCSS.js | 5 +-- src/css/support.js | 24 +++++++------- src/data/support.js | 3 +- src/deferred.js | 2 +- src/effects.js | 10 +++--- src/event.js | 3 +- src/event/support.js | 3 +- src/manipulation.js | 3 +- src/manipulation/support.js | 14 ++++++-- src/offset.js | 4 ++- src/queue/delay.js | 4 +-- src/var/document.js | 3 ++ src/var/documentElement.js | 5 +++ test/node_smoke_tests/.jshintrc | 14 ++++++++ test/node_smoke_tests/document_missing.js | 11 +++++++ test/node_smoke_tests/document_passed.js | 14 ++++++++ .../document_present_originally.js | 17 ++++++++++ .../iterable_with_native_symbol.js | 8 +++++ .../iterable_with_symbol_polyfill.js | 13 ++++++++ .../lib/ensure_global_not_created.js | 15 +++++++++ .../lib/ensure_iterability_es6.js | 25 +++++++++++++++ test/node_smoke_tests/lib/ensure_jquery.js | 9 ++++++ test/promises_aplus_adapter.js | 22 +++++++++++++ 45 files changed, 363 insertions(+), 68 deletions(-) create mode 100644 build/tasks/install_jsdom.js create mode 100644 build/tasks/lib/spawn_test.js create mode 100644 build/tasks/node_smoke_tests.js create mode 100644 build/tasks/promises_aplus_tests.js create mode 100644 src/ajax/var/location.js create mode 100644 src/var/document.js create mode 100644 src/var/documentElement.js create mode 100644 test/node_smoke_tests/.jshintrc create mode 100644 test/node_smoke_tests/document_missing.js create mode 100644 test/node_smoke_tests/document_passed.js create mode 100644 test/node_smoke_tests/document_present_originally.js create mode 100644 test/node_smoke_tests/iterable_with_native_symbol.js create mode 100644 test/node_smoke_tests/iterable_with_symbol_polyfill.js create mode 100644 test/node_smoke_tests/lib/ensure_global_not_created.js create mode 100644 test/node_smoke_tests/lib/ensure_iterability_es6.js create mode 100644 test/node_smoke_tests/lib/ensure_jquery.js create mode 100644 test/promises_aplus_adapter.js diff --git a/.gitignore b/.gitignore index 463dea426..eae5df6e6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ /dist /node_modules + +/test/node_smoke_tests/lib/ensure_iterability.js diff --git a/.jscsrc b/.jscsrc index fa91a9d9e..14f349133 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,5 +1,6 @@ { "preset": "jquery", - "excludeFiles": [ "external", "src/intro.js", "src/outro.js" ] + "excludeFiles": [ "external", "src/intro.js", "src/outro.js", + "test/node_smoke_tests/lib/ensure_iterability.js" ] } diff --git a/.jshintignore b/.jshintignore index 19f1b9c52..1ddafd635 100644 --- a/.jshintignore +++ b/.jshintignore @@ -9,3 +9,4 @@ test/data/readywaitasset.js test/data/readywaitloader.js test/data/support/csp.js test/data/support/getComputedSupport.js +test/node_smoke_tests/lib/ensure_iterability.js diff --git a/Gruntfile.js b/Gruntfile.js index 082bf28c8..6b8dada62 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -34,6 +34,18 @@ module.exports = function( grunt ) { cache: "build/.sizecache.json" } }, + babel: { + options: { + sourceMap: "inline", + retainLines: true + }, + nodeSmokeTests: { + files: { + "test/node_smoke_tests/lib/ensure_iterability.js": + "test/node_smoke_tests/lib/ensure_iterability_es6.js" + } + } + }, build: { all: { dest: "dist/jquery.js", @@ -159,11 +171,9 @@ module.exports = function( grunt ) { grunt.registerTask( "lint", [ "jsonlint", "jshint", "jscs" ] ); - // Only defined for master at this time, but kept for cross-branch consistency - grunt.registerTask( "test_fast", [] ); + grunt.registerTask( "test_fast", [ "node_smoke_tests" ] ); - // gh-2133 TODO: cherry-pick 76df9e4e389d80bff410a9e5f08b848de1d21a2f for promises-aplus-tests - grunt.registerTask( "test", [ "test_fast"/*, "promises-aplus-tests"*/ ] ); + grunt.registerTask( "test", [ "test_fast", "promises_aplus_tests" ] ); // Short list as a high frequency watch task grunt.registerTask( "dev", [ "build:*:*", "lint", "uglify", "remove_map_comment", "dist:*" ] ); diff --git a/build/tasks/install_jsdom.js b/build/tasks/install_jsdom.js new file mode 100644 index 000000000..21d67eb0e --- /dev/null +++ b/build/tasks/install_jsdom.js @@ -0,0 +1,27 @@ +module.exports = function( grunt ) { + grunt.registerTask( "jsdom", function() { + var current, + pkg = grunt.config( "pkg" ), + version = pkg.jsdomVersions[ + + // Unfortunately, this is currently the only + // way to tell the difference between Node and iojs + /^v0/.test( process.version ) ? "node" : "iojs" + ]; + + try { + current = require( "jsdom/package.json" ).version; + if ( current === version ) { + return; + } + } catch ( e ) {} + + // Use npm on the command-line + // There is no local npm + grunt.util.spawn( { + cmd: "npm", + args: [ "install", "jsdom@" + version ], + opts: { stdio: "inherit" } + }, this.async() ); + }); +}; diff --git a/build/tasks/lib/spawn_test.js b/build/tasks/lib/spawn_test.js new file mode 100644 index 000000000..6c4596a3d --- /dev/null +++ b/build/tasks/lib/spawn_test.js @@ -0,0 +1,16 @@ +/* jshint node: true */ + +"use strict"; + +// Run Node with provided parameters: the first one being the Grunt +// done function and latter ones being files to be tested. +// See the comment in ../node_smoke_tests.js for more information. +module.exports = function spawnTest( done ) { + var testPaths = [].slice.call( arguments, 1 ), + spawn = require( "win-spawn" ); + + spawn( "node", testPaths, { stdio: "inherit" } ) + .on( "close", function( code ) { + done( code === 0 ); + } ); +} ; diff --git a/build/tasks/node_smoke_tests.js b/build/tasks/node_smoke_tests.js new file mode 100644 index 000000000..9334516d9 --- /dev/null +++ b/build/tasks/node_smoke_tests.js @@ -0,0 +1,32 @@ +module.exports = function( grunt ) { + + "use strict"; + + var fs = require( "fs" ), + spawnTest = require( "./lib/spawn_test.js" ), + testsDir = "./test/node_smoke_tests/", + nodeSmokeTests = [ "jsdom", "babel:nodeSmokeTests" ]; + + // Fire up all tests defined in test/node_smoke_tests/*.js in spawned sub-processes. + // All the files under test/node_smoke_tests/*.js are supposed to exit with 0 code + // on success or another one on failure. Spawning in sub-processes is + // important so that the tests & the main process don't interfere with + // each other, e.g. so that they don't share the require cache. + + fs.readdirSync( testsDir ) + .filter( function( testFilePath ) { + return fs.statSync( testsDir + testFilePath ).isFile() && + /\.js$/.test( testFilePath ); + } ) + .forEach( function( testFilePath ) { + var taskName = "node_" + testFilePath.replace( /\.js$/, "" ); + + grunt.registerTask( taskName, function() { + spawnTest( this.async(), "test/node_smoke_tests/" + testFilePath ); + } ); + + nodeSmokeTests.push( taskName ); + } ); + + grunt.registerTask( "node_smoke_tests", nodeSmokeTests ); +}; diff --git a/build/tasks/promises_aplus_tests.js b/build/tasks/promises_aplus_tests.js new file mode 100644 index 000000000..3e770a079 --- /dev/null +++ b/build/tasks/promises_aplus_tests.js @@ -0,0 +1,13 @@ +module.exports = function( grunt ) { + + "use strict"; + + var spawnTest = require( "./lib/spawn_test.js" ); + + grunt.registerTask( "promises_aplus_tests", function() { + spawnTest( this.async(), + "./node_modules/.bin/promises-aplus-tests", + "test/promises_aplus_adapter.js" + ); + } ); +}; diff --git a/package.json b/package.json index eb6c27f49..a8178ea7d 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "dependencies": {}, "devDependencies": { "commitplease": "2.0.0", + "core-js": "0.9.17", "grunt": "0.4.5", + "grunt-babel": "5.0.1", "grunt-cli": "0.1.13", "grunt-compare-size": "0.4.0", "grunt-contrib-jshint": "0.11.2", @@ -46,7 +48,12 @@ "sinon": "1.12.2", "sizzle": "2.2.0", "strip-json-comments": "1.0.3", - "testswarm": "1.1.0" + "testswarm": "1.1.0", + "win-spawn": "2.0.0" + }, + "jsdomVersions": { + "node": "3.1.2", + "iojs": "5.3.0" }, "scripts": { "build": "npm install && grunt", diff --git a/src/.jshintrc b/src/.jshintrc index 87dcde1cd..f1a2eb53e 100644 --- a/src/.jshintrc +++ b/src/.jshintrc @@ -16,11 +16,11 @@ // The above browsers are failing a lot of tests in the ES5 // test suite at http://test262.ecmascript.org. "es3": true, - "browser": true, - "wsh": true, "globals": { + "window": true, "JSON": false, + "jQuery": true, "define": false, "module": false, diff --git a/src/ajax.js b/src/ajax.js index 24425bac6..8357d6420 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -1,13 +1,15 @@ define([ "./core", + "./var/document", "./var/rnotwhite", + "./ajax/var/location", "./ajax/var/nonce", "./ajax/var/rquery", "./core/init", "./ajax/parseJSON", "./ajax/parseXML", "./deferred" -], function( jQuery, rnotwhite, nonce, rquery ) { +], function( jQuery, document, rnotwhite, location, nonce, rquery ) { var rhash = /#.*$/, @@ -643,7 +645,7 @@ jQuery.extend({ // Timeout if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout(function() { + timeoutTimer = window.setTimeout(function() { jqXHR.abort("timeout"); }, s.timeout ); } @@ -677,7 +679,7 @@ jQuery.extend({ // Clear timeout if it exists if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); + window.clearTimeout( timeoutTimer ); } // Dereference transport for early garbage collection diff --git a/src/ajax/parseXML.js b/src/ajax/parseXML.js index 9fbd9da9a..e0b248513 100644 --- a/src/ajax/parseXML.js +++ b/src/ajax/parseXML.js @@ -10,10 +10,10 @@ jQuery.parseXML = function( data ) { } try { if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); + tmp = new window.DOMParser(); xml = tmp.parseFromString( data, "text/xml" ); } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml = new window.ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } diff --git a/src/ajax/script.js b/src/ajax/script.js index 2e937fe65..1af0963f3 100644 --- a/src/ajax/script.js +++ b/src/ajax/script.js @@ -1,7 +1,8 @@ define([ "../core", + "../var/document", "../ajax" -], function( jQuery ) { +], function( jQuery, document ) { // Install script dataType jQuery.ajaxSetup({ diff --git a/src/ajax/var/location.js b/src/ajax/var/location.js new file mode 100644 index 000000000..4c9cf4a4c --- /dev/null +++ b/src/ajax/var/location.js @@ -0,0 +1,3 @@ +define(function() { + return window.location; +}); diff --git a/src/ajax/xhr.js b/src/ajax/xhr.js index 585703f44..ef68ef4c0 100644 --- a/src/ajax/xhr.js +++ b/src/ajax/xhr.js @@ -1,8 +1,9 @@ define([ "../core", + "../var/document", "../var/support", "../ajax" -], function( jQuery, support ) { +], function( jQuery, document, support ) { // Create the request object // (This is still attached to ajaxSettings for backward compatibility) diff --git a/src/attributes/support.js b/src/attributes/support.js index 044e23823..6fd6827f4 100644 --- a/src/attributes/support.js +++ b/src/attributes/support.js @@ -1,21 +1,25 @@ define([ + "../var/document", "../var/support" -], function( support ) { +], function( document, support ) { (function() { - // Minified: var a,b,c,d,e - var input, div, select, a, opt; + var a, + input = document.createElement( "input" ), + div = document.createElement( "div" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); // Setup - div = document.createElement( "div" ); - div.innerHTML = " a"; - a = div.getElementsByTagName("a")[ 0 ]; + div.innerHTML = " a"; + // Support: Windows Web Apps (WWA) + // `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "checkbox" ); + div.appendChild( input ); - // First batch of tests. - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; + a = div.getElementsByTagName( "a" )[ 0 ]; + // First batch of tests. a.style.cssText = "top:1px"; // Get the style information from getAttribute diff --git a/src/core.js b/src/core.js index 6eae1990c..0c21744e2 100644 --- a/src/core.js +++ b/src/core.js @@ -1,5 +1,6 @@ define([ "./var/deletedIds", + "./var/document", "./var/slice", "./var/concat", "./var/push", @@ -8,7 +9,8 @@ define([ "./var/toString", "./var/hasOwn", "./var/support" -], function( deletedIds, slice, concat, push, indexOf, class2type, toString, hasOwn, support ) { +], function( deletedIds, document, slice, concat, push, indexOf, + class2type, toString, hasOwn, support ) { var version = "@VERSION+compat", diff --git a/src/core/init.js b/src/core/init.js index 52999d4ea..a438ea0db 100644 --- a/src/core/init.js +++ b/src/core/init.js @@ -1,16 +1,14 @@ // Initialize a jQuery object define([ "../core", + "../var/document", "./var/rsingleTag", "../traversing/findFilter" -], function( jQuery, rsingleTag ) { +], function( jQuery, document, rsingleTag ) { // A central reference to the root jQuery(document) var rootjQuery, - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) diff --git a/src/core/parseHTML.js b/src/core/parseHTML.js index 68dd6cf8d..e7d7c63c8 100644 --- a/src/core/parseHTML.js +++ b/src/core/parseHTML.js @@ -1,11 +1,12 @@ define([ "../core", + "../var/document", "./var/rsingleTag", "../manipulation/buildFragment", // This is the only module that needs core/support "./support" -], function( jQuery, rsingleTag, buildFragment, support ) { +], function( jQuery, document, rsingleTag, buildFragment, support ) { // data: string of html // context (optional): If specified, the fragment will be created in this context, diff --git a/src/core/ready.js b/src/core/ready.js index ae72fdeab..c5835a4a3 100644 --- a/src/core/ready.js +++ b/src/core/ready.js @@ -1,7 +1,8 @@ define([ "../core", + "../var/document", "../deferred" -], function( jQuery ) { +], function( jQuery, document ) { // The deferred used on DOM ready var readyList; @@ -72,7 +73,7 @@ function detach() { function completed() { // readyState === "complete" is good enough for us to call the dom ready in oldIE if ( document.addEventListener || - event.type === "load" || + window.event.type === "load" || document.readyState === "complete" ) { detach(); @@ -93,7 +94,7 @@ jQuery.ready.promise = function( obj ) { // http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); + window.setTimeout( jQuery.ready ); // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { diff --git a/src/core/support.js b/src/core/support.js index e15450275..8348ab7e3 100644 --- a/src/core/support.js +++ b/src/core/support.js @@ -1,6 +1,7 @@ define([ + "../var/document", "../var/support" -], function( support ) { +], function( document, support ) { // Support: Safari 8+ // In Safari 8 documents created via document.implementation.createHTMLDocument diff --git a/src/css.js b/src/css.js index 43ba09cd3..27c5ecf88 100644 --- a/src/css.js +++ b/src/css.js @@ -3,12 +3,13 @@ define([ "./var/pnum", "./core/access", "./css/var/rmargin", + "./var/document", "./var/rcssNum", "./css/var/rnumnonpx", "./css/var/cssExpand", "./css/var/isHidden", - "./css/curCSS", "./css/var/swap", + "./css/curCSS", "./css/adjustCSS", "./css/addGetHookIf", "./css/support", @@ -17,8 +18,8 @@ define([ "./core/init", "./core/ready", "./selector" // contains -], function( jQuery, pnum, access, rmargin, rcssNum, rnumnonpx, cssExpand, isHidden, - curCSS, swap, adjustCSS, addGetHookIf, support, showHide ) { +], function( jQuery, pnum, access, rmargin, document, rcssNum, rnumnonpx, cssExpand, + isHidden, swap, curCSS, adjustCSS, addGetHookIf, support, showHide ) { var // BuildExclude diff --git a/src/css/curCSS.js b/src/css/curCSS.js index 918139631..967ce3e94 100644 --- a/src/css/curCSS.js +++ b/src/css/curCSS.js @@ -1,11 +1,12 @@ define([ "exports", "../core", + "../var/documentElement", "./var/rnumnonpx", "./var/rmargin", "./support", "../selector" // contains -], function( exports, jQuery, rnumnonpx, rmargin, support ) { +], function( exports, jQuery, documentElement, rnumnonpx, rmargin, support ) { var getStyles, curCSS, rposition = /^(top|right|bottom|left)$/; @@ -68,7 +69,7 @@ if ( window.getComputedStyle ) { ret : ret + ""; }; -} else if ( document.documentElement.currentStyle ) { +} else if ( documentElement.currentStyle ) { getStyles = function( elem ) { return elem.currentStyle; }; diff --git a/src/css/support.js b/src/css/support.js index 6b5731771..7eb3c7de4 100644 --- a/src/css/support.js +++ b/src/css/support.js @@ -1,32 +1,30 @@ define([ "../core", + "../var/document", + "../var/documentElement", "../var/support" -], function( jQuery, support ) { +], function( jQuery, document, documentElement, support ) { (function() { - var div, container, style, a, pixelPositionVal, boxSizingReliableVal, gBCRDimensionsVal, - pixelMarginRightVal, reliableHiddenOffsetsVal, reliableMarginRightVal; - - // Setup - div = document.createElement( "div" ); - div.innerHTML = "
a"; - a = div.getElementsByTagName( "a" )[ 0 ]; - style = a && a.style; + var pixelPositionVal, boxSizingReliableVal, gBCRDimensionsVal, + pixelMarginRightVal, reliableHiddenOffsetsVal, reliableMarginRightVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); // Finish early in limited (non-browser) environments - if ( !style ) { + if ( !div.style ) { return; } - style.cssText = "float:left;opacity:.5"; + div.style.cssText = "float:left;opacity:.5"; // Support: IE<9 // Make sure that element opacity exists (as opposed to filter) - support.opacity = style.opacity === "0.5"; + support.opacity = div.style.opacity === "0.5"; // Verify style float existence // (IE uses styleFloat instead of cssFloat) - support.cssFloat = !!style.cssFloat; + support.cssFloat = !!div.style.cssFloat; div.style.backgroundClip = "content-box"; div.cloneNode( true ).style.backgroundClip = ""; diff --git a/src/data/support.js b/src/data/support.js index 9e0ba14bc..df17c5c40 100644 --- a/src/data/support.js +++ b/src/data/support.js @@ -1,6 +1,7 @@ define([ + "../var/document", "../var/support" -], function( support ) { +], function( document, support ) { (function() { var div = document.createElement( "div" ); diff --git a/src/deferred.js b/src/deferred.js index ac6956dfb..050ad765e 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -176,7 +176,7 @@ jQuery.extend({ if ( depth ) { process(); } else { - setTimeout( process ); + window.setTimeout( process ); } }; } diff --git a/src/effects.js b/src/effects.js index a6b5748f5..9a0e4e0f1 100644 --- a/src/effects.js +++ b/src/effects.js @@ -1,5 +1,6 @@ define([ "./core", + "./var/document", "./var/rcssNum", "./var/rnotwhite", "./css/var/cssExpand", @@ -15,7 +16,8 @@ define([ "./manipulation", "./css", "./effects/Tween" -], function( jQuery, rcssNum, rnotwhite, cssExpand, isHidden, swap, adjustCSS, showHide ) { +], function( jQuery, document, rcssNum, rnotwhite, cssExpand, isHidden, swap, + adjustCSS, showHide ) { var fxNow, timerId, @@ -31,7 +33,7 @@ function raf() { // Animations created synchronously will run synchronously function createFxNow() { - setTimeout(function() { + window.setTimeout(function() { fxNow = undefined; }); return ( fxNow = jQuery.now() ); @@ -640,14 +642,14 @@ jQuery.fx.interval = 13; jQuery.fx.start = function() { timerId = window.requestAnimationFrame ? window.requestAnimationFrame( raf ) : - setInterval( jQuery.fx.tick, jQuery.fx.interval ); + window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); }; jQuery.fx.stop = function() { if ( window.cancelAnimationFrame ) { window.cancelAnimationFrame( timerId ); } else { - clearInterval( timerId ); + window.clearInterval( timerId ); } timerId = null; diff --git a/src/event.js b/src/event.js index 165c2c0f0..f821bbda7 100644 --- a/src/event.js +++ b/src/event.js @@ -1,5 +1,6 @@ define([ "./core", + "./var/document", "./var/rnotwhite", "./var/hasOwn", "./var/slice", @@ -8,7 +9,7 @@ define([ "./core/init", "./data", "./selector" -], function( jQuery, rnotwhite, hasOwn, slice, support ) { +], function( jQuery, document, rnotwhite, hasOwn, slice, support ) { var rformElems = /^(?:input|select|textarea)$/i, rkeyEvent = /^key/, diff --git a/src/event/support.js b/src/event/support.js index ed0c861aa..132575c20 100644 --- a/src/event/support.js +++ b/src/event/support.js @@ -1,6 +1,7 @@ define([ + "../var/document", "../var/support" -], function( support ) { +], function( document, support ) { (function() { var i, eventName, diff --git a/src/manipulation.js b/src/manipulation.js index 4fc1e0cf3..d62d480b7 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -1,5 +1,6 @@ define([ "./core", + "./var/document", "./var/concat", "./var/push", "./var/deletedIds", @@ -22,7 +23,7 @@ define([ "./traversing", "./selector", "./event" -], function( jQuery, concat, push, deletedIds, access, +], function( jQuery, document, concat, push, deletedIds, access, rcheckableType, rtagName, rscriptType, rleadingWhitespace, nodeNames, createSafeFragment, wrapMap, getAll, setGlobalEval, buildFragment, support ) { diff --git a/src/manipulation/support.js b/src/manipulation/support.js index 9bfceabe2..edf162a3f 100644 --- a/src/manipulation/support.js +++ b/src/manipulation/support.js @@ -1,11 +1,13 @@ define([ "../core", + "../var/document", "../var/support" -], function( jQuery, support ) { +], function( jQuery, document, support ) { (function() { var div = document.createElement( "div" ), - fragment = document.createDocumentFragment(); + fragment = document.createDocumentFragment(), + input = document.createElement( "input" ); // Setup div.innerHTML = " "; @@ -29,7 +31,13 @@ define([ // #11217 - WebKit loses check when the name is after the checked attribute fragment.appendChild( div ); - div.innerHTML = ""; + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); // Support: Android<4.2 // Older WebKit doesn't clone checked state correctly in fragments diff --git a/src/offset.js b/src/offset.js index 43bf20b7c..5e5ce7bc7 100644 --- a/src/offset.js +++ b/src/offset.js @@ -1,6 +1,8 @@ define([ "./core", "./core/access", + "./var/document", + "./var/documentElement", "./css/var/rnumnonpx", "./css/curCSS", "./css/addGetHookIf", @@ -9,7 +11,7 @@ define([ "./core/init", "./css", "./selector" // contains -], function( jQuery, access, rnumnonpx, curCSS, addGetHookIf, support ) { +], function( jQuery, access, document, documentElement, rnumnonpx, curCSS, addGetHookIf, support ) { // BuildExclude curCSS = curCSS.curCSS; diff --git a/src/queue/delay.js b/src/queue/delay.js index 037ef0998..93abd0bf2 100644 --- a/src/queue/delay.js +++ b/src/queue/delay.js @@ -11,9 +11,9 @@ jQuery.fn.delay = function( time, type ) { type = type || "fx"; return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); + var timeout = window.setTimeout( next, time ); hooks.stop = function() { - clearTimeout( timeout ); + window.clearTimeout( timeout ); }; }); }; diff --git a/src/var/document.js b/src/var/document.js new file mode 100644 index 000000000..ded014f1a --- /dev/null +++ b/src/var/document.js @@ -0,0 +1,3 @@ +define(function() { + return window.document; +}); diff --git a/src/var/documentElement.js b/src/var/documentElement.js new file mode 100644 index 000000000..c639670f1 --- /dev/null +++ b/src/var/documentElement.js @@ -0,0 +1,5 @@ +define([ + "./document" +], function( document ) { + return document.documentElement; +}); diff --git a/test/node_smoke_tests/.jshintrc b/test/node_smoke_tests/.jshintrc new file mode 100644 index 000000000..1445c7b18 --- /dev/null +++ b/test/node_smoke_tests/.jshintrc @@ -0,0 +1,14 @@ +{ + "boss": true, + "curly": true, + "eqeqeq": true, + "eqnull": true, + "expr": true, + "immed": true, + "noarg": true, + "quotmark": "double", + "undef": true, + "unused": true, + + "node": true +} diff --git a/test/node_smoke_tests/document_missing.js b/test/node_smoke_tests/document_missing.js new file mode 100644 index 000000000..4a0ad2e2b --- /dev/null +++ b/test/node_smoke_tests/document_missing.js @@ -0,0 +1,11 @@ +"use strict"; + +var assert = require( "assert" ), + ensureGlobalNotCreated = require( "./lib/ensure_global_not_created" ), + jQueryFactory = require( "../../dist/jquery.js" ); + +assert.throws( function () { + jQueryFactory( {} ); +}, /jQuery requires a window with a document/ ); + +ensureGlobalNotCreated( module.exports ); diff --git a/test/node_smoke_tests/document_passed.js b/test/node_smoke_tests/document_passed.js new file mode 100644 index 000000000..5999cc744 --- /dev/null +++ b/test/node_smoke_tests/document_passed.js @@ -0,0 +1,14 @@ +"use strict"; + +var assert = require( "assert" ); + +require( "jsdom" ).env( "", function( errors, window ) { + assert.ifError( errors ); + + var ensureJQuery = require( "./lib/ensure_jquery" ), + ensureGlobalNotCreated = require( "./lib/ensure_global_not_created" ), + jQuery = require( "../../dist/jquery.js" )( window ); + + ensureJQuery( jQuery ); + ensureGlobalNotCreated( module.exports ); +} ); diff --git a/test/node_smoke_tests/document_present_originally.js b/test/node_smoke_tests/document_present_originally.js new file mode 100644 index 000000000..f75148708 --- /dev/null +++ b/test/node_smoke_tests/document_present_originally.js @@ -0,0 +1,17 @@ +"use strict"; + +var assert = require( "assert" ); + +require( "jsdom" ).env( "", function( errors, window ) { + assert.ifError( errors ); + + // Pretend the window is a global. + global.window = window; + + var ensureJQuery = require( "./lib/ensure_jquery" ), + ensureGlobalNotCreated = require( "./lib/ensure_global_not_created" ), + jQuery = require( "../../dist/jquery.js" ); + + ensureJQuery( jQuery ); + ensureGlobalNotCreated( module.exports, window ); +} ); diff --git a/test/node_smoke_tests/iterable_with_native_symbol.js b/test/node_smoke_tests/iterable_with_native_symbol.js new file mode 100644 index 000000000..3376ebdc5 --- /dev/null +++ b/test/node_smoke_tests/iterable_with_native_symbol.js @@ -0,0 +1,8 @@ +"use strict"; + +if ( typeof Symbol === "undefined" ) { + console.log( "Symbols not supported, skipping the test..." ); + process.exit(); +} + +require( "./lib/ensure_iterability_es6" )(); diff --git a/test/node_smoke_tests/iterable_with_symbol_polyfill.js b/test/node_smoke_tests/iterable_with_symbol_polyfill.js new file mode 100644 index 000000000..dd377f19c --- /dev/null +++ b/test/node_smoke_tests/iterable_with_symbol_polyfill.js @@ -0,0 +1,13 @@ +/* jshint esnext: true */ + +"use strict"; + +var assert = require( "assert" ); + +delete global.Symbol; +require( "core-js" ); + +assert.strictEqual( typeof Symbol, "function", "Expected Symbol to be a function" ); +assert.notEqual( typeof Symbol.iterator, "symbol", "Expected Symbol.iterator to be polyfilled" ); + +require( "./lib/ensure_iterability" )(); diff --git a/test/node_smoke_tests/lib/ensure_global_not_created.js b/test/node_smoke_tests/lib/ensure_global_not_created.js new file mode 100644 index 000000000..7cc83b541 --- /dev/null +++ b/test/node_smoke_tests/lib/ensure_global_not_created.js @@ -0,0 +1,15 @@ +"use strict"; + +var assert = require( "assert" ); + +// Ensure the jQuery property on global/window/module.exports/etc. was not +// created in a CommonJS environment. +// `global` is always checked in addition to passed parameters. +module.exports = function ensureGlobalNotCreated() { + var args = [].slice.call( arguments ).concat( global ); + + args.forEach( function( object ) { + assert.strictEqual( object.jQuery, undefined, + "A jQuery global was created in a CommonJS environment." ); + } ); +}; diff --git a/test/node_smoke_tests/lib/ensure_iterability_es6.js b/test/node_smoke_tests/lib/ensure_iterability_es6.js new file mode 100644 index 000000000..ebe68539e --- /dev/null +++ b/test/node_smoke_tests/lib/ensure_iterability_es6.js @@ -0,0 +1,25 @@ +/* jshint esnext: true */ + +"use strict"; + +var assert = require( "assert" ); + +module.exports = function ensureIterability() { + require( "jsdom" ).env( "", function( errors, window ) { + assert.ifError( errors ); + + var i, + ensureJQuery = require( "./ensure_jquery" ), + jQuery = require( "../../../dist/jquery.js" )( window ), + elem = jQuery( "
" ), + result = ""; + + ensureJQuery( jQuery ); + + for ( i of elem ) { + result += i.nodeName; + } + + assert.strictEqual( result, "DIVSPANA", "for-of doesn't work on jQuery objects" ); + } ); +}; diff --git a/test/node_smoke_tests/lib/ensure_jquery.js b/test/node_smoke_tests/lib/ensure_jquery.js new file mode 100644 index 000000000..0933a1d33 --- /dev/null +++ b/test/node_smoke_tests/lib/ensure_jquery.js @@ -0,0 +1,9 @@ +"use strict"; + +var assert = require( "assert" ); + +// Check if the object we got is the jQuery object by invoking a basic API. +module.exports = function ensureJQuery( jQuery ) { + assert( /^jQuery/.test( jQuery.expando ), + "jQuery.expando was not detected, the jQuery bootstrap process has failed" ); +}; diff --git a/test/promises_aplus_adapter.js b/test/promises_aplus_adapter.js new file mode 100644 index 000000000..decc3e0f0 --- /dev/null +++ b/test/promises_aplus_adapter.js @@ -0,0 +1,22 @@ +/* jshint node: true */ + +"use strict"; + +require( "jsdom" ).env( "", function ( errors, window ) { + if ( errors ) { + console.error( errors ); + return; + } + + var jQuery = require( ".." )( window ); + + exports.deferred = function () { + var deferred = jQuery.Deferred(); + + return { + promise: deferred.promise(), + resolve: deferred.resolve.bind( deferred ), + reject: deferred.reject.bind( deferred ) + }; + }; +} ); -- 2.39.5