Skip to content

Commit

Permalink
fix(core): CHECKOUT-4455 Provide fallback for browsers that don't sup…
Browse files Browse the repository at this point in the history
…port `preload` attribute
  • Loading branch information
davidchin committed Oct 3, 2019
1 parent d8e6e4b commit 0fc52e7
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 76 deletions.
62 changes: 58 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"validate-commits": "validate-commits"
},
"dependencies": {
"@bigcommerce/request-sender": "^0.3.0",
"tslib": "^1.10.0"
},
"devDependencies": {
Expand Down
43 changes: 43 additions & 0 deletions src/browser-support.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import BrowserSupport from './browser-support';

describe('BrowserSupport', () => {
let link: HTMLLinkElement;
let support: BrowserSupport;

beforeEach(() => {
const createElement = document.createElement.bind(document);

link = {
relList: {
supports: jest.fn(() => true),
},
} as unknown as HTMLLinkElement;

jest.spyOn(document, 'createElement')
.mockImplementation(type => {
return type === 'link' ? link : createElement(type);
});

support = new BrowserSupport();
});

it('returns true if able to support rel type', () => {
expect(support.canSupportRel('preload'))
.toEqual(true);
});

it('returns false if unable to support rel type', () => {
jest.spyOn(link.relList, 'supports')
.mockReturnValue(false);

expect(support.canSupportRel('preload'))
.toEqual(false);
});

it('returns false if `relList` is not supported', () => {
link = {} as unknown as HTMLLinkElement;

expect(support.canSupportRel('preload'))
.toEqual(false);
});
});
11 changes: 11 additions & 0 deletions src/browser-support.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default class BrowserSupport {
canSupportRel(rel: string): boolean {
const link = document.createElement('link');

return !!(
link.relList &&
link.relList.supports &&
link.relList.supports(rel)
);
}
}
8 changes: 7 additions & 1 deletion src/create-script-loader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { createRequestSender } from '@bigcommerce/request-sender';

import BrowserSupport from './browser-support';
import ScriptLoader from './script-loader';

export default function createScriptLoader(): ScriptLoader {
return new ScriptLoader();
return new ScriptLoader(
new BrowserSupport(),
createRequestSender()
);
}
8 changes: 7 additions & 1 deletion src/create-stylesheet-loader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { createRequestSender } from '@bigcommerce/request-sender';

import BrowserSupport from './browser-support';
import StylesheetLoader from './stylesheet-loader';

export default function createStylesheetLoader(): StylesheetLoader {
return new StylesheetLoader();
return new StylesheetLoader(
new BrowserSupport(),
createRequestSender()
);
}
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { default as ScriptLoader } from './script-loader';
export { default as ScriptLoader, LoadScriptOptions, PreloadScriptOptions } from './script-loader';
export { default as createScriptLoader } from './create-script-loader';
export { default as getScriptLoader } from './get-script-loader';

export { default as StylesheetLoader } from './stylesheet-loader';
export { default as StylesheetLoader, LoadStylesheetOptions, PreloadStylesheetOptions } from './stylesheet-loader';
export { default as createStylesheetLoader } from './create-stylesheet-loader';
export { default as getStylesheetLoader } from './get-stylesheet-loader';
46 changes: 38 additions & 8 deletions src/script-loader.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import { createRequestSender, RequestSender } from '@bigcommerce/request-sender';

import BrowserSupport from './browser-support';
import ScriptLoader from './script-loader';

describe('ScriptLoader', () => {
let browserSupport: BrowserSupport;
let loader: ScriptLoader;
let requestSender: RequestSender;

beforeEach(() => {
loader = new ScriptLoader();
browserSupport = new BrowserSupport();
requestSender = createRequestSender();

jest.spyOn(browserSupport, 'canSupportRel')
.mockReturnValue(true);

jest.spyOn(requestSender, 'get')
.mockReturnValue(Promise.resolve({}));

loader = new ScriptLoader(
browserSupport,
requestSender
);
});

afterEach(() => {
Expand Down Expand Up @@ -36,6 +53,13 @@ describe('ScriptLoader', () => {
.toEqual('https://code.jquery.com/jquery-3.2.1.min.js');
});

it('loads script synchronously by default', async () => {
await loader.loadScript('https://code.jquery.com/jquery-3.2.1.min.js');

expect(script.async)
.toEqual(false);
});

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

Expand Down Expand Up @@ -111,13 +135,6 @@ describe('ScriptLoader', () => {
];
});

it('preloads scripts in parallel', async () => {
await loader.loadScripts(urls);

expect(loader.preloadScripts)
.toHaveBeenCalledWith(urls);
});

it('loads preloaded scripts in sequence', async () => {
jest.spyOn(loader, 'loadScript')
.mockReturnValue(Promise.resolve(new Event('readystatechange')));
Expand Down Expand Up @@ -195,6 +212,19 @@ describe('ScriptLoader', () => {
.toEqual('https://cdn.foobar.com/foo.min.js');
});

it('falls back to using XHR if browser does not support preload', async () => {
jest.spyOn(browserSupport, 'canSupportRel')
.mockImplementation(rel => rel === 'preload' ? false : true);

await loader.preloadScript('https://cdn.foobar.com/foo.min.js');

expect(requestSender.get)
.toHaveBeenCalledWith('https://cdn.foobar.com/foo.min.js', {
credentials: false,
headers: { Accept: 'application/javascript' },
});
});

it('resolves promise if script is preloaded', async () => {
const output = await loader.preloadScript('https://cdn.foobar.com/foo.min.js');

Expand Down
Loading

0 comments on commit 0fc52e7

Please sign in to comment.