import Setting from '../../models/Setting'; import PluginService from '../../services/plugins/PluginService'; import { setupDatabaseAndSynchronizer, switchClient } from '../../testing/test-utils'; import loadPlugins, { Props as LoadPluginsProps } from './loadPlugins'; import MockPluginRunner from './testing/MockPluginRunner'; import reducer, { State, defaultState } from '../../reducer'; import { Action, createStore } from 'redux'; import MockPlatformImplementation from './testing/MockPlatformImplementation'; import createTestPlugin from '../../testing/plugins/createTestPlugin'; const createMockReduxStore = () => { return createStore((state: State = defaultState, action: Action) => { return reducer(state, action); }); }; const defaultManifestProperties = { manifest_version: 1, version: '0.1.0', app_min_version: '2.3.4', platforms: ['desktop', 'mobile'], }; const platformImplementation = new MockPlatformImplementation(); describe('loadPlugins', () => { beforeEach(async () => { await setupDatabaseAndSynchronizer(1); await switchClient(1); }); afterEach(async () => { for (const id of PluginService.instance().pluginIds) { await PluginService.instance().unloadPlugin(id); } await PluginService.instance().destroy(); }); test('should load only enabled plugins', async () => { await createTestPlugin({ ...defaultManifestProperties, id: 'this.is.a.test.1', name: 'Disabled Plugin', }, { enabled: false }); const enabledPluginId = 'this.is.a.test.2'; await createTestPlugin({ ...defaultManifestProperties, id: enabledPluginId, name: 'Enabled Plugin', }); const pluginRunner = new MockPluginRunner(); const store = createMockReduxStore(); const loadPluginsOptions: LoadPluginsProps = { pluginRunner, pluginSettings: Setting.value('plugins.states'), platformImplementation, store, reloadAll: false, cancelEvent: { cancelled: false }, }; expect(Object.keys(PluginService.instance().plugins)).toHaveLength(0); await loadPlugins(loadPluginsOptions); await pluginRunner.waitForAllToBeRunning([enabledPluginId]); expect(pluginRunner.runningPluginIds).toMatchObject([enabledPluginId]); // No plugins were running before, so none should be stopped. expect(pluginRunner.stopCalledTimes).toBe(0); // Loading again should not re-run plugins await loadPlugins(loadPluginsOptions); // Should have tried to stop at most the disabled plugin (which is a no-op). expect(pluginRunner.stopCalledTimes).toBe(1); expect(pluginRunner.runningPluginIds).toMatchObject([enabledPluginId]); }); test('should reload all plugins when reloadAll is true', async () => { const enabledCount = 3; for (let i = 0; i < enabledCount; i++) { await createTestPlugin({ ...defaultManifestProperties, id: `joplin.test.plugin.${i}`, name: `Enabled Plugin ${i}`, }); } const disabledCount = 6; const disabledPlugins = []; for (let i = 0; i < disabledCount; i++) { disabledPlugins.push( await createTestPlugin({ ...defaultManifestProperties, id: `joplin.test.plugin.disabled.${i}`, name: `Disabled Plugin ${i}`, }, { enabled: false }), ); } const pluginRunner = new MockPluginRunner(); const store = createMockReduxStore(); const loadPluginsOptions: LoadPluginsProps = { pluginRunner, pluginSettings: Setting.value('plugins.states'), platformImplementation, store, reloadAll: true, cancelEvent: { cancelled: false }, }; await loadPlugins(loadPluginsOptions); let expectedRunningIds = ['joplin.test.plugin.0', 'joplin.test.plugin.1', 'joplin.test.plugin.2']; await pluginRunner.waitForAllToBeRunning(expectedRunningIds); // No additional plugins should be running. expect([...pluginRunner.runningPluginIds].sort()).toMatchObject(expectedRunningIds); // No plugins were running before -- there were no plugins to stop expect(pluginRunner.stopCalledTimes).toBe(0); const testPlugin = disabledPlugins[2]; expect(testPlugin.manifest.id).toBe('joplin.test.plugin.disabled.2'); // Enabling a plugin and reloading it should cause all plugins to load. testPlugin.setEnabled(true); await loadPlugins({ ...loadPluginsOptions, pluginSettings: Setting.value('plugins.states') }); expectedRunningIds = ['joplin.test.plugin.0', 'joplin.test.plugin.1', 'joplin.test.plugin.2', 'joplin.test.plugin.disabled.2']; await pluginRunner.waitForAllToBeRunning(expectedRunningIds); // Reloading all should stop all plugins and rerun enabled plugins, even // if not enabled previously. expect(pluginRunner.stopCalledTimes).toBe(disabledCount + enabledCount); expect([...pluginRunner.runningPluginIds].sort()).toMatchObject(expectedRunningIds); }); });