Skip to content

Commit

Permalink
feat(core): CHECKOUT-2739 Add ScriptLoader responsible for loading …
Browse files Browse the repository at this point in the history
…JS files asynchronously
  • Loading branch information
davidchin committed Feb 26, 2018
1 parent d06a228 commit 06620da
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/create-script-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ScriptLoader from './script-loader';

export default function createScriptLoader(): ScriptLoader {
return new ScriptLoader(document);
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as ScriptLoader } from './script-loader';
export { default as createScriptLoader } from './create-script-loader';
46 changes: 46 additions & 0 deletions src/script-loader.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import ScriptLoader from './script-loader';

describe('ScriptLoader', () => {
let loader: ScriptLoader;
let script: HTMLScriptElement;

beforeEach(() => {
script = document.createElement('script');

jest.spyOn(document, 'createElement').mockImplementation(() => script);
jest.spyOn(document.body, 'appendChild').mockImplementation((element) =>
element.onreadystatechange(new Event('readystatechange'))
);

loader = new ScriptLoader(document);
});

afterEach(() => {
jest.restoreAllMocks();
});

it('attaches script tag to document', async () => {
await loader.loadScript('https://code.jquery.com/jquery-3.2.1.min.js');

expect(document.body.appendChild).toHaveBeenCalledWith(script);
expect(script.src).toEqual('https://code.jquery.com/jquery-3.2.1.min.js');
});

it('resolves promise if script is loaded', async () => {
const output = await loader.loadScript('https://code.jquery.com/jquery-3.2.1.min.js');

expect(output).toBeInstanceOf(Event);
});

it('rejects promise if script is not loaded', async () => {
jest.spyOn(document.body, 'appendChild').mockImplementation(
(element) => element.onerror(new Event('error'))
);

try {
await loader.loadScript('https://code.jquery.com/jquery-3.2.1.min.js');
} catch (output) {
expect(output).toBeInstanceOf(Event);
}
});
});
24 changes: 24 additions & 0 deletions src/script-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default class ScriptLoader {
constructor(
private _document: Document
) {}

loadScript(src: string): Promise<Event> {
return new Promise((resolve, reject) => {
const script = this._document.createElement('script') as LegacyHTMLScriptElement;

script.onload = (event) => resolve(event);
script.onreadystatechange = (event) => resolve(event);
script.onerror = (event) => reject(event);
script.async = true;
script.src = src;

this._document.body.appendChild(script);
});
}
}

interface LegacyHTMLScriptElement extends HTMLScriptElement {
// `onreadystatechange` is needed to support legacy IE
onreadystatechange: (this: HTMLElement, event: Event) => any;
}

0 comments on commit 06620da

Please sign in to comment.