diff --git a/src/ajax.js b/src/ajax.js index 9db26f66c..31880032d 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -458,6 +458,12 @@ jQuery.extend( { if ( !responseHeaders ) { responseHeaders = {}; while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + + // Support: IE 11+ + // `getResponseHeader( key )` in IE doesn't combine all header + // values for the provided key into a single result with values + // joined by commas as other browsers do. Instead, it returns + // them on separate lines. responseHeaders[ match[ 1 ].toLowerCase() + " " ] = ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) .concat( match[ 2 ] ); diff --git a/src/attributes/attr.js b/src/attributes/attr.js index 6b5cbd2c4..cd2b3128b 100644 --- a/src/attributes/attr.js +++ b/src/attributes/attr.js @@ -2,10 +2,10 @@ define( [ "../core", "../core/access", "../core/nodeName", - "./support", "../var/rnothtmlwhite", + "../var/isIE", "../selector" -], function( jQuery, access, nodeName, support, rnothtmlwhite ) { +], function( jQuery, access, nodeName, rnothtmlwhite, isIE ) { "use strict"; @@ -74,8 +74,10 @@ jQuery.extend( { attrHooks: { type: { set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { + + // Support: IE <=11+ + // An input loses its value after becoming a radio + if ( isIE && value === "radio" && nodeName( elem, "input" ) ) { var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { diff --git a/src/attributes/prop.js b/src/attributes/prop.js index 8ada707f4..71358aa92 100644 --- a/src/attributes/prop.js +++ b/src/attributes/prop.js @@ -1,9 +1,9 @@ define( [ "../core", "../core/access", - "./support", + "../var/isIE", "../selector" -], function( jQuery, access, support ) { +], function( jQuery, access, isIE ) { "use strict"; @@ -90,14 +90,11 @@ jQuery.extend( { } ); // Support: IE <=11+ -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { +// Accessing the selectedIndex property forces the browser to respect +// setting selected on the option. The getter ensures a default option +// is selected when in an optgroup. ESLint rule "no-unused-expressions" +// is disabled for this code since it considers such accessions noop. +if ( isIE ) { jQuery.propHooks.selected = { get: function( elem ) { diff --git a/src/attributes/support.js b/src/attributes/support.js deleted file mode 100644 index 78d0040a9..000000000 --- a/src/attributes/support.js +++ /dev/null @@ -1,29 +0,0 @@ -define( [ - "../var/document", - "../var/support" -], function( document, support ) { - -"use strict"; - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: IE <=11+ - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11+ - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - -return support; - -} ); diff --git a/src/css.js b/src/css.js index 91c42624e..2ae0c0c2c 100644 --- a/src/css.js +++ b/src/css.js @@ -2,6 +2,7 @@ define( [ "./core", "./core/access", "./var/rcssNum", + "./var/isIE", "./css/var/rnumnonpx", "./css/var/cssExpand", "./css/isAutoPx", @@ -10,14 +11,13 @@ define( [ "./css/var/swap", "./css/curCSS", "./css/adjustCSS", - "./css/support", "./css/finalPropName", "./core/init", "./core/ready", "./selector" // contains -], function( jQuery, access, rcssNum, rnumnonpx, cssExpand, isAutoPx, cssCamelCase, - getStyles, swap, curCSS, adjustCSS, support, finalPropName ) { +], function( jQuery, access, rcssNum, isIE, rnumnonpx, cssExpand, isAutoPx, + cssCamelCase, getStyles, swap, curCSS, adjustCSS, finalPropName ) { "use strict"; @@ -121,7 +121,7 @@ function getWidthOrHeight( elem, dimension, extra ) { // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, + boxSizingNeeded = isIE || extra, isBorderBox = boxSizingNeeded && jQuery.css( elem, "boxSizing", false, styles ) === "border-box", valueIsBorderBox = isBorderBox, @@ -140,11 +140,12 @@ function getWidthOrHeight( elem, dimension, extra ) { // Fall back to offsetWidth/offsetHeight when value is "auto" // This happens for inline elements with no explicit setting (gh-3571) + // // Support: IE 9 - 11+ // Also use offsetWidth/offsetHeight for when box sizing is unreliable // We use getClientRects() to check for hidden/disconnected. // In those cases, the computed value can be trusted to be border-box - if ( ( !support.boxSizingReliable() && isBorderBox || val === "auto" ) && + if ( ( isIE && isBorderBox || val === "auto" ) && elem.getClientRects().length ) { isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; @@ -239,8 +240,9 @@ jQuery.extend( { value += ret && ret[ 3 ] || ( isAutoPx( origName ) ? "px" : "" ); } - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + // Support: IE <=9 - 11+ + // background-* props of a cloned element affect the source element (#8908) + if ( isIE && value === "" && name.indexOf( "background" ) === 0 ) { style[ name ] = "inherit"; } diff --git a/src/css/support.js b/src/css/support.js deleted file mode 100644 index 65763baec..000000000 --- a/src/css/support.js +++ /dev/null @@ -1,60 +0,0 @@ -define( [ - "../core", - "../var/document", - "../var/documentElement", - "../var/support" -], function( jQuery, document, documentElement, support ) { - -"use strict"; - -( function() { - - var boxSizingReliableVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11+ - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - - // This is a singleton, we need to execute it only once - if ( div ) { - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - - // Support: IE 9 - 11+ - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = Math.round( parseFloat( divStyle.width ) ) === 36; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - return boxSizingReliableVal; - } - } ); -} )(); - -return support; - -} ); diff --git a/src/manipulation.js b/src/manipulation.js index fb10ef5c2..cca3947ce 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -2,6 +2,7 @@ define( [ "./core", "./core/isAttached", "./var/concat", + "./var/isIE", "./var/push", "./var/rcheckableType", "./core/access", @@ -11,7 +12,6 @@ define( [ "./manipulation/getAll", "./manipulation/setGlobalEval", "./manipulation/buildFragment", - "./manipulation/support", "./data/var/dataPriv", "./data/var/dataUser", @@ -23,9 +23,9 @@ define( [ "./traversing", "./selector", "./event" -], function( jQuery, isAttached, concat, push, rcheckableType, - access, rtagName, rscriptType, - wrapMap, getAll, setGlobalEval, buildFragment, support, +], function( jQuery, isAttached, concat, isIE, push, + rcheckableType, access, rtagName, rscriptType, + wrapMap, getAll, setGlobalEval, buildFragment, dataPriv, dataUser, acceptData, DOMEval, nodeName ) { "use strict"; @@ -222,7 +222,7 @@ jQuery.extend( { inPage = isAttached( elem ); // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + if ( isIE && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 @@ -233,7 +233,7 @@ jQuery.extend( { // Support: IE <=11+ // IE fails to set the defaultValue to the correct value when - // cloning other types of input fields + // cloning textareas. if ( destElements[ i ].nodeName.toLowerCase() === "textarea" ) { destElements[ i ].defaultValue = srcElements[ i ].defaultValue; } diff --git a/src/manipulation/support.js b/src/manipulation/support.js deleted file mode 100644 index f2ff88e17..000000000 --- a/src/manipulation/support.js +++ /dev/null @@ -1,28 +0,0 @@ -define( [ - "../var/document", - "../var/support" -], function( document, support ) { - -"use strict"; - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - - div.appendChild( input ); - - // Support: IE <=11+ - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); - -return support; - -} ); diff --git a/src/var/isIE.js b/src/var/isIE.js new file mode 100644 index 000000000..e6a37cb5a --- /dev/null +++ b/src/var/isIE.js @@ -0,0 +1,7 @@ +define( [ + "./document" +], function( document ) { + "use strict"; + + return document.documentMode; +} ); diff --git a/test/data/inner_nomodule.js b/test/data/inner_nomodule.js index c37b4ed42..a84492b68 100644 --- a/test/data/inner_nomodule.js +++ b/test/data/inner_nomodule.js @@ -1 +1 @@ -QUnit.assert.ok( !QUnit.moduleTypeSupported, "evaluated: inner nomodule script with src" ); +QUnit.assert.ok( QUnit.isIE, "evaluated: inner nomodule script with src" ); diff --git a/test/data/nomodule.js b/test/data/nomodule.js index 155143ab8..804c07a22 100644 --- a/test/data/nomodule.js +++ b/test/data/nomodule.js @@ -1 +1 @@ -QUnit.assert.ok( !QUnit.moduleTypeSupported, "evaluated: nomodule script with src" ); +QUnit.assert.ok( QUnit.isIE, "evaluated: nomodule script with src" ); diff --git a/test/data/testinit-jsdom.js b/test/data/testinit-jsdom.js index e0830cc92..37e57d8c4 100644 --- a/test/data/testinit-jsdom.js +++ b/test/data/testinit-jsdom.js @@ -4,6 +4,9 @@ // jsdom implements a throwing `window.scrollTo`. QUnit.config.scrolltop = false; +QUnit.isIE = false; +QUnit.testUnlessIE = QUnit.test; + const FILEPATH = "/test/data/testinit-jsdom.js"; const activeScript = document.currentScript; const parentUrl = activeScript && activeScript.src ? diff --git a/test/data/testinit.js b/test/data/testinit.js index eb4901062..cb600cf15 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -256,14 +256,11 @@ if ( !window.__karma__ ) { QUnit.isSwarm = ( QUnit.urlParams.swarmURL + "" ).indexOf( "http" ) === 0; QUnit.basicTests = ( QUnit.urlParams.module + "" ) === "basic"; -// Async test for module script type support -function moduleTypeSupported() { - var script = document.createElement( "script" ); - script.type = "module"; - script.text = "QUnit.moduleTypeSupported = true"; - document.head.appendChild( script ).parentNode.removeChild( script ); -} -moduleTypeSupported(); +// Support: IE 11+ +// A variable to make it easier to skip specific tests in IE, mostly +// testing integrations with newer Web features not supported by it. +QUnit.isIE = !!window.document.documentMode; +QUnit.testUnlessIE = QUnit.isIE ? QUnit.skip : QUnit.test; this.loadTests = function() { diff --git a/test/middleware-mockserver.js b/test/middleware-mockserver.js index 20a660714..a8f83c205 100644 --- a/test/middleware-mockserver.js +++ b/test/middleware-mockserver.js @@ -138,7 +138,7 @@ var mocks = { "constructor": "prototype collision (constructor)" } ); req.query.keys.split( "|" ).forEach( function( key ) { - if ( req.headers[ key.toLowerCase() ] ) { + if ( key.toLowerCase() in req.headers ) { resp.write( key + ": " + req.headers[ key.toLowerCase() ] + "\n" ); } } ); diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 9b151988d..bda534ea5 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -260,7 +260,7 @@ QUnit.module( "ajax", { } ); }, url: url( "mock.php?action=headers&keys=siMPle|SometHing-elsE|OthEr|Nullable|undefined|Empty|ajax-send" ), - headers: { + headers: supportjQuery.extend( { "siMPle": "value", "SometHing-elsE": "other value", "OthEr": "something else", @@ -268,11 +268,12 @@ QUnit.module( "ajax", { "undefined": undefined // Support: IE 9 - 11+, Edge 12 - 14 only - // Not all browsers allow empty-string headers - //"Empty": "" - }, + // IE can receive empty headers but not send them. + }, QUnit.isIE ? {} : { + "Empty": "" + } ), success: function( data, _, xhr ) { - var i, emptyHeader, + var i, requestHeaders = jQuery.extend( this.headers, { "ajax-send": "test" } ), @@ -285,13 +286,7 @@ QUnit.module( "ajax", { assert.strictEqual( data, tmp, "Headers were sent" ); assert.strictEqual( xhr.getResponseHeader( "Sample-Header" ), "Hello World", "Sample header received" ); assert.ok( data.indexOf( "undefined" ) < 0, "Undefined header value was not sent" ); - - emptyHeader = xhr.getResponseHeader( "Empty-Header" ); - if ( emptyHeader === null ) { - assert.ok( true, "Firefox doesn't support empty headers" ); - } else { - assert.strictEqual( emptyHeader, "", "Empty header received" ); - } + assert.strictEqual( xhr.getResponseHeader( "Empty-Header" ), "", "Empty header received" ); assert.strictEqual( xhr.getResponseHeader( "Sample-Header2" ), "Hello World 2", "Second sample header received" ); assert.strictEqual( xhr.getResponseHeader( "List-Header" ), "Item 1, Item 2", "List header received" ); assert.strictEqual( xhr.getResponseHeader( "constructor" ), "prototype collision (constructor)", "constructor header received" ); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 7d5d2de1a..1e176b22e 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -989,29 +989,37 @@ QUnit.test( "val() with non-matching values on dropdown list", function( assert select6.remove(); } ); -if ( "value" in document.createElement( "meter" ) && - "value" in document.createElement( "progress" ) ) { +QUnit.test( "val() respects numbers without exception (Bug #9319) - progress", + function( assert ) { - QUnit.test( "val() respects numbers without exception (Bug #9319)", function( assert ) { + assert.expect( 2 ); - assert.expect( 4 ); + var $progress = jQuery( "" ); - var $meter = jQuery( "" ), - $progress = jQuery( "" ); + try { + assert.equal( typeof $progress.val(), "number", "progress, returns a number and does not throw exception" ); + assert.equal( $progress.val(), $progress[ 0 ].value, "progress, api matches host and does not throw exception" ); - try { - assert.equal( typeof $meter.val(), "number", "meter, returns a number and does not throw exception" ); - assert.equal( $meter.val(), $meter[ 0 ].value, "meter, api matches host and does not throw exception" ); + } catch ( e ) {} - assert.equal( typeof $progress.val(), "number", "progress, returns a number and does not throw exception" ); - assert.equal( $progress.val(), $progress[ 0 ].value, "progress, api matches host and does not throw exception" ); + $progress.remove(); +} ); - } catch ( e ) {} +// IE doesn't support +QUnit.testUnlessIE( "val() respects numbers without exception (Bug #9319) - meter", + function( assert ) { - $meter.remove(); - $progress.remove(); - } ); -} + assert.expect( 2 ); + + var $meter = jQuery( "" ); + + try { + assert.equal( typeof $meter.val(), "number", "meter, returns a number and does not throw exception" ); + assert.equal( $meter.val(), $meter[ 0 ].value, "meter, api matches host and does not throw exception" ); + } catch ( e ) {} + + $meter.remove(); +} ); var testVal = function( valueObj, assert ) { assert.expect( 9 ); diff --git a/test/unit/core.js b/test/unit/core.js index 6c331349a..df71caa26 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -329,7 +329,7 @@ QUnit.test( "isPlainObject", function( assert ) { } } ); -QUnit[ typeof Symbol === "function" ? "test" : "skip" ]( "isPlainObject(Symbol)", function( assert ) { +QUnit.testUnlessIE( "isPlainObject(Symbol)", function( assert ) { assert.expect( 2 ); assert.equal( jQuery.isPlainObject( Symbol() ), false, "Symbol" ); @@ -342,7 +342,7 @@ QUnit.test( "isPlainObject(localStorage)", function( assert ) { assert.equal( jQuery.isPlainObject( localStorage ), false ); } ); -QUnit[ "assign" in Object ? "test" : "skip" ]( "isPlainObject(Object.assign(...))", +QUnit.testUnlessIE( "isPlainObject(Object.assign(...))", function( assert ) { assert.expect( 1 ); diff --git a/test/unit/css.js b/test/unit/css.js index 75b1cc7ef..24d490ef3 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -641,7 +641,11 @@ QUnit.test( "show/hide detached nodes", function( assert ) { span.remove(); } ); -QUnit[ document.body.getRootNode ? "test" : "skip" ]( "show/hide shadow child nodes", function( assert ) { +// Support: IE 11+, Edge 12 - 18+ +// IE/Edge don't support Shadow DOM. +QUnit[ document.body.getRootNode ? "test" : "skip" ]( + "show/hide shadow child nodes", function( assert ) { + assert.expect( 28 ); jQuery( "
" ).appendTo( "#qunit-fixture" ); var shadowHost = document.querySelector( "#shadowHost" ); @@ -1210,11 +1214,10 @@ QUnit.test( "Do not append px (#9548, #12990, #2792)", function( assert ) { } ); -QUnit[ - jQuery( "
" )[ 0 ].style.gridArea === "" ? - "test" : - "skip" -]( "Do not append px to CSS Grid-related properties (gh-4007)", function( assert ) { +// IE doesn't support the standard version of CSS Grid. +QUnit.testUnlessIE( "Do not append px to CSS Grid-related properties (gh-4007)", + function( assert ) { + assert.expect( 12 ); var prop, value, subProp, subValue, $div, @@ -1365,50 +1368,28 @@ testIframe( } ); -( function() { - var supportsFractionalGBCR, - qunitFixture = document.getElementById( "qunit-fixture" ), - div = document.createElement( "div" ); - div.style.width = "3.3px"; - qunitFixture.appendChild( div ); - supportsFractionalGBCR = div.getBoundingClientRect().width.toFixed( 1 ) === "3.3"; - qunitFixture.removeChild( div ); +QUnit.testUnlessIE( "css('width') and css('height') should return fractional values for nodes in the document", function( assert ) { + assert.expect( 2 ); - QUnit.test( "css('width') and css('height') should return fractional values for nodes in the document", function( assert ) { - if ( !supportsFractionalGBCR ) { - assert.expect( 1 ); - assert.ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" ); - return; - } + var el = jQuery( "
" ).appendTo( "#qunit-fixture" ); + jQuery( "" ).appendTo( "#qunit-fixture" ); - assert.expect( 2 ); + assert.equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", + "css('width') should return fractional values" ); + assert.equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", + "css('height') should return fractional values" ); +} ); - var el = jQuery( "
" ).appendTo( "#qunit-fixture" ); - jQuery( "" ).appendTo( "#qunit-fixture" ); +QUnit.testUnlessIE( "css('width') and css('height') should return fractional values for disconnected nodes", function( assert ) { + assert.expect( 2 ); - assert.equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", - "css('width') should return fractional values" ); - assert.equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", - "css('height') should return fractional values" ); - } ); + var el = jQuery( "
" ); - QUnit.test( "css('width') and css('height') should return fractional values for disconnected nodes", function( assert ) { - if ( !supportsFractionalGBCR ) { - assert.expect( 1 ); - assert.ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" ); - return; - } - - assert.expect( 2 ); - - var el = jQuery( "
" ); - - assert.equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", - "css('width') should return fractional values" ); - assert.equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", - "css('height') should return fractional values" ); - } ); -} )(); + assert.equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", + "css('width') should return fractional values" ); + assert.equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", + "css('height') should return fractional values" ); +} ); QUnit.test( "certain css values of 'normal' should be convertable to a number, see #8627", function( assert ) { assert.expect( 3 ); @@ -1736,94 +1717,87 @@ QUnit.test( "Do not throw on frame elements from css method (#15098)", function( } )(); -( function() { - var supportsCssVars, - elem = jQuery( "
" ).appendTo( document.body ), - div = elem[ 0 ]; +// IE doesn't support CSS variables. +QUnit.testUnlessIE( "css(--customProperty)", function( assert ) { - div.style.setProperty( "--prop", "value" ); - supportsCssVars = !!getComputedStyle( div ).getPropertyValue( "--prop" ); - elem.remove(); + jQuery( "#qunit-fixture" ).append( + "" + ); - QUnit[ supportsCssVars ? "test" : "skip" ]( "css(--customProperty)", function( assert ) { - jQuery( "#qunit-fixture" ).append( - "" - ); + var div = jQuery( "
" ).appendTo( "#qunit-fixture" ), + $elem = jQuery( "
" ).addClass( "test__customProperties" ) + .appendTo( "#qunit-fixture" ), + webkitOrBlink = /\bsafari\b/i.test( navigator.userAgent ) && + !/\bfirefox\b/i.test( navigator.userAgent ) && + !/\bedge\b/i.test( navigator.userAgent ), + expected = 10; - var div = jQuery( "
" ).appendTo( "#qunit-fixture" ), - $elem = jQuery( "
" ).addClass( "test__customProperties" ) - .appendTo( "#qunit-fixture" ), - webkitOrBlink = /\bsafari\b/i.test( navigator.userAgent ) && - !/\bfirefox\b/i.test( navigator.userAgent ) && - !/\bedge\b/i.test( navigator.userAgent ), - expected = 10; + if ( webkitOrBlink ) { + expected -= 2; + } + assert.expect( expected ); - if ( webkitOrBlink ) { - expected -= 2; - } - assert.expect( expected ); + div.css( "--color", "blue" ); + assert.equal( div.css( "--color" ), "blue", "Modified CSS custom property using string" ); - div.css( "--color", "blue" ); - assert.equal( div.css( "--color" ), "blue", "Modified CSS custom property using string" ); + div.css( "--color", "yellow" ); + assert.equal( div.css( "--color" ), "yellow", "Overwrite CSS custom property" ); - div.css( "--color", "yellow" ); - assert.equal( div.css( "--color" ), "yellow", "Overwrite CSS custom property" ); + div.css( { "--color": "red" } ); + assert.equal( div.css( "--color" ), "red", "Modified CSS custom property using object" ); - div.css( { "--color": "red" } ); - assert.equal( div.css( "--color" ), "red", "Modified CSS custom property using object" ); + div.css( { "--mixedCase": "green" } ); + div.css( { "--mixed-case": "red" } ); + assert.equal( div.css( "--mixedCase" ), "green", + "Modified CSS custom property with mixed case" ); - div.css( { "--mixedCase": "green" } ); - div.css( { "--mixed-case": "red" } ); - assert.equal( div.css( "--mixedCase" ), "green", - "Modified CSS custom property with mixed case" ); + div.css( { "--theme-dark": "purple" } ); + div.css( { "--themeDark": "red" } ); + assert.equal( div.css( "--theme-dark" ), "purple", + "Modified CSS custom property with dashed name" ); - div.css( { "--theme-dark": "purple" } ); - div.css( { "--themeDark": "red" } ); - assert.equal( div.css( "--theme-dark" ), "purple", - "Modified CSS custom property with dashed name" ); + assert.equal( $elem.css( "--prop1" ), "val1", "Basic CSS custom property" ); - assert.equal( $elem.css( "--prop1" ), "val1", "Basic CSS custom property" ); + assert.equal( $elem.css( "--prop2" ), " val2", "Preceding whitespace maintained" ); + assert.equal( $elem.css( "--prop3" ), "val3 ", "Following whitespace maintained" ); - assert.equal( $elem.css( "--prop2" ), " val2", "Preceding whitespace maintained" ); - assert.equal( $elem.css( "--prop3" ), "val3 ", "Following whitespace maintained" ); + // Support: Chrome <=49 - 73+, Safari <=9.1 - 12.1+ + // Chrome treats single quotes as double ones. + // Safari treats double quotes as single ones. + if ( !webkitOrBlink ) { + assert.equal( $elem.css( "--prop4" ), "\"val4\"", "Works with double quotes" ); + assert.equal( $elem.css( "--prop5" ), "'val5'", "Works with single quotes" ); + } +} ); - // Support: Chrome <=49 - 73+, Safari <=9.1 - 12.1+ - // Chrome treats single quotes as double ones. - // Safari treats double quotes as single ones. - if ( !webkitOrBlink ) { - assert.equal( $elem.css( "--prop4" ), "\"val4\"", "Works with double quotes" ); - assert.equal( $elem.css( "--prop5" ), "'val5'", "Works with single quotes" ); - } - } ); +// IE doesn't support CSS variables. +QUnit.testUnlessIE( "Don't append px to CSS vars", function( assert ) { - QUnit[ supportsCssVars ? "test" : "skip" ]( "Don't append px to CSS vars", function( assert ) { - assert.expect( 3 ); + assert.expect( 3 ); - var $div = jQuery( "
" ).appendTo( "#qunit-fixture" ); + var $div = jQuery( "
" ).appendTo( "#qunit-fixture" ); - $div - .css( "--a", 3 ) - .css( "--line-height", 4 ) - .css( "--lineHeight", 5 ); + $div + .css( "--a", 3 ) + .css( "--line-height", 4 ) + .css( "--lineHeight", 5 ); - assert.equal( $div.css( "--a" ), "3", "--a: 3" ); - assert.equal( $div.css( "--line-height" ), "4", "--line-height: 4" ); - assert.equal( $div.css( "--lineHeight" ), "5", "--lineHeight: 5" ); - } ); -} )(); - -} + assert.equal( $div.css( "--a" ), "3", "--a: 3" ); + assert.equal( $div.css( "--line-height" ), "4", "--line-height: 4" ); + assert.equal( $div.css( "--lineHeight" ), "5", "--lineHeight: 5" ); +} ); // Support: IE 11+ -if ( document.documentMode ) { +// This test requires Grid to be *not supported* to work. +if ( QUnit.isIE ) { // Make sure explicitly provided IE vendor prefix (`-ms-`) is not converted // to a non-working `Ms` prefix in JavaScript. QUnit.test( "IE vendor prefixes are not mangled", function( assert ) { @@ -1836,3 +1810,5 @@ if ( document.documentMode ) { assert.strictEqual( div.css( "-ms-grid-row" ), "1", "IE vendor prefixing" ); } ); } + +} diff --git a/test/unit/data.js b/test/unit/data.js index 07628bfd4..7e019a4ce 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -513,16 +513,14 @@ QUnit.test( ".removeData()", function( assert ) { assert.equal( div.data( "test.foo" ), undefined, "Make sure data is intact" ); } ); -if ( window.JSON && window.JSON.stringify ) { - QUnit.test( "JSON serialization (#8108)", function( assert ) { - assert.expect( 1 ); +QUnit.test( "JSON serialization (#8108)", function( assert ) { + assert.expect( 1 ); - var obj = { "foo": "bar" }; - jQuery.data( obj, "hidden", true ); + var obj = { "foo": "bar" }; + jQuery.data( obj, "hidden", true ); - assert.equal( JSON.stringify( obj ), "{\"foo\":\"bar\"}", "Expando is hidden from JSON.stringify" ); - } ); -} + assert.equal( JSON.stringify( obj ), "{\"foo\":\"bar\"}", "Expando is hidden from JSON.stringify" ); +} ); QUnit.test( ".data should follow html5 specification regarding camel casing", function( assert ) { assert.expect( 12 ); diff --git a/test/unit/deferred.js b/test/unit/deferred.js index 936a57524..27a913216 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -543,25 +543,23 @@ QUnit.test( "jQuery.Deferred.then - spec compatibility", function( assert ) { } catch ( _ ) {} } ); -QUnit[ typeof Symbol === "function" && Symbol.toStringTag ? "test" : "skip" ]( - "jQuery.Deferred.then - IsCallable determination (gh-3596)", +QUnit.testUnlessIE( "jQuery.Deferred.then - IsCallable determination (gh-3596)", function( assert ) { - assert.expect( 1 ); + assert.expect( 1 ); - var done = assert.async(), - defer = jQuery.Deferred(); + var done = assert.async(), + defer = jQuery.Deferred(); - function faker() { - assert.ok( true, "handler with non-'Function' @@toStringTag gets invoked" ); - } - faker[ Symbol.toStringTag ] = "String"; - - defer.then( faker ).then( done ); - - defer.resolve(); + function faker() { + assert.ok( true, "handler with non-'Function' @@toStringTag gets invoked" ); } -); + faker[ Symbol.toStringTag ] = "String"; + + defer.then( faker ).then( done ); + + defer.resolve(); +} ); QUnit.test( "jQuery.Deferred.exceptionHook", function( assert ) { diff --git a/test/unit/deprecated.js b/test/unit/deprecated.js index fd920fb73..c0ebf19d6 100644 --- a/test/unit/deprecated.js +++ b/test/unit/deprecated.js @@ -41,29 +41,25 @@ QUnit.test( "delegate/undelegate", function( assert ) { .remove(); } ); -if ( jQuery.fn.hover ) { - QUnit.test( "hover() mouseenter mouseleave", function( assert ) { - assert.expect( 1 ); +QUnit[ jQuery.fn.hover ? "test" : "skip" ]( "hover() mouseenter mouseleave", function( assert ) { + assert.expect( 1 ); - var times = 0, - handler1 = function() { ++times; }, - handler2 = function() { ++times; }; + var times = 0, + handler1 = function() { ++times; }, + handler2 = function() { ++times; }; - jQuery( "#firstp" ) - .hover( handler1, handler2 ) - .mouseenter().mouseleave() - .off( "mouseenter", handler1 ) - .off( "mouseleave", handler2 ) - .hover( handler1 ) - .mouseenter().mouseleave() - .off( "mouseenter mouseleave", handler1 ) - .mouseenter().mouseleave(); - - assert.equal( times, 4, "hover handlers fired" ); - - } ); -} + jQuery( "#firstp" ) + .hover( handler1, handler2 ) + .mouseenter().mouseleave() + .off( "mouseenter", handler1 ) + .off( "mouseleave", handler2 ) + .hover( handler1 ) + .mouseenter().mouseleave() + .off( "mouseenter mouseleave", handler1 ) + .mouseenter().mouseleave(); + assert.equal( times, 4, "hover handlers fired" ); +} ); QUnit[ jQuery.fn.click ? "test" : "skip" ]( "trigger() shortcuts", function( assert ) { assert.expect( 5 ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 4a3ad5ecb..d20a56c3b 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -659,9 +659,9 @@ QUnit.test( "interaction with scrollbars (gh-3589)", function( assert ) { parent = jQuery( "
" ) .css( { position: "absolute", width: "1000px", height: "1000px" } ) .appendTo( "#qunit-fixture" ), - fraction = jQuery.support.boxSizingReliable() ? - jQuery( "
" ).appendTo( parent ).width() % 1 : - 0, + + // Workarounds for IE kill fractional output here. + fraction = document.documentMode ? 0 : 0.5, borderWidth = 1, padding = 2, size = 100 + fraction, diff --git a/test/unit/effects.js b/test/unit/effects.js index 9f9f34514..c2e38fa86 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -221,6 +221,8 @@ supportjQuery.each( hideOptions, function( type, setup ) { assert.expectJqData( this, $span, "olddisplay" ); } ); + // Support: IE 11+, Edge 12 - 18+ + // IE/Edge don't support Shadow DOM. QUnit[ document.body.getRootNode ? "test" : "skip" ]( "Persist correct display value - " + type + " hidden, shadow child", function( assert ) { assert.expect( 3 ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index e5cf856ec..2ba802656 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -445,18 +445,16 @@ QUnit.test( "append HTML5 sectioning elements (Bug #6485)", function( assert ) { assert.equal( aside.length, 1, "HTML5 elements do not collapse their children" ); } ); -if ( jQuery.css ) { - QUnit.test( "HTML5 Elements inherit styles from style rules (Bug #10501)", function( assert ) { +QUnit[ jQuery.fn.css ? "test" : "skip" ]( "HTML5 Elements inherit styles from style rules (Bug #10501)", function( assert ) { - assert.expect( 1 ); + assert.expect( 1 ); - jQuery( "#qunit-fixture" ).append( "
" ); - jQuery( "#article" ).append( "
This section should have a pink background.
" ); + jQuery( "#qunit-fixture" ).append( "
" ); + jQuery( "#article" ).append( "
This section should have a pink background.
" ); - // In IE, the missing background color will claim its value is "transparent" - assert.notEqual( jQuery( "section" ).css( "background-color" ), "transparent", "HTML5 elements inherit styles" ); - } ); -} + // In IE, the missing background color will claim its value is "transparent" + assert.notEqual( jQuery( "section" ).css( "background-color" ), "transparent", "HTML5 elements inherit styles" ); +} ); QUnit.test( "html(String) with HTML5 (Bug #6485)", function( assert ) { @@ -1767,9 +1765,9 @@ QUnit.test( "html(Function)", function( assert ) { QUnit[ // Support: Edge 16 - 18+ // Edge sometimes doesn't execute module scripts so skip the test there. - ( QUnit.moduleTypeSupported && !/edge\//i.test( navigator.userAgent ) ) ? - "test" : - "skip" + ( QUnit.isIE || /edge\//i.test( navigator.userAgent ) ) ? + "skip" : + "test" ]( "html(script type module)", function( assert ) { assert.expect( 4 ); var done = assert.async(), @@ -1794,18 +1792,17 @@ QUnit[ QUnit.test( "html(script nomodule)", function( assert ) { - // Support: IE 9 - 11+ // `nomodule` scripts should be executed by legacy browsers only. - assert.expect( QUnit.moduleTypeSupported ? 0 : 4 ); + assert.expect( QUnit.isIE ? 4 : 0 ); var done = assert.async(), $fixture = jQuery( "#qunit-fixture" ); $fixture.html( [ - "", + "", "", "
", - "", + "", "", "
" ].join( "" ) diff --git a/test/unit/queue.js b/test/unit/queue.js index 6c8ad762d..df7eaf4ca 100644 --- a/test/unit/queue.js +++ b/test/unit/queue.js @@ -271,64 +271,61 @@ QUnit.test( ".promise(obj)", function( assert ) { assert.strictEqual( promise, obj, ".promise(type, obj) returns obj" ); } ); -if ( jQuery.fn.stop ) { - QUnit.test( "delay() can be stopped", function( assert ) { - var done = assert.async(); - assert.expect( 3 ); - var storage = {}; - jQuery( {} ) - .queue( "alternate", function( next ) { - storage.alt1 = true; - assert.ok( true, "This first function was dequeued" ); - next(); - } ) - .delay( 1000, "alternate" ) - .queue( "alternate", function() { - storage.alt2 = true; - assert.ok( true, "The function was dequeued immediately, the delay was stopped" ); - } ) - .dequeue( "alternate" ) +QUnit[ jQuery.fn.stop ? "test" : "skip" ]( "delay() can be stopped", function( assert ) { + var done = assert.async(); + assert.expect( 3 ); + var storage = {}; + jQuery( {} ) + .queue( "alternate", function( next ) { + storage.alt1 = true; + assert.ok( true, "This first function was dequeued" ); + next(); + } ) + .delay( 1000, "alternate" ) + .queue( "alternate", function() { + storage.alt2 = true; + assert.ok( true, "The function was dequeued immediately, the delay was stopped" ); + } ) + .dequeue( "alternate" ) - // stop( "alternate", false ) will NOT clear the queue, so it should automatically dequeue the next - .stop( "alternate", false, false ) + // stop( "alternate", false ) will NOT clear the queue, so it should automatically dequeue the next + .stop( "alternate", false, false ) - // this test - .delay( 1 ) - .queue( function() { - storage.default1 = true; - assert.ok( false, "This queue should never run" ); - } ) + // this test + .delay( 1 ) + .queue( function() { + storage.default1 = true; + assert.ok( false, "This queue should never run" ); + } ) - // stop( clearQueue ) should clear the queue - .stop( true, false ); + // stop( clearQueue ) should clear the queue + .stop( true, false ); - assert.deepEqual( storage, { alt1: true, alt2: true }, "Queue ran the proper functions" ); + assert.deepEqual( storage, { alt1: true, alt2: true }, "Queue ran the proper functions" ); - setTimeout( function() { + setTimeout( function() { + done(); + }, 1500 ); +} ); + +QUnit[ jQuery.fn.stop ? "test" : "skip" ]( "queue stop hooks", function( assert ) { + assert.expect( 2 ); + var done = assert.async(); + var foo = jQuery( "#foo" ); + + foo.queue( function( next, hooks ) { + hooks.stop = function( gotoEnd ) { + assert.equal( !!gotoEnd, false, "Stopped without gotoEnd" ); + }; + } ); + foo.stop(); + + foo.queue( function( next, hooks ) { + hooks.stop = function( gotoEnd ) { + assert.equal( gotoEnd, true, "Stopped with gotoEnd" ); done(); - }, 1500 ); + }; } ); - QUnit.test( "queue stop hooks", function( assert ) { - assert.expect( 2 ); - var done = assert.async(); - var foo = jQuery( "#foo" ); - - foo.queue( function( next, hooks ) { - hooks.stop = function( gotoEnd ) { - assert.equal( !!gotoEnd, false, "Stopped without gotoEnd" ); - }; - } ); - foo.stop(); - - foo.queue( function( next, hooks ) { - hooks.stop = function( gotoEnd ) { - assert.equal( gotoEnd, true, "Stopped with gotoEnd" ); - done(); - }; - } ); - - foo.stop( false, true ); - } ); - -} // if ( jQuery.fn.stop ) + foo.stop( false, true ); +} ); diff --git a/test/unit/support.js b/test/unit/support.js index e81e60c5d..266b02dd8 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -58,48 +58,12 @@ testIframe( var expected, userAgent = window.navigator.userAgent, expectedMap = { - edge: { - boxSizingReliable: true, - clearCloneStyle: true, - noCloneChecked: true, - optSelected: true, - radioValue: true - }, - ie_11: { - boxSizingReliable: false, - clearCloneStyle: false, - noCloneChecked: false, - optSelected: false, - radioValue: false - }, - chrome: { - boxSizingReliable: true, - clearCloneStyle: true, - noCloneChecked: true, - optSelected: true, - radioValue: true - }, - safari: { - boxSizingReliable: true, - clearCloneStyle: true, - noCloneChecked: true, - optSelected: true, - radioValue: true - }, - firefox: { - boxSizingReliable: true, - clearCloneStyle: true, - noCloneChecked: true, - optSelected: true, - radioValue: true - }, - ios: { - boxSizingReliable: true, - clearCloneStyle: true, - noCloneChecked: true, - optSelected: true, - radioValue: true - } + edge: {}, + ie_11: {}, + chrome: {}, + safari: {}, + firefox: {}, + ios: {} }; if ( /edge\//i.test( userAgent ) ) { @@ -140,8 +104,8 @@ testIframe( } } ); - QUnit.test( "Verify most support tests are failing in one " + - "of tested browsers", function( assert ) { + QUnit.test( "Verify support tests are failing in one of tested browsers", + function( assert ) { var prop, browserKey, supportTestName, i = 0, diff --git a/test/unit/traversing.js b/test/unit/traversing.js index e8d23536e..57273dece 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -773,7 +773,7 @@ QUnit.test( "contents() for