From 6341f4260abecb106a78427cc5aa6df5adc64eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Wed, 7 Sep 2016 11:56:17 +0200 Subject: [PATCH 1/4] refactor(jqLite): run more tests on jQuery 2.2, add version detection helpers --- test/jqLiteSpec.js | 146 ++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 87ad0566a08f..48be3ed8199a 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -3,6 +3,19 @@ describe('jqLite', function() { var scope, a, b, c, document; + // Checks if jQuery 2.1 is used. + function isJQuery21() { + if (_jqLiteMode) return false; + var jQueryVersionParts = _jQuery.fn.jquery.split('.'); + return jQueryVersionParts[0] + '.' + jQueryVersionParts[1] === '2.1'; + } + + // Checks if jQuery 2.x is used. + function isJQuery2x() { + if (_jqLiteMode) return false; + var jQueryVersionParts = _jQuery.fn.jquery.split('.'); + return jQueryVersionParts[0] === '2'; + } beforeEach(module(provideLog)); @@ -83,30 +96,27 @@ describe('jqLite', function() { }); - // This is not working correctly in jQuery prior to v3.0. + // This is not working correctly in jQuery prior to v2.2. // See https://github.com/jquery/jquery/issues/1987 for details. it('should properly handle dash-delimited node names', function() { - var jQueryVersion = window.jQuery && window.jQuery.fn.jquery.split('.')[0]; - var jQuery3xOrNewer = jQueryVersion && (Number(jQueryVersion) >= 3); + if (isJQuery21()) return; - if (_jqLiteMode || jQuery3xOrNewer) { - var nodeNames = 'thead tbody tfoot colgroup caption tr th td div kung'.split(' '); - var nodeNamesTested = 0; - var nodes, customNodeName; + var nodeNames = 'thead tbody tfoot colgroup caption tr th td div kung'.split(' '); + var nodeNamesTested = 0; + var nodes, customNodeName; - forEach(nodeNames, function(nodeName) { - var customNodeName = nodeName + '-foo'; - var nodes = jqLite('<' + customNodeName + '>Hello, world !'); + forEach(nodeNames, function(nodeName) { + var customNodeName = nodeName + '-foo'; + var nodes = jqLite('<' + customNodeName + '>Hello, world !'); - expect(nodes.length).toBe(1); - expect(nodeName_(nodes)).toBe(customNodeName); - expect(nodes.html()).toBe('Hello, world !'); + expect(nodes.length).toBe(1); + expect(nodeName_(nodes)).toBe(customNodeName); + expect(nodes.html()).toBe('Hello, world !'); - nodeNamesTested++; - }); + nodeNamesTested++; + }); - expect(nodeNamesTested).toBe(10); - } + expect(nodeNamesTested).toBe(10); }); @@ -712,11 +722,9 @@ describe('jqLite', function() { describe('class', function() { it('should properly do with SVG elements', function() { - // This is not working correctly in jQuery prior to v3.0. + // This is not working correctly in jQuery prior to v2.2. // See https://github.com/jquery/jquery/issues/2199 for details. - var jQueryVersion = window.jQuery && window.jQuery.fn.jquery.split('.')[0]; - var jQuery3xOrNewer = jQueryVersion && (Number(jQueryVersion) >= 3); - if (!_jqLiteMode && !jQuery3xOrNewer) return; + if (isJQuery21()) return; var svg = jqLite(''); var rect = svg.children(); @@ -1023,12 +1031,10 @@ describe('jqLite', function() { // See https://github.com/jquery/jquery/issues/2562 for more details. // jqLite will align with jQuery 3.0 behavior in Angular 1.6. var val; - var jQueryVersion = window.jQuery && window.jQuery.fn.jquery.split('.')[0]; - var jQuery3xOrNewer = jQueryVersion && (Number(jQueryVersion) >= 3); - if (!_jqLiteMode && jQuery3xOrNewer) { - val = []; - } else { + if (_jqLiteMode || isJQuery2x()) { val = null; + } else { + val = []; } expect(jqLite( @@ -1070,7 +1076,8 @@ describe('jqLite', function() { describe('on', function() { it('should bind to window on hashchange', function() { - if (jqLite.fn) return; // don't run in jQuery + if (!_jqLiteMode) return; // don't run in jQuery + var eventFn; var window = { document: {}, @@ -1260,7 +1267,7 @@ describe('jqLite', function() { }); it('should fire mouseenter when coming from outside the browser window', function() { - if (window.jQuery) return; + if (!_jqLiteMode) return; setup('
root

parentchild

', 'p', 'span'); @@ -1279,7 +1286,7 @@ describe('jqLite', function() { }); it('should fire the mousenter on SVG elements', function() { - if (window.jQuery) return; + if (!_jqLiteMode) return; setup( '
' + @@ -1301,29 +1308,28 @@ describe('jqLite', function() { }); }); - // Only run this test for jqLite and not normal jQuery - if (_jqLiteMode) { - it('should throw an error if eventData or a selector is passed', function() { - var elm = jqLite(a), - anObj = {}, - aString = '', - aValue = 45, - callback = function() {}; + it('should throw an error if eventData or a selector is passed', function() { + if (!_jqLiteMode) return; - expect(function() { - elm.on('click', anObj, callback); - }).toThrowMinErr('jqLite', 'onargs'); + var elm = jqLite(a), + anObj = {}, + aString = '', + aValue = 45, + callback = function() {}; - expect(function() { - elm.on('click', null, aString, callback); - }).toThrowMinErr('jqLite', 'onargs'); + expect(function() { + elm.on('click', anObj, callback); + }).toThrowMinErr('jqLite', 'onargs'); - expect(function() { - elm.on('click', aValue, callback); - }).toThrowMinErr('jqLite', 'onargs'); + expect(function() { + elm.on('click', null, aString, callback); + }).toThrowMinErr('jqLite', 'onargs'); - }); - } + expect(function() { + elm.on('click', aValue, callback); + }).toThrowMinErr('jqLite', 'onargs'); + + }); }); @@ -1554,11 +1560,6 @@ describe('jqLite', function() { describe('native listener deregistration', function() { - var jQueryVersionString = window.jQuery && window.jQuery.fn.jquery; - var jQueryMajor = jQueryVersionString && Number(jQueryVersionString.split('.')[0]); - var jQueryMinor = jQueryVersionString && Number(jQueryVersionString.split('.')[1]); - var jQuery21 = jQueryMajor === 2 && jQueryMinor === 1; - it('should deregister the native listener when all jqLite listeners for given type are gone ' + 'after off("eventName", listener) call', function() { var aElem = jqLite(a); @@ -1571,7 +1572,7 @@ describe('jqLite', function() { // jQuery <2.2 passes the non-needed `false` useCapture parameter. // See https://github.com/jquery/jquery/issues/2199 for details. - if (jQuery21) { + if (isJQuery21()) { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function), false); } else { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function)); @@ -1580,7 +1581,7 @@ describe('jqLite', function() { expect(removeEventListenerSpy).not.toHaveBeenCalled(); aElem.off('click', jqLiteListener); - if (jQuery21) { + if (isJQuery21()) { expect(removeEventListenerSpy).toHaveBeenCalledOnceWith('click', nativeListenerFn, false); } else { expect(removeEventListenerSpy).toHaveBeenCalledOnceWith('click', nativeListenerFn); @@ -1596,7 +1597,7 @@ describe('jqLite', function() { var nativeListenerFn; aElem.on('click', function() {}); - if (jQuery21) { + if (isJQuery21()) { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function), false); } else { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function)); @@ -1605,7 +1606,7 @@ describe('jqLite', function() { expect(removeEventListenerSpy).not.toHaveBeenCalled(); aElem.off('click'); - if (jQuery21) { + if (isJQuery21()) { expect(removeEventListenerSpy).toHaveBeenCalledOnceWith('click', nativeListenerFn, false); } else { expect(removeEventListenerSpy).toHaveBeenCalledOnceWith('click', nativeListenerFn); @@ -1621,7 +1622,7 @@ describe('jqLite', function() { var nativeListenerFn; aElem.on('click', function() {}); - if (jQuery21) { + if (isJQuery21()) { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function), false); } else { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function)); @@ -1630,7 +1631,7 @@ describe('jqLite', function() { addEventListenerSpy.calls.reset(); aElem.on('dblclick', function() {}); - if (jQuery21) { + if (isJQuery21()) { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('dblclick', nativeListenerFn, false); } else { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('dblclick', nativeListenerFn); @@ -1640,7 +1641,7 @@ describe('jqLite', function() { aElem.off('click dblclick'); - if (jQuery21) { + if (isJQuery21()) { expect(removeEventListenerSpy).toHaveBeenCalledWith('click', nativeListenerFn, false); expect(removeEventListenerSpy).toHaveBeenCalledWith('dblclick', nativeListenerFn, false); } else { @@ -1659,7 +1660,7 @@ describe('jqLite', function() { var nativeListenerFn; aElem.on('click', function() {}); - if (jQuery21) { + if (isJQuery21()) { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function), false); } else { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('click', jasmine.any(Function)); @@ -1668,7 +1669,7 @@ describe('jqLite', function() { addEventListenerSpy.calls.reset(); aElem.on('dblclick', function() {}); - if (jQuery21) { + if (isJQuery21()) { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('dblclick', nativeListenerFn, false); } else { expect(addEventListenerSpy).toHaveBeenCalledOnceWith('dblclick', nativeListenerFn); @@ -1676,7 +1677,7 @@ describe('jqLite', function() { aElem.off(); - if (jQuery21) { + if (isJQuery21()) { expect(removeEventListenerSpy).toHaveBeenCalledWith('click', nativeListenerFn, false); expect(removeEventListenerSpy).toHaveBeenCalledWith('dblclick', nativeListenerFn, false); } else { @@ -1688,16 +1689,15 @@ describe('jqLite', function() { }); - // Only run this test for jqLite and not normal jQuery - if (_jqLiteMode) { - it('should throw an error if a selector is passed', function() { - var aElem = jqLite(a); - aElem.on('click', noop); - expect(function() { - aElem.off('click', noop, '.test'); - }).toThrowError(/\[jqLite:offargs\]/); - }); - } + it('should throw an error if a selector is passed', function() { + if (!_jqLiteMode) return; + + var aElem = jqLite(a); + aElem.on('click', noop); + expect(function() { + aElem.off('click', noop, '.test'); + }).toThrowError(/\[jqLite:offargs\]/); + }); }); describe('one', function() { From dbb8483b4d6f7c133ac96b700a60fc26f52b6839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Wed, 7 Sep 2016 12:03:07 +0200 Subject: [PATCH 2/4] refactor(matchers): add the toEqualOneOf matcher --- test/helpers/matchers.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/test/helpers/matchers.js b/test/helpers/matchers.js index 79b02bbbb23a..9161e612c0ee 100644 --- a/test/helpers/matchers.js +++ b/test/helpers/matchers.js @@ -32,6 +32,12 @@ beforeEach(function() { }; } + function DOMTester(a, b) { + if (a && b && a.nodeType > 0 && b.nodeType > 0) { + return a === b; + } + } + function isNgElementHidden(element) { // we need to check element.getAttribute for SVG nodes var hidden = true; @@ -111,12 +117,19 @@ beforeEach(function() { }; } }; + }, - function DOMTester(a, b) { - if (a && b && a.nodeType > 0 && b.nodeType > 0) { - return a === b; + toEqualOneOf: function(util) { + return { + compare: function(actual) { + var expectedArgs = Array.prototype.slice.call(arguments, 1); + return { + pass: expectedArgs.some(function(expected) { + return util.equals(actual, expected, [DOMTester]); + }) + }; } - } + }; }, toEqualData: function() { From 121f64936e82c92c6ec055b07be7511cc1c2834a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Wed, 7 Sep 2016 12:09:43 +0200 Subject: [PATCH 3/4] refactor(jqLite): use the toEqualOneOf matcher in jqLite tests --- test/jqLiteSpec.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 48be3ed8199a..3b51e17f2509 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1026,22 +1026,13 @@ describe('jqLite', function() { '' + '').val()).toEqual(['test 1']); - // In jQuery >= 3.0 .val() on select[multiple] with no selected options returns an - // empty array, not null. - // See https://github.com/jquery/jquery/issues/2562 for more details. - // jqLite will align with jQuery 3.0 behavior in Angular 1.6. - var val; - if (_jqLiteMode || isJQuery2x()) { - val = null; - } else { - val = []; - } - + // In jQuery < 3.0 .val() on select[multiple] with no selected options returns an + // null instead of an empty array. expect(jqLite( '').val()).toEqual(val); + '').val()).toEqualOneOf(null, []); }); }); From d882fde2e532216e7cf424495db1ccb5be1789f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Wed, 7 Sep 2016 12:13:00 +0200 Subject: [PATCH 4/4] feat(jqLite): return [] for .val() on JavaScript: var value = $element.val(); if (value) { /* do something */ } After: HTML: JavaScript: var value = $element.val(); if (value.length > 0) { /* do something */ } --- src/jqLite.js | 2 +- test/jqLiteSpec.js | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/jqLite.js b/src/jqLite.js index e4ad42f86932..1d199dee46d4 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -699,7 +699,7 @@ forEach({ result.push(option.value || option.text); } }); - return result.length === 0 ? null : result; + return result; } return element.value; } diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 3b51e17f2509..b00703c9bc04 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1034,6 +1034,31 @@ describe('jqLite', function() { '' + '').val()).toEqualOneOf(null, []); }); + + it('should get an empty array from a multi select if no elements are chosen', function() { + // In jQuery < 3.0 .val() on select[multiple] with no selected options returns an + // null instead of an empty array. + // See https://github.com/jquery/jquery/issues/2562 for more details. + if (isJQuery2x()) return; + + expect(jqLite( + '').val()).toEqual([]); + + expect(jqLite( + '').val()).toEqual([]); + }); });