2023-12-22 13:31:57 +02:00
|
|
|
import { afterDefaultPluginsLoaded, getDefaultPluginPathsAndSettings } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
|
2022-09-01 12:44:33 +02:00
|
|
|
import PluginRunner from '../../../app/services/plugins/PluginRunner';
|
2022-09-12 17:08:06 +02:00
|
|
|
import { checkThrow, setupDatabaseAndSynchronizer, supportDir, switchClient } from '@joplin/lib/testing/test-utils';
|
2023-12-22 13:31:57 +02:00
|
|
|
import PluginService, { defaultPluginSetting, DefaultPluginsInfo } from '@joplin/lib/services/plugins/PluginService';
|
2022-09-01 12:44:33 +02:00
|
|
|
import Setting from '@joplin/lib/models/Setting';
|
|
|
|
|
2024-02-03 21:28:47 +02:00
|
|
|
const testDefaultPluginsDir = `${supportDir}/testDefaultPlugins`;
|
2022-09-01 12:44:33 +02:00
|
|
|
|
2024-02-03 21:28:47 +02:00
|
|
|
function newPluginService(appVersion = '2.4') {
|
2022-09-01 12:44:33 +02:00
|
|
|
const runner = new PluginRunner();
|
|
|
|
const service = new PluginService();
|
|
|
|
service.initialize(
|
|
|
|
appVersion,
|
|
|
|
{
|
|
|
|
joplin: {},
|
|
|
|
},
|
|
|
|
runner,
|
|
|
|
{
|
|
|
|
dispatch: () => {},
|
|
|
|
getState: () => {},
|
2023-08-22 12:58:53 +02:00
|
|
|
},
|
2022-09-01 12:44:33 +02:00
|
|
|
);
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
|
2023-02-20 17:02:29 +02:00
|
|
|
describe('defaultPluginsUtils', () => {
|
2022-09-01 12:44:33 +02:00
|
|
|
|
|
|
|
const pluginsId = ['joplin.plugin.ambrt.backlinksToNote', 'org.joplinapp.plugins.ToggleSidebars'];
|
2023-12-22 13:31:57 +02:00
|
|
|
const defaultPluginsInfo = {
|
|
|
|
'joplin.plugin.ambrt.backlinksToNote': {},
|
|
|
|
'org.joplinapp.plugins.ToggleSidebars': {},
|
|
|
|
};
|
2022-09-01 12:44:33 +02:00
|
|
|
|
2022-11-15 12:23:50 +02:00
|
|
|
beforeEach(async () => {
|
2022-09-01 12:44:33 +02:00
|
|
|
await setupDatabaseAndSynchronizer(1);
|
|
|
|
await switchClient(1);
|
|
|
|
});
|
|
|
|
|
2024-02-03 21:28:47 +02:00
|
|
|
it('should load default plugins when not previously installed', (async () => {
|
2022-09-01 12:44:33 +02:00
|
|
|
Setting.setValue('installedDefaultPlugins', []);
|
|
|
|
|
|
|
|
const service = newPluginService('2.1');
|
|
|
|
|
|
|
|
const pluginSettings = service.unserializePluginSettings(Setting.value('plugins.states'));
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
for (const pluginId of pluginsId) {
|
|
|
|
expect(pluginSettings[pluginId]).toBeFalsy();
|
|
|
|
}
|
2022-09-01 12:44:33 +02:00
|
|
|
|
2024-02-03 21:28:47 +02:00
|
|
|
const pluginPathsAndNewSettings = await getDefaultPluginPathsAndSettings(
|
|
|
|
testDefaultPluginsDir, defaultPluginsInfo, pluginSettings, service,
|
|
|
|
);
|
2022-09-01 12:44:33 +02:00
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
for (const pluginId of pluginsId) {
|
|
|
|
expect(
|
|
|
|
pluginPathsAndNewSettings.pluginSettings[pluginId],
|
|
|
|
).toMatchObject(defaultPluginSetting());
|
|
|
|
}
|
2022-09-01 12:44:33 +02:00
|
|
|
}));
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
it('should keep already created default plugins disabled with previous default plugins installed', (async () => {
|
2022-09-01 12:44:33 +02:00
|
|
|
Setting.setValue('installedDefaultPlugins', ['org.joplinapp.plugins.ToggleSidebars']);
|
2023-12-22 13:31:57 +02:00
|
|
|
Setting.setValue('plugins.states', {
|
|
|
|
'org.joplinapp.plugins.ToggleSidebars': { ...defaultPluginSetting(), enabled: false },
|
|
|
|
});
|
2022-09-01 12:44:33 +02:00
|
|
|
|
|
|
|
const service = newPluginService('2.1');
|
|
|
|
|
|
|
|
const pluginSettings = service.unserializePluginSettings(Setting.value('plugins.states'));
|
2024-02-03 21:28:47 +02:00
|
|
|
const pluginPathsAndNewSettings = await getDefaultPluginPathsAndSettings(testDefaultPluginsDir, defaultPluginsInfo, pluginSettings, service);
|
2022-09-01 12:44:33 +02:00
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
// Should still be disabled
|
|
|
|
expect(
|
|
|
|
pluginPathsAndNewSettings.pluginSettings['org.joplinapp.plugins.ToggleSidebars'].enabled,
|
|
|
|
).toBe(false);
|
2022-09-01 12:44:33 +02:00
|
|
|
}));
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
const sampleJsBundlePlugin = `
|
|
|
|
/* joplin-manifest:
|
|
|
|
{
|
|
|
|
"id": "io.github.jackgruber.backup",
|
|
|
|
"manifest_version": 1,
|
|
|
|
"app_min_version": "1.4",
|
|
|
|
"name": "JS Bundle test",
|
|
|
|
"version": "1.0.0"
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
joplin.plugins.register({
|
|
|
|
onStart: async function() {
|
|
|
|
await joplin.settings.registerSettings({
|
|
|
|
path: {
|
|
|
|
value: "initial-path",
|
|
|
|
type: 2,
|
|
|
|
section: "backupSection",
|
|
|
|
public: true,
|
|
|
|
label: "Backup path",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
},
|
|
|
|
});`;
|
2022-09-01 12:44:33 +02:00
|
|
|
|
|
|
|
it('should set initial settings for default plugins', async () => {
|
|
|
|
const service = newPluginService();
|
|
|
|
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
|
|
|
plugin.builtIn = true;
|
2022-09-01 12:44:33 +02:00
|
|
|
await service.runPlugin(plugin);
|
2023-12-22 13:31:57 +02:00
|
|
|
const runningPlugins = { 'io.github.jackgruber.backup': plugin };
|
2022-09-01 12:44:33 +02:00
|
|
|
|
|
|
|
const defaultPluginsInfo: DefaultPluginsInfo = {
|
|
|
|
'io.github.jackgruber.backup': {
|
|
|
|
settings: {
|
|
|
|
'path': `${Setting.value('profileDir')}`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
'plugin.calebjohn.rich-markdown': {
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// with pre-installed default plugin
|
|
|
|
Setting.setValue('installedDefaultPlugins', ['io.github.jackgruber.backup']);
|
2023-12-22 13:31:57 +02:00
|
|
|
const pluginSettings = { 'io.github.jackgruber.backup': defaultPluginSetting() };
|
|
|
|
|
|
|
|
await afterDefaultPluginsLoaded(
|
|
|
|
runningPlugins,
|
|
|
|
defaultPluginsInfo,
|
|
|
|
pluginSettings,
|
|
|
|
);
|
2022-09-01 12:44:33 +02:00
|
|
|
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe('initial-path');
|
|
|
|
|
|
|
|
// with no pre-installed default plugin
|
|
|
|
Setting.setValue('installedDefaultPlugins', ['']);
|
2023-12-22 13:31:57 +02:00
|
|
|
await afterDefaultPluginsLoaded(
|
|
|
|
runningPlugins,
|
|
|
|
defaultPluginsInfo,
|
|
|
|
pluginSettings,
|
|
|
|
);
|
2022-09-01 12:44:33 +02:00
|
|
|
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe(`${Setting.value('profileDir')}`);
|
|
|
|
await service.destroy();
|
|
|
|
});
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
it('should not overwrite existing settings for a user-installed version of a built-in plugin', async () => {
|
2022-09-12 17:08:06 +02:00
|
|
|
const service = newPluginService();
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
|
|
|
plugin.builtIn = false;
|
|
|
|
await service.runPlugin(plugin);
|
|
|
|
|
|
|
|
const defaultPluginsInfo: DefaultPluginsInfo = {
|
|
|
|
'io.github.jackgruber.backup': {
|
|
|
|
settings: {
|
|
|
|
'path': 'overwrite?',
|
|
|
|
},
|
2022-09-12 17:08:06 +02:00
|
|
|
},
|
2023-12-22 13:31:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// No pre-installed default plugins
|
|
|
|
Setting.setValue('installedDefaultPlugins', []);
|
|
|
|
|
|
|
|
// The plugin is running and enabled
|
|
|
|
const runningPlugins = { 'io.github.jackgruber.backup': plugin };
|
|
|
|
const pluginSettings = { 'io.github.jackgruber.backup': defaultPluginSetting() };
|
2022-09-12 17:08:06 +02:00
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
await afterDefaultPluginsLoaded(
|
|
|
|
runningPlugins,
|
|
|
|
defaultPluginsInfo,
|
|
|
|
pluginSettings,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Should not overwrite
|
|
|
|
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe('initial-path');
|
|
|
|
});
|
|
|
|
|
2024-02-09 00:48:39 +02:00
|
|
|
it('should support disabled-by-default plugins', async () => {
|
|
|
|
const service = newPluginService();
|
|
|
|
|
|
|
|
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
|
|
|
plugin.builtIn = false;
|
|
|
|
await service.runPlugin(plugin);
|
|
|
|
|
|
|
|
const defaultPluginsInfo: DefaultPluginsInfo = {
|
|
|
|
'joplin.plugin.ambrt.backlinksToNote': {
|
|
|
|
enabled: false,
|
|
|
|
},
|
|
|
|
'org.joplinapp.plugins.ToggleSidebars': {},
|
|
|
|
};
|
|
|
|
Setting.setValue('installedDefaultPlugins', []);
|
|
|
|
|
|
|
|
const { pluginSettings } = await getDefaultPluginPathsAndSettings(
|
|
|
|
testDefaultPluginsDir, defaultPluginsInfo, {}, service,
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(pluginSettings).toMatchObject({
|
|
|
|
'joplin.plugin.ambrt.backlinksToNote': {
|
|
|
|
enabled: false,
|
|
|
|
deleted: false,
|
|
|
|
},
|
|
|
|
'org.joplinapp.plugins.ToggleSidebars': defaultPluginSetting(),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-12-22 13:31:57 +02:00
|
|
|
it('should not throw error on missing setting key', async () => {
|
|
|
|
|
|
|
|
const service = newPluginService();
|
|
|
|
|
|
|
|
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
|
|
|
plugin.builtIn = true;
|
2022-09-12 17:08:06 +02:00
|
|
|
await service.runPlugin(plugin);
|
|
|
|
|
|
|
|
const defaultPluginsInfo: DefaultPluginsInfo = {
|
|
|
|
'io.github.jackgruber.backup': {
|
|
|
|
settings: {
|
|
|
|
'path': `${Setting.value('profileDir')}`,
|
|
|
|
'missing-key1': 'someValue',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
'plugin.calebjohn.rich-markdown': {
|
|
|
|
settings: {
|
|
|
|
'missing-key2': 'someValue',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
Setting.setValue('installedDefaultPlugins', ['']);
|
2023-12-22 13:31:57 +02:00
|
|
|
const pluginSettings = { 'io.github.jackgruber.backup': defaultPluginSetting() };
|
|
|
|
const runningPlugins = { 'io.github.jackgruber.backup': plugin };
|
|
|
|
|
|
|
|
expect(checkThrow(() => afterDefaultPluginsLoaded(runningPlugins, defaultPluginsInfo, pluginSettings))).toBe(false);
|
2022-09-12 17:08:06 +02:00
|
|
|
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe(`${Setting.value('profileDir')}`);
|
|
|
|
await service.destroy();
|
|
|
|
});
|
|
|
|
|
2024-02-03 21:28:47 +02:00
|
|
|
// Only returning not-yet-loaded plugins prevents non-default versions of built-in plugins
|
|
|
|
// from being overwritten by PluginService.
|
|
|
|
it('getDefaultPluginPathsAndSettings should return only plugins that haven\'t been loaded', async () => {
|
|
|
|
const service = newPluginService();
|
|
|
|
|
|
|
|
const testPluginId = 'org.joplinapp.plugins.ToggleSidebars';
|
|
|
|
const testPluginPath = `${supportDir}/pluginRepo/plugins/${testPluginId}/plugin.jpl`;
|
|
|
|
|
|
|
|
const pluginSettings = {
|
|
|
|
[testPluginId]: defaultPluginSetting(),
|
|
|
|
};
|
|
|
|
|
|
|
|
await service.loadAndRunPlugins([testPluginPath], pluginSettings, { devMode: false, builtIn: false });
|
|
|
|
|
|
|
|
// Should be running
|
|
|
|
expect(service.isPluginLoaded(testPluginId)).toBe(true);
|
|
|
|
|
|
|
|
const testDefaultPluginsInfo = {
|
|
|
|
[testPluginId]: {},
|
|
|
|
'joplin.plugin.ambrt.backlinksToNote': {},
|
|
|
|
};
|
|
|
|
|
|
|
|
const { pluginPaths } = await getDefaultPluginPathsAndSettings(
|
|
|
|
testDefaultPluginsDir, testDefaultPluginsInfo, pluginSettings, service,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Should only return plugins that aren't loaded.
|
|
|
|
expect(pluginPaths).toHaveLength(1);
|
|
|
|
expect(pluginPaths[0]).toContain('joplin.plugin.ambrt.backlinksToNote');
|
|
|
|
});
|
2022-09-01 12:44:33 +02:00
|
|
|
});
|