mirror of https://github.com/abpframework/abp.git
3 changed files with 160 additions and 0 deletions
@ -0,0 +1,105 @@ |
|||
import { DomStrategy, DOM_STRATEGY } from '../strategies'; |
|||
import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy'; |
|||
import { uuid } from '../utils'; |
|||
import { fromLazyLoad } from '../utils/lazy-load-utils'; |
|||
|
|||
describe('Lazy Load Utils', () => { |
|||
describe('#fromLazyLoad', () => { |
|||
afterEach(() => { |
|||
jest.clearAllMocks(); |
|||
}); |
|||
|
|||
it('should append to head by default', () => { |
|||
const element = document.createElement('link'); |
|||
const spy = jest.spyOn(document.head, 'insertAdjacentElement'); |
|||
|
|||
fromLazyLoad(element); |
|||
expect(spy).toHaveBeenCalledWith('beforeend', element); |
|||
}); |
|||
|
|||
it('should allow setting a dom strategy', () => { |
|||
const element = document.createElement('link'); |
|||
const spy = jest.spyOn(document.head, 'insertAdjacentElement'); |
|||
|
|||
fromLazyLoad(element, DOM_STRATEGY.PrependToHead()); |
|||
expect(spy).toHaveBeenCalledWith('afterbegin', element); |
|||
}); |
|||
|
|||
it('should set crossorigin to "anonymous" by default', () => { |
|||
const element = document.createElement('link'); |
|||
|
|||
fromLazyLoad(element); |
|||
|
|||
expect(element.crossOrigin).toBe('anonymous'); |
|||
}); |
|||
|
|||
it('should allow setting a crossorigin strategy', () => { |
|||
const element = document.createElement('link'); |
|||
|
|||
const integrity = uuid(); |
|||
|
|||
fromLazyLoad(element, undefined, CROSS_ORIGIN_STRATEGY.UseCredentials(integrity)); |
|||
|
|||
expect(element.crossOrigin).toBe('use-credentials'); |
|||
expect(element.getAttribute('integrity')).toBe(integrity); |
|||
}); |
|||
|
|||
it('should emit error event on fail and clear callbacks', done => { |
|||
const error = new CustomEvent('error'); |
|||
const parentNode = { removeChild: jest.fn() }; |
|||
const element = ({ parentNode } as any) as HTMLLinkElement; |
|||
|
|||
fromLazyLoad( |
|||
element, |
|||
{ |
|||
insertElement(el: HTMLLinkElement) { |
|||
expect(el).toBe(element); |
|||
|
|||
setTimeout(() => { |
|||
el.onerror(error); |
|||
}, 0); |
|||
}, |
|||
} as DomStrategy, |
|||
{ |
|||
setCrossOrigin(el: HTMLLinkElement) {}, |
|||
} as CrossOriginStrategy, |
|||
).subscribe({ |
|||
error: value => { |
|||
expect(value).toBe(error); |
|||
expect(parentNode.removeChild).toHaveBeenCalledWith(element); |
|||
expect(element.onerror).toBeNull(); |
|||
done(); |
|||
}, |
|||
}); |
|||
}); |
|||
|
|||
it('should emit load event on success and clear callbacks', done => { |
|||
const success = new CustomEvent('load'); |
|||
const parentNode = { removeChild: jest.fn() }; |
|||
const element = ({ parentNode } as any) as HTMLLinkElement; |
|||
|
|||
fromLazyLoad( |
|||
element, |
|||
{ |
|||
insertElement(el: HTMLLinkElement) { |
|||
expect(el).toBe(element); |
|||
|
|||
setTimeout(() => { |
|||
el.onload(success); |
|||
}, 0); |
|||
}, |
|||
} as DomStrategy, |
|||
{ |
|||
setCrossOrigin(el: HTMLLinkElement) {}, |
|||
} as CrossOriginStrategy, |
|||
).subscribe({ |
|||
next: value => { |
|||
expect(value).toBe(success); |
|||
expect(parentNode.removeChild).not.toHaveBeenCalled(); |
|||
expect(element.onload).toBeNull(); |
|||
done(); |
|||
}, |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,5 +1,6 @@ |
|||
export * from './common-utils'; |
|||
export * from './generator-utils'; |
|||
export * from './initial-utils'; |
|||
export * from './lazy-load-utils'; |
|||
export * from './route-utils'; |
|||
export * from './rxjs-utils'; |
|||
|
|||
@ -0,0 +1,54 @@ |
|||
import { Observable, Observer } from 'rxjs'; |
|||
import { |
|||
CrossOriginStrategy, |
|||
CROSS_ORIGIN_STRATEGY, |
|||
DomStrategy, |
|||
DOM_STRATEGY, |
|||
} from '../strategies'; |
|||
|
|||
export function fromLazyLoad<T extends Event>( |
|||
element: HTMLScriptElement | HTMLLinkElement, |
|||
domStrategy: DomStrategy = DOM_STRATEGY.AppendToHead(), |
|||
crossOriginStrategy: CrossOriginStrategy = CROSS_ORIGIN_STRATEGY.Anonymous(), |
|||
): Observable<T> { |
|||
crossOriginStrategy.setCrossOrigin(element); |
|||
domStrategy.insertElement(element); |
|||
|
|||
return Observable.create((observer: Observer<Event>) => { |
|||
element.onload = event => { |
|||
clearCallbacks(element); |
|||
observer.next(event); |
|||
observer.complete(); |
|||
}; |
|||
|
|||
const handleError = createErrorHandler(observer, element); |
|||
|
|||
element.onerror = handleError; |
|||
element.onabort = handleError; |
|||
element.onemptied = handleError; |
|||
element.onstalled = handleError; |
|||
element.onsuspend = handleError; |
|||
|
|||
return () => { |
|||
clearCallbacks(element); |
|||
observer.complete(); |
|||
}; |
|||
}); |
|||
} |
|||
|
|||
function createErrorHandler(observer: Observer<Event>, element: HTMLElement) { |
|||
return function(event: Event | string) { |
|||
clearCallbacks(element); |
|||
element.parentNode.removeChild(element); |
|||
observer.error(event); |
|||
}; |
|||
} |
|||
|
|||
function clearCallbacks(element: HTMLElement) { |
|||
element.onload = null; |
|||
element.onerror = null; |
|||
element.onabort = null; |
|||
element.onemptied = null; |
|||
element.onstalled = null; |
|||
element.onsuspend = null; |
|||
} |
|||
Loading…
Reference in new issue