| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-01 11:26:29 -08:00
										 |  |  | import {camelToDashCase, createCustomEvent, isElement, isFunction, kebabToCamelCase, matchesSelector, scheduler, strictEquals} from '../src/utils'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | describe('utils', () => { | 
					
						
							|  |  |  |   describe('scheduler', () => { | 
					
						
							|  |  |  |     describe('schedule()', () => { | 
					
						
							|  |  |  |       let setTimeoutSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let clearTimeoutSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         setTimeoutSpy = spyOn(window, 'setTimeout').and.returnValue(42); | 
					
						
							|  |  |  |         clearTimeoutSpy = spyOn(window, 'clearTimeout'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should delegate to `window.setTimeout()`', () => { | 
					
						
							|  |  |  |         const cb = () => null; | 
					
						
							|  |  |  |         const delay = 1337; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scheduler.schedule(cb, delay); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(setTimeoutSpy).toHaveBeenCalledWith(cb, delay); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should return a function for cancelling the scheduled job', () => { | 
					
						
							|  |  |  |         const cancelFn = scheduler.schedule(() => null, 0); | 
					
						
							|  |  |  |         expect(clearTimeoutSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         cancelFn(); | 
					
						
							|  |  |  |         expect(clearTimeoutSpy).toHaveBeenCalledWith(42); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('scheduleBeforeRender()', () => { | 
					
						
							|  |  |  |       if (typeof window.requestAnimationFrame === 'undefined') { | 
					
						
							|  |  |  |         const mockCancelFn = () => undefined; | 
					
						
							|  |  |  |         let scheduleSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         beforeEach(() => scheduleSpy = spyOn(scheduler, 'schedule').and.returnValue(mockCancelFn)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should delegate to `scheduler.schedule()`', () => { | 
					
						
							|  |  |  |           const cb = () => null; | 
					
						
							|  |  |  |           expect(scheduler.scheduleBeforeRender(cb)).toBe(mockCancelFn); | 
					
						
							|  |  |  |           expect(scheduleSpy).toHaveBeenCalledWith(cb, 16); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         let requestAnimationFrameSpy: jasmine.Spy; | 
					
						
							|  |  |  |         let cancelAnimationFrameSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         beforeEach(() => { | 
					
						
							|  |  |  |           requestAnimationFrameSpy = spyOn(window, 'requestAnimationFrame').and.returnValue(42); | 
					
						
							|  |  |  |           cancelAnimationFrameSpy = spyOn(window, 'cancelAnimationFrame'); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should delegate to `window.requestAnimationFrame()`', () => { | 
					
						
							|  |  |  |           const cb = () => null; | 
					
						
							|  |  |  |           scheduler.scheduleBeforeRender(cb); | 
					
						
							|  |  |  |           expect(requestAnimationFrameSpy).toHaveBeenCalledWith(cb); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should return a function for cancelling the scheduled job', () => { | 
					
						
							|  |  |  |           const cancelFn = scheduler.scheduleBeforeRender(() => null); | 
					
						
							|  |  |  |           expect(cancelAnimationFrameSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           cancelFn(); | 
					
						
							|  |  |  |           expect(cancelAnimationFrameSpy).toHaveBeenCalledWith(42); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('camelToKebabCase()', () => { | 
					
						
							|  |  |  |     it('should convert camel-case to kebab-case', () => { | 
					
						
							| 
									
										
										
										
											2018-03-01 11:26:29 -08:00
										 |  |  |       expect(camelToDashCase('fooBarBazQux')).toBe('foo-bar-baz-qux'); | 
					
						
							|  |  |  |       expect(camelToDashCase('foo1Bar2Baz3Qux4')).toBe('foo1-bar2-baz3-qux4'); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should keep existing dashes', | 
					
						
							| 
									
										
										
										
											2018-03-01 11:26:29 -08:00
										 |  |  |        () => { expect(camelToDashCase('fooBar-baz-Qux')).toBe('foo-bar-baz--qux'); }); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('createCustomEvent()', () => { | 
					
						
							|  |  |  |     it('should create a custom event (with appropriate properties)', () => { | 
					
						
							|  |  |  |       const value = {bar: 'baz'}; | 
					
						
							|  |  |  |       const event = createCustomEvent(document, 'foo', value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(event).toEqual(jasmine.any(CustomEvent)); | 
					
						
							|  |  |  |       expect(event).toEqual(jasmine.any(Event)); | 
					
						
							|  |  |  |       expect(event.type).toBe('foo'); | 
					
						
							|  |  |  |       expect(event.bubbles).toBe(false); | 
					
						
							|  |  |  |       expect(event.cancelable).toBe(false); | 
					
						
							|  |  |  |       expect(event.detail).toEqual(value); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('isElement()', () => { | 
					
						
							|  |  |  |     it('should return true for Element nodes', () => { | 
					
						
							|  |  |  |       const elems = [ | 
					
						
							|  |  |  |         document.body, | 
					
						
							|  |  |  |         document.createElement('div'), | 
					
						
							|  |  |  |         document.createElement('option'), | 
					
						
							|  |  |  |         document.documentElement, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       elems.forEach(n => expect(isElement(n)).toBe(true)); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return false for non-Element nodes', () => { | 
					
						
							|  |  |  |       const nonElems = [ | 
					
						
							|  |  |  |         document, | 
					
						
							|  |  |  |         document.createAttribute('foo'), | 
					
						
							|  |  |  |         document.createDocumentFragment(), | 
					
						
							|  |  |  |         document.createComment('bar'), | 
					
						
							|  |  |  |         document.createTextNode('baz'), | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       nonElems.forEach(n => expect(isElement(n)).toBe(false)); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('isFunction()', () => { | 
					
						
							|  |  |  |     it('should return true for functions', () => { | 
					
						
							|  |  |  |       const obj = {foo: function() {}, bar: () => null, baz() {}}; | 
					
						
							|  |  |  |       const fns = [ | 
					
						
							|  |  |  |         function(){}, | 
					
						
							|  |  |  |         () => null, | 
					
						
							|  |  |  |         obj.foo, | 
					
						
							|  |  |  |         obj.bar, | 
					
						
							|  |  |  |         obj.baz, | 
					
						
							|  |  |  |         Function, | 
					
						
							|  |  |  |         Date, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fns.forEach(v => expect(isFunction(v)).toBe(true)); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return false for non-functions', () => { | 
					
						
							|  |  |  |       const nonFns = [ | 
					
						
							|  |  |  |         undefined, | 
					
						
							|  |  |  |         null, | 
					
						
							|  |  |  |         true, | 
					
						
							|  |  |  |         42, | 
					
						
							|  |  |  |         {}, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       nonFns.forEach(v => expect(isFunction(v)).toBe(false)); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('kebabToCamelCase()', () => { | 
					
						
							|  |  |  |     it('should convert camel-case to kebab-case', () => { | 
					
						
							|  |  |  |       expect(kebabToCamelCase('foo-bar-baz-qux')).toBe('fooBarBazQux'); | 
					
						
							|  |  |  |       expect(kebabToCamelCase('foo1-bar2-baz3-qux4')).toBe('foo1Bar2Baz3Qux4'); | 
					
						
							|  |  |  |       expect(kebabToCamelCase('foo-1-bar-2-baz-3-qux-4')).toBe('foo1Bar2Baz3Qux4'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should keep uppercase letters', () => { | 
					
						
							|  |  |  |       expect(kebabToCamelCase('foo-barBaz-Qux')).toBe('fooBarBaz-Qux'); | 
					
						
							|  |  |  |       expect(kebabToCamelCase('foo-barBaz--qux')).toBe('fooBarBaz-Qux'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('matchesSelector()', () => { | 
					
						
							|  |  |  |     let li: HTMLLIElement; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       const div = document.createElement('div'); | 
					
						
							|  |  |  |       div.innerHTML = `
 | 
					
						
							|  |  |  |         <div class="bar" id="barDiv"> | 
					
						
							|  |  |  |           <span class="baz"></span> | 
					
						
							|  |  |  |           <ul class="baz" id="bazUl"> | 
					
						
							|  |  |  |             <li class="qux" id="quxLi"></li> | 
					
						
							|  |  |  |           </ul> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       li = div.querySelector('li') !; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return whether the element matches the selector', () => { | 
					
						
							|  |  |  |       expect(matchesSelector(li, 'li')).toBe(true); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.qux')).toBe(true); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '#quxLi')).toBe(true); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.qux#quxLi:not(.quux)')).toBe(true); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.bar > #bazUl > li')).toBe(true); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.bar .baz ~ .baz li')).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(matchesSelector(li, 'ol')).toBe(false); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.quux')).toBe(false); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '#quuxOl')).toBe(false); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.qux#quxLi:not(li)')).toBe(false); | 
					
						
							|  |  |  |       expect(matchesSelector(li, '.bar > #bazUl > .quxLi')).toBe(false); | 
					
						
							|  |  |  |       expect(matchesSelector(li, 'div span ul li')).toBe(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('strictEquals()', () => { | 
					
						
							|  |  |  |     it('should perform strict equality check', () => { | 
					
						
							|  |  |  |       const values = [ | 
					
						
							|  |  |  |         undefined, | 
					
						
							|  |  |  |         null, | 
					
						
							|  |  |  |         true, | 
					
						
							|  |  |  |         false, | 
					
						
							|  |  |  |         42, | 
					
						
							|  |  |  |         '42', | 
					
						
							|  |  |  |         () => undefined, | 
					
						
							|  |  |  |         () => undefined, | 
					
						
							|  |  |  |         {}, | 
					
						
							|  |  |  |         {}, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       values.forEach((v1, i) => { | 
					
						
							|  |  |  |         values.forEach((v2, j) => { expect(strictEquals(v1, v2)).toBe(i === j); }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should consider two `NaN` values equals', () => { | 
					
						
							|  |  |  |       expect(strictEquals(NaN, NaN)).toBe(true); | 
					
						
							|  |  |  |       expect(strictEquals(NaN, 'foo')).toBe(false); | 
					
						
							|  |  |  |       expect(strictEquals(NaN, 42)).toBe(false); | 
					
						
							|  |  |  |       expect(strictEquals(NaN, null)).toBe(false); | 
					
						
							|  |  |  |       expect(strictEquals(NaN, undefined)).toBe(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); |