diff options
Diffstat (limited to 'polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.ts')
-rw-r--r-- | polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.ts | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.ts new file mode 100644 index 0000000000..4bfa0eb3bd --- /dev/null +++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.ts @@ -0,0 +1,428 @@ +/** + * @license + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '../../../test/common-test-setup-karma'; +import {PLUGIN_LOADING_TIMEOUT_MS} from './gr-api-utils'; +import {PluginLoader, _testOnly_resetPluginLoader} from './gr-plugin-loader'; +import {resetPlugins, stubBaseUrl} from '../../../test/test-utils'; +import {addListenerForTest, stubRestApi} from '../../../test/test-utils'; +import {PluginApi} from '../../../api/plugin'; +import {SinonFakeTimers} from 'sinon'; +import {Timestamp} from '../../../api/rest-api'; + +suite('gr-plugin-loader tests', () => { + let plugin: PluginApi; + + let url: string; + let pluginLoader: PluginLoader; + let clock: SinonFakeTimers; + let bodyStub: sinon.SinonStub; + + setup(() => { + clock = sinon.useFakeTimers(); + + stubRestApi('getAccount').returns( + Promise.resolve({name: 'Judy Hopps', registered_on: '' as Timestamp}) + ); + stubRestApi('send').returns( + Promise.resolve({...new Response(), status: 200}) + ); + pluginLoader = _testOnly_resetPluginLoader(); + bodyStub = sinon.stub(document.body, 'appendChild'); + url = window.location.origin; + }); + + teardown(() => { + clock.restore(); + resetPlugins(); + }); + + test('reuse plugin for install calls', () => { + window.Gerrit.install( + p => { + plugin = p; + }, + '0.1', + 'http://test.com/plugins/testplugin/static/test.js' + ); + + let otherPlugin; + window.Gerrit.install( + p => { + otherPlugin = p; + }, + '0.1', + 'http://test.com/plugins/testplugin/static/test.js' + ); + assert.strictEqual(plugin, otherPlugin); + }); + + test('versioning', () => { + const callback = sinon.spy(); + window.Gerrit.install(callback, '0.0pre-alpha'); + assert(callback.notCalled); + }); + + test('report pluginsLoaded', async () => { + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + pluginsLoadedStub.reset(); + (window.Gerrit as any)._loadPlugins([]); + await flush(); + assert.isTrue(pluginsLoadedStub.called); + }); + + test('arePluginsLoaded', () => { + assert.isFalse(pluginLoader.arePluginsLoaded()); + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + + pluginLoader.loadPlugins(plugins); + assert.isFalse(pluginLoader.arePluginsLoaded()); + // Timeout on loading plugins + clock.tick(PLUGIN_LOADING_TIMEOUT_MS * 2); + + flush(); + assert.isTrue(pluginLoader.arePluginsLoaded()); + }); + + test('plugins installed successfully', async () => { + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install(() => void 0, undefined, url); + }); + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + pluginLoader.loadPlugins(plugins); + + await flush(); + assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo', 'bar'])); + assert.isTrue(pluginLoader.arePluginsLoaded()); + }); + + test('isPluginEnabled and isPluginLoaded', () => { + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install(() => void 0, undefined, url); + }); + + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + 'bar/static/test.js', + ]; + pluginLoader.loadPlugins(plugins); + assert.isTrue( + plugins.every(plugin => pluginLoader.isPluginEnabled(plugin)) + ); + + flush(); + assert.isTrue(pluginLoader.arePluginsLoaded()); + assert.isTrue(plugins.every(plugin => pluginLoader.isPluginLoaded(plugin))); + }); + + test('plugins installed mixed result, 1 fail 1 succeed', async () => { + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + + const alertStub = sinon.stub(); + addListenerForTest(document, 'show-alert', alertStub); + + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install( + () => { + if (url === plugins[0]) { + throw new Error('failed'); + } + }, + undefined, + url + ); + }); + + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + + pluginLoader.loadPlugins(plugins); + + await flush(); + assert.isTrue(pluginsLoadedStub.calledWithExactly(['bar'])); + assert.isTrue(pluginLoader.arePluginsLoaded()); + assert.isTrue(alertStub.calledOnce); + }); + + test('isPluginEnabled and isPluginLoaded for mixed results', async () => { + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + + const alertStub = sinon.stub(); + addListenerForTest(document, 'show-alert', alertStub); + + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install( + () => { + if (url === plugins[0]) { + throw new Error('failed'); + } + }, + undefined, + url + ); + }); + + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + + pluginLoader.loadPlugins(plugins); + assert.isTrue( + plugins.every(plugin => pluginLoader.isPluginEnabled(plugin)) + ); + + await flush(); + assert.isTrue(pluginsLoadedStub.calledWithExactly(['bar'])); + assert.isTrue(pluginLoader.arePluginsLoaded()); + assert.isTrue(alertStub.calledOnce); + assert.isTrue(pluginLoader.isPluginLoaded(plugins[1])); + assert.isFalse(pluginLoader.isPluginLoaded(plugins[0])); + }); + + test('plugins installed all failed', async () => { + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + + const alertStub = sinon.stub(); + addListenerForTest(document, 'show-alert', alertStub); + + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install( + () => { + throw new Error('failed'); + }, + undefined, + url + ); + }); + + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + + pluginLoader.loadPlugins(plugins); + + await flush(); + assert.isTrue(pluginsLoadedStub.calledWithExactly([])); + assert.isTrue(pluginLoader.arePluginsLoaded()); + assert.isTrue(alertStub.calledTwice); + }); + + test('plugins installed failed because of wrong version', async () => { + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + + const alertStub = sinon.stub(); + addListenerForTest(document, 'show-alert', alertStub); + + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install(() => {}, url === plugins[0] ? '' : 'alpha', url); + }); + + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + + pluginLoader.loadPlugins(plugins); + + await flush(); + assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo'])); + assert.isTrue(pluginLoader.arePluginsLoaded()); + assert.isTrue(alertStub.calledOnce); + }); + + test('multiple assets for same plugin installed successfully', async () => { + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install(() => void 0, undefined, url); + }); + const pluginsLoadedStub = sinon.stub( + pluginLoader._getReporting(), + 'pluginsLoaded' + ); + + const plugins = [ + 'http://test.com/plugins/foo/static/test.js', + 'http://test.com/plugins/foo/static/test2.js', + 'http://test.com/plugins/bar/static/test.js', + ]; + pluginLoader.loadPlugins(plugins); + + await flush(); + assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo', 'bar'])); + assert.isTrue(pluginLoader.arePluginsLoaded()); + }); + + suite('plugin path and url', () => { + let loadJsPluginStub: sinon.SinonStub; + setup(() => { + loadJsPluginStub = sinon.stub(); + sinon + .stub(pluginLoader, '_createScriptTag') + .callsFake((url: string, _onerror?: OnErrorEventHandler | undefined) => + loadJsPluginStub(url) + ); + }); + + test('invalid plugin path', () => { + const failToLoadStub = sinon.stub(); + sinon.stub(pluginLoader, '_failToLoad').callsFake((...args) => { + failToLoadStub(...args); + }); + + pluginLoader.loadPlugins(['foo/bar']); + + assert.isTrue(failToLoadStub.calledOnce); + assert.isTrue( + failToLoadStub.calledWithExactly( + 'Unrecognized plugin path foo/bar', + 'foo/bar' + ) + ); + }); + + test('relative path for plugins', () => { + pluginLoader.loadPlugins(['foo/bar.js']); + + assert.isTrue(loadJsPluginStub.calledOnce); + assert.isTrue(loadJsPluginStub.calledWithExactly(`${url}/foo/bar.js`)); + }); + + test('relative path should honor getBaseUrl', () => { + const testUrl = '/test'; + stubBaseUrl(testUrl); + + pluginLoader.loadPlugins(['foo/bar.js']); + + assert.isTrue(loadJsPluginStub.calledOnce); + assert.isTrue( + loadJsPluginStub.calledWithExactly(`${url}${testUrl}/foo/bar.js`) + ); + }); + + test('absolute path for plugins', () => { + pluginLoader.loadPlugins(['http://e.com/foo/bar.js']); + + assert.isTrue(loadJsPluginStub.calledOnce); + assert.isTrue( + loadJsPluginStub.calledWithExactly('http://e.com/foo/bar.js') + ); + }); + }); + + suite('With ASSETS_PATH', () => { + let loadJsPluginStub: sinon.SinonStub; + setup(() => { + window.ASSETS_PATH = 'https://cdn.com'; + loadJsPluginStub = sinon.stub(); + sinon + .stub(pluginLoader, '_createScriptTag') + .callsFake((url: string, _onerror?: OnErrorEventHandler | undefined) => + loadJsPluginStub(url) + ); + }); + + teardown(() => { + window.ASSETS_PATH = ''; + }); + + test('Should try load plugins from assets path instead', () => { + pluginLoader.loadPlugins(['foo/bar.js']); + + assert.isTrue(loadJsPluginStub.calledOnce); + assert.isTrue( + loadJsPluginStub.calledWithExactly('https://cdn.com/foo/bar.js') + ); + }); + + test('Should honor original path if exists', () => { + pluginLoader.loadPlugins(['http://e.com/foo/bar.js']); + + assert.isTrue(loadJsPluginStub.calledOnce); + assert.isTrue( + loadJsPluginStub.calledWithExactly('http://e.com/foo/bar.js') + ); + }); + + test('Should try replace current host with assetsPath', () => { + const host = window.location.origin; + pluginLoader.loadPlugins([`${host}/foo/bar.js`]); + + assert.isTrue(loadJsPluginStub.calledOnce); + assert.isTrue( + loadJsPluginStub.calledWithExactly('https://cdn.com/foo/bar.js') + ); + }); + }); + + test('adds js plugins will call the body', () => { + pluginLoader.loadPlugins([ + 'http://e.com/foo/bar.js', + 'http://e.com/bar/foo.js', + ]); + assert.isTrue(bodyStub.calledTwice); + }); + + test('can call awaitPluginsLoaded multiple times', async () => { + const plugins = ['http://e.com/foo/bar.js', 'http://e.com/bar/foo.js']; + + let installed = false; + function pluginCallback(url: string) { + if (url === plugins[1]) { + installed = true; + } + } + sinon.stub(pluginLoader, '_loadJsPlugin').callsFake(url => { + window.Gerrit.install(() => pluginCallback(url), undefined, url); + }); + + pluginLoader.loadPlugins(plugins); + + await pluginLoader.awaitPluginsLoaded(); + assert.isTrue(installed); + await pluginLoader.awaitPluginsLoaded(); + }); +}); |