diff --git a/src/jqLite.js b/src/jqLite.js index 78fc1655fa27..6539aaabfbf8 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -342,7 +342,8 @@ forEach({ append: function(element, node) { forEach(new JQLite(node), function(child){ - element.appendChild(child); + if (element.nodeType === 1) + element.appendChild(child); }); }, @@ -371,8 +372,8 @@ forEach({ }, parent: function(element) { - // in IE it returns undefined, but we need differentiate it from functions which have no return - return element.parentNode || null; + var parent = element.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; }, next: function(element) { diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 346017f1cf5a..3486fbbb872d 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1,12 +1,13 @@ describe('jqLite', function(){ - var scope; - var a, b, c; + var scope, a, b, c; + beforeEach(function(){ a = jqLite('
A
')[0]; b = jqLite('
B
')[0]; c = jqLite('
C
')[0]; }); + beforeEach(function(){ scope = angular.scope(); this.addMatchers({ @@ -28,12 +29,14 @@ describe('jqLite', function(){ }); }); + afterEach(function(){ dealoc(a); dealoc(b); dealoc(c); }); + describe('construction', function(){ it('should allow construction with text node', function(){ var text = a.firstChild; @@ -41,14 +44,38 @@ describe('jqLite', function(){ expect(selected.length).toEqual(1); expect(selected[0]).toEqual(text); }); + + it('should allow construction with html', function(){ var nodes = jqLite('
1
2'); expect(nodes.length).toEqual(2); expect(nodes[0].innerHTML).toEqual('1'); expect(nodes[1].innerHTML).toEqual('2'); }); + + + it('should allow creation of comment tags', function() { + var nodes = jqLite(''); + expect(nodes.length).toBe(1); + expect(nodes[0].nodeType).toBe(8); + }); + + + it('should allow creation of script tags', function() { + var nodes = jqLite(''); + expect(nodes.length).toBe(1); + expect(nodes[0].tagName.toUpperCase()).toBe('SCRIPT'); + }); + + + it('should wrap document fragment', function() { + var fragment = jqLite(document.createDocumentFragment()); + expect(fragment.length).toBe(1); + expect(fragment[0].nodeType).toBe(11); + }); }); + describe('scope', function() { it('should retrieve scope attached to the current element', function() { var element = jqLite('foo'); @@ -57,6 +84,7 @@ describe('jqLite', function(){ dealoc(element); }); + it('should walk up the dom to find scope', function() { var element = jqLite(''); var deepChild = jqLite(element[0].getElementsByTagName('b')[0]); @@ -65,6 +93,7 @@ describe('jqLite', function(){ dealoc(element); }); + it('should return undefined when no scope was found', function() { var element = jqLite(''); var deepChild = jqLite(element[0].getElementsByTagName('b')[0]); @@ -73,6 +102,7 @@ describe('jqLite', function(){ }); }); + describe('data', function(){ it('should set and get ande remove data', function(){ var selected = jqLite([a, b, c]); @@ -96,6 +126,7 @@ describe('jqLite', function(){ }); }); + describe('attr', function(){ it('shoul read wirite and remove attr', function(){ var selector = jqLite([a, b]); @@ -117,13 +148,18 @@ describe('jqLite', function(){ expect(jqLite(b).attr('prop')).toBeFalsy(); }); }); + + describe('class', function(){ + describe('hasClass', function(){ it('should check class', function(){ var selector = jqLite([a, b]); expect(selector.hasClass('abc')).toEqual(false); }); }); + + describe('addClass', function(){ it('should allow adding of class', function(){ var selector = jqLite([a, b]); @@ -132,6 +168,8 @@ describe('jqLite', function(){ expect(jqLite(b).hasClass('abc')).toEqual(true); }); }); + + describe('toggleClass', function(){ it('should allow toggling of class', function(){ var selector = jqLite([a, b]); @@ -153,6 +191,8 @@ describe('jqLite', function(){ }); }); + + describe('removeClass', function(){ it('should allow removal of class', function(){ var selector = jqLite([a, b]); @@ -163,6 +203,8 @@ describe('jqLite', function(){ }); }); }); + + describe('css', function(){ it('should set and read css', function(){ var selector = jqLite([a, b]); @@ -184,12 +226,15 @@ describe('jqLite', function(){ expect(jqLite(b).css('prop')).toBeFalsy(); }); }); + + describe('text', function(){ it('should return null on empty', function(){ expect(jqLite().length).toEqual(0); expect(jqLite().text()).toEqual(''); }); + it('should read/write value', function(){ var element = jqLite('
abc
'); expect(element.length).toEqual(1); @@ -199,6 +244,8 @@ describe('jqLite', function(){ expect(element.text()).toEqual('xyz'); }); }); + + describe('val', function(){ it('should read, write value', function(){ var input = jqLite(''); @@ -207,12 +254,15 @@ describe('jqLite', function(){ expect(input.val()).toEqual('abc'); }); }); + + describe('html', function(){ it('should return null on empty', function(){ expect(jqLite().length).toEqual(0); expect(jqLite().html()).toEqual(null); }); + it('should read/write value', function(){ var element = jqLite('
abc
'); expect(element.length).toEqual(1); @@ -223,6 +273,7 @@ describe('jqLite', function(){ }); }); + describe('bind', function(){ it('should bind to window on hashchange', function(){ if (jqLite.fn) return; // don't run in jQuery @@ -253,6 +304,7 @@ describe('jqLite', function(){ dealoc(jWindow); }); + it('should bind to all elements and return functions', function(){ var selected = jqLite([a, b]); var log = ''; @@ -266,6 +318,7 @@ describe('jqLite', function(){ }); }); + describe('replaceWith', function(){ it('should replaceWith', function(){ var root = jqLite('
').html('before-
after'); @@ -273,6 +326,8 @@ describe('jqLite', function(){ expect(div.replaceWith('span-bold-')).toEqual(div); expect(root.text()).toEqual('before-span-bold-after'); }); + + it('should replaceWith text', function(){ var root = jqLite('
').html('before-
after'); var div = root.find('div'); @@ -280,6 +335,8 @@ describe('jqLite', function(){ expect(root.text()).toEqual('before-text-after'); }); }); + + describe('children', function(){ it('should select non-text children', function(){ var root = jqLite('
').html('before-
after-'); @@ -288,6 +345,8 @@ describe('jqLite', function(){ expect(root.children()).toJqEqual([div, span]); }); }); + + describe('append', function(){ it('should append', function(){ var root = jqLite('
'); @@ -299,7 +358,14 @@ describe('jqLite', function(){ expect(root.append('text')).toEqual(root); expect(root.html()).toEqual('text'); }); + it('should not append anything if parent node is not of type element', function() { + var root = jqLite(document.createDocumentFragment()); + expect(root.append('

foo

')).toBe(root); + expect(root.children().length).toBe(0); + }); }); + + describe('remove', function(){ it('should remove', function(){ var root = jqLite('
abc
'); @@ -308,6 +374,8 @@ describe('jqLite', function(){ expect(root.html()).toEqual(''); }); }); + + describe('after', function(){ it('should after', function(){ var root = jqLite('
'); @@ -315,6 +383,8 @@ describe('jqLite', function(){ expect(span.after('')).toEqual(span); expect(root.html().toLowerCase()).toEqual(''); }); + + it('should allow taking text', function(){ var root = jqLite('
'); var span = root.find('span'); @@ -322,13 +392,40 @@ describe('jqLite', function(){ expect(root.html().toLowerCase()).toEqual('abc'); }); }); + + describe('parent', function(){ + it('should return parent or an empty set when no parent', function(){ + var parent = jqLite('

abc

'), + child = parent.find('p'); + + expect(parent.parent()).toBeTruthy(); + expect(parent.parent().length).toEqual(0); + + expect(child.parent().length).toBe(1); + expect(child.parent()[0]).toBe(parent[0]); + }); + + it('should return empty set when no parent', function(){ var element = jqLite('
abc
'); expect(element.parent()).toBeTruthy(); expect(element.parent().length).toEqual(0); }); + + + it('should return empty jqLite object when parent is a document fragment', function() { + //this is quite unfortunate but jQuery 1.5.1 behaves this way + var fragment = document.createDocumentFragment(), + child = jqLite('

foo

'); + + fragment.appendChild(child[0]); + expect(child[0].parentNode).toBe(fragment); + expect(child.parent().length).toBe(0); + }); }); + + describe('next', function(){ it('should return next sibling', function(){ var element = jqLite('
bi
'); @@ -337,6 +434,8 @@ describe('jqLite', function(){ expect(b.next()).toJqEqual([i]); }); }); + + describe('find', function(){ it('should find child by name', function(){ var root = jqLite('
text
'); @@ -345,5 +444,4 @@ describe('jqLite', function(){ expect(innerDiv.html()).toEqual('text'); }); }); - });