diff --git a/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap b/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap index 065f2308a..1efb2c290 100644 --- a/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap +++ b/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap @@ -87,3 +87,112 @@ Object { "uninstalledPluginNames": Set {}, } `; + +exports[`can create a Fake flipper with legacy wrapper 1`] = ` +Object { + "activeClient": Object { + "id": "TestApp#Android#MockAndroidDevice#serial", + "query": Object { + "app": "TestApp", + "device": "MockAndroidDevice", + "device_id": "serial", + "os": "Android", + "sdk_version": 4, + }, + }, + "activeDevice": Object { + "deviceType": "physical", + "os": "Android", + "serial": "serial", + "title": "MockAndroidDevice", + }, + "androidEmulators": Array [], + "clients": Array [ + Object { + "id": "TestApp#Android#MockAndroidDevice#serial", + "query": Object { + "app": "TestApp", + "device": "MockAndroidDevice", + "device_id": "serial", + "os": "Android", + "sdk_version": 4, + }, + }, + ], + "deepLinkPayload": null, + "devices": Array [ + Object { + "deviceType": "physical", + "os": "Android", + "serial": "serial", + "title": "MockAndroidDevice", + }, + ], + "enabledDevicePlugins": Set { + "DeviceLogs", + "CrashReporter", + "MobileBuilds", + "Hermesdebuggerrn", + "React", + }, + "enabledPlugins": Object { + "TestApp": Array [ + "TestPlugin", + ], + }, + "metroDevice": null, + "selectedApp": "TestApp#Android#MockAndroidDevice#serial", + "selectedDevice": Object { + "deviceType": "physical", + "os": "Android", + "serial": "serial", + "title": "MockAndroidDevice", + }, + "selectedPlugin": "TestPlugin", + "staticView": null, + "uninitializedClients": Array [], + "userPreferredApp": "TestApp#Android#MockAndroidDevice#serial", + "userPreferredDevice": "MockAndroidDevice", + "userPreferredPlugin": "TestPlugin", +} +`; + +exports[`can create a Fake flipper with legacy wrapper 2`] = ` +Object { + "bundledPlugins": Map {}, + "clientPlugins": Map { + "TestPlugin" => SandyPluginDefinition { + "details": Object { + "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-sample1", + "entry": "./test/index.js", + "id": "TestPlugin", + "isActivatable": true, + "isBundled": false, + "main": "dist/bundle.js", + "name": "flipper-plugin-hello", + "pluginType": "client", + "source": "src/index.js", + "specVersion": 2, + "title": "TestPlugin", + "version": "0.1.0", + }, + "id": "TestPlugin", + "isDevicePlugin": false, + "module": Object { + "Component": [Function], + "plugin": [Function], + }, + }, + }, + "devicePlugins": Map {}, + "disabledPlugins": Array [], + "failedPlugins": Array [], + "gatekeepedPlugins": Array [], + "initialised": false, + "installedPlugins": Map {}, + "loadedPlugins": Map {}, + "marketplacePlugins": Array [], + "selectedPlugins": Array [], + "uninstalledPluginNames": Set {}, +} +`; diff --git a/desktop/app/src/__tests__/createMockFlipperWithPlugin.node.tsx b/desktop/app/src/__tests__/createMockFlipperWithPlugin.node.tsx index ca44b5191..1b845e319 100644 --- a/desktop/app/src/__tests__/createMockFlipperWithPlugin.node.tsx +++ b/desktop/app/src/__tests__/createMockFlipperWithPlugin.node.tsx @@ -9,6 +9,7 @@ import {createMockFlipperWithPlugin} from '../test-utils/createMockFlipperWithPlugin'; import {FlipperPlugin} from '../plugin'; +import {TestIdler} from '../utils/Idler'; interface PersistedState { count: 1; @@ -41,7 +42,7 @@ class TestPlugin extends FlipperPlugin { test('can create a Fake flipper', async () => { const {client, device, store, sendMessage} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, {disableLegacyWrapper: true}); expect(client).toBeTruthy(); expect(device).toBeTruthy(); expect(store).toBeTruthy(); @@ -58,3 +59,29 @@ test('can create a Fake flipper', async () => { } `); }); + +const testIdler = new TestIdler(); + +function testOnStatusMessage() { + // emtpy stub +} + +test('can create a Fake flipper with legacy wrapper', async () => { + const {client, device, store, sendMessage} = + await createMockFlipperWithPlugin(TestPlugin); + expect(client).toBeTruthy(); + expect(device).toBeTruthy(); + expect(store).toBeTruthy(); + expect(sendMessage).toBeTruthy(); + expect(client.plugins.includes(TestPlugin.id)).toBe(true); + expect(client.sandyPluginStates.has(TestPlugin.id)).toBe(true); + const state = store.getState(); + expect(state.connections).toMatchSnapshot(); + expect(state.plugins).toMatchSnapshot(); + sendMessage('inc', {}); + expect( + await state.connections.clients[0].sandyPluginStates + .get(TestPlugin.id)! + .exportState(testIdler, testOnStatusMessage), + ).toMatchInlineSnapshot(`"{\\"count\\":1}"`); +}); diff --git a/desktop/app/src/chrome/__tests__/ExportDataPluginSheet.node.tsx b/desktop/app/src/chrome/__tests__/ExportDataPluginSheet.node.tsx index 2febd9b6c..093272752 100644 --- a/desktop/app/src/chrome/__tests__/ExportDataPluginSheet.node.tsx +++ b/desktop/app/src/chrome/__tests__/ExportDataPluginSheet.node.tsx @@ -93,8 +93,15 @@ test('SettingsSheet snapshot with one plugin enabled', async () => { }, ); - // enabled, but no data - expect(getExportablePlugins(store.getState(), device, client)).toEqual([]); + // enabled + // in Sandy wrapper, a plugin is either persistable or not, but it doesn't depend on the current state. + // So this plugin will show up, even though its state is still the default + expect(getExportablePlugins(store.getState(), device, client)).toEqual([ + { + id: 'TestPlugin', + label: 'TestPlugin', + }, + ]); store.dispatch( setPluginState({ diff --git a/desktop/app/src/dispatcher/__tests__/plugins.node.tsx b/desktop/app/src/dispatcher/__tests__/plugins.node.tsx index 88a2ef4a6..04a9f435e 100644 --- a/desktop/app/src/dispatcher/__tests__/plugins.node.tsx +++ b/desktop/app/src/dispatcher/__tests__/plugins.node.tsx @@ -162,7 +162,14 @@ test('requirePlugin loads plugin', () => { version: '1.0.0', }); expect(plugin).not.toBeNull(); - expect((plugin as any).prototype).toBeInstanceOf(FlipperPlugin); + expect(Object.keys(plugin as any)).toEqual([ + 'id', + 'details', + 'isDevicePlugin', + 'module', + ]); + expect(Object.keys((plugin as any).module)).toEqual(['plugin', 'Component']); + expect(plugin!.id).toBe(TestPlugin.id); }); diff --git a/desktop/app/src/dispatcher/plugins.tsx b/desktop/app/src/dispatcher/plugins.tsx index a1ae4fed7..2d86e4f7d 100644 --- a/desktop/app/src/dispatcher/plugins.tsx +++ b/desktop/app/src/dispatcher/plugins.tsx @@ -318,11 +318,11 @@ const requirePluginInternal = ( plugin.packageName = pluginDetails.name; plugin.details = pluginDetails; - if (GK.get('flipper_use_sandy_plugin_wrapper')) { - return new _SandyPluginDefinition( - pluginDetails, - createSandyPluginWrapper(plugin), - ); + if ( + GK.get('flipper_use_sandy_plugin_wrapper') || + process.env.NODE_ENV === 'test' + ) { + return createSandyPluginFromClassicPlugin(pluginDetails, plugin); } // set values from package.json as static variables on class @@ -336,6 +336,17 @@ const requirePluginInternal = ( return plugin; }; +export function createSandyPluginFromClassicPlugin( + pluginDetails: ActivatablePluginDetails, + plugin: any, +) { + pluginDetails.id = plugin.id; // for backward compatibility, see above check! + return new _SandyPluginDefinition( + pluginDetails, + createSandyPluginWrapper(plugin), + ); +} + export function selectCompatibleMarketplaceVersions( availablePlugins: MarketplacePluginDetails[], ): MarketplacePluginDetails[] { diff --git a/desktop/app/src/reducers/__tests__/sandyplugins.node.tsx b/desktop/app/src/reducers/__tests__/sandyplugins.node.tsx index b8fad9f75..ea9afd9ac 100644 --- a/desktop/app/src/reducers/__tests__/sandyplugins.node.tsx +++ b/desktop/app/src/reducers/__tests__/sandyplugins.node.tsx @@ -9,7 +9,6 @@ import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin'; import {Store, Client} from '../../'; -import {selectPlugin} from '../../reducers/connections'; import {registerPlugins} from '../../reducers/plugins'; import { _SandyPluginDefinition, @@ -66,19 +65,8 @@ function starTestPlugin(store: Store, client: Client) { ); } -function selectTestPlugin(store: Store, client: Client) { - store.dispatch( - selectPlugin({ - selectedPlugin: TestPlugin.id, - selectedApp: client.query.app, - deepLinkPayload: null, - selectedDevice: store.getState().connections.selectedDevice!, - }), - ); -} - test('it should initialize starred sandy plugins', async () => { - const {client, store} = await createMockFlipperWithPlugin(TestPlugin); + const {client} = await createMockFlipperWithPlugin(TestPlugin); // already started, so initialized immediately expect(initialized).toBe(true); @@ -89,12 +77,6 @@ test('it should initialize starred sandy plugins', async () => { TestPlugin.id, )!.instanceApi; - expect(instanceApi.connectStub).toBeCalledTimes(0); - selectTestPlugin(store, client); - - // without rendering, non-bg plugins won't connect automatically, - // so this isn't the best test, but PluginContainer tests do test that part of the lifecycle - client.initPlugin(TestPlugin.id); expect(instanceApi.connectStub).toBeCalledTimes(1); client.deinitPlugin(TestPlugin.id); expect(instanceApi.disconnectStub).toBeCalledTimes(1); diff --git a/desktop/app/src/test-utils/MockFlipper.tsx b/desktop/app/src/test-utils/MockFlipper.tsx index 5321c1658..3b76b089a 100644 --- a/desktop/app/src/test-utils/MockFlipper.tsx +++ b/desktop/app/src/test-utils/MockFlipper.tsx @@ -216,9 +216,10 @@ export default class MockFlipper { } }; client.rawSend = jest.fn(); - if (!device.isArchived) { await client.init(); + } else { + await client.initFromImport({}); } // As convenience, by default we select the new client, star the plugin, and select it diff --git a/desktop/app/src/test-utils/createMockFlipperWithPlugin.tsx b/desktop/app/src/test-utils/createMockFlipperWithPlugin.tsx index 46dfcba69..59b50d5b5 100644 --- a/desktop/app/src/test-utils/createMockFlipperWithPlugin.tsx +++ b/desktop/app/src/test-utils/createMockFlipperWithPlugin.tsx @@ -27,11 +27,14 @@ import {Store} from '../reducers/index'; import Client, {ClientQuery} from '../Client'; import {Logger} from '../fb-interfaces/Logger'; -import {PluginDefinition} from '../plugin'; +import {FlipperDevicePlugin, PluginDefinition} from '../plugin'; import PluginContainer from '../PluginContainer'; import {getPluginKey, isDevicePluginDefinition} from '../utils/pluginUtils'; import MockFlipper from './MockFlipper'; import {switchPlugin} from '../reducers/pluginManager'; +import {createSandyPluginFromClassicPlugin} from '../dispatcher/plugins'; +import {createMockActivatablePluginDetails} from '../utils/testUtils'; +import {_SandyPluginDefinition} from 'flipper-plugin'; export type MockFlipperResult = { client: Client; @@ -49,6 +52,12 @@ export type MockFlipperResult = { ): Promise; logger: Logger; togglePlugin(plugin?: string): void; + selectPlugin( + id?: string, + client?: Client, + device?: BaseDevice, + deepLinkPayload?: any, + ): void; }; type MockOptions = Partial<{ @@ -63,6 +72,7 @@ type MockOptions = Partial<{ supportedPlugins?: string[]; device?: BaseDevice; archivedDevice?: boolean; + disableLegacyWrapper?: boolean; }>; function isPluginEnabled( @@ -84,9 +94,30 @@ export async function createMockFlipperWithPlugin( pluginClazz: PluginDefinition, options?: MockOptions, ): Promise { + function wrapSandy(clazz: PluginDefinition) { + return clazz instanceof _SandyPluginDefinition || + options?.disableLegacyWrapper + ? clazz + : createSandyPluginFromClassicPlugin( + createMockActivatablePluginDetails({ + id: clazz.id, + title: clazz.title ?? clazz.id, + pluginType: + clazz.prototype instanceof FlipperDevicePlugin + ? 'device' + : 'client', + }), + clazz, + ); + } + + pluginClazz = wrapSandy(pluginClazz); const mockFlipper = new MockFlipper(); await mockFlipper.init({ - plugins: [pluginClazz, ...(options?.additionalPlugins ?? [])], + plugins: [ + pluginClazz, + ...(options?.additionalPlugins?.map(wrapSandy) ?? []), + ], }); const logger = mockFlipper.logger; const store = mockFlipper.store; @@ -107,6 +138,7 @@ export async function createMockFlipperWithPlugin( supportedPlugins: options?.supportedPlugins, backgroundPlugins: options?.asBackgroundPlugin ? [pluginClazz.id] : [], }); + // enable the plugin if (!isPluginEnabled(store, pluginClazz, name)) { store.dispatch( @@ -116,6 +148,7 @@ export async function createMockFlipperWithPlugin( }), ); } + if (!options?.dontEnableAdditionalPlugins) { options?.additionalPlugins?.forEach((plugin) => { if (!isPluginEnabled(store, plugin, name)) { @@ -139,19 +172,36 @@ export async function createMockFlipperWithPlugin( store.dispatch(selectDevice(device)); store.dispatch(selectClient(client.id)); - store.dispatch( - selectPlugin({ - selectedPlugin: pluginClazz.id, - selectedApp: client.query.app, - deepLinkPayload: null, - selectedDevice: device, - }), - ); + let lastSelected: string | undefined = undefined; + + function selectPluginImpl( + id = pluginClazz.id, + theClient = client, + theDevice = device, + deepLinkPayload = null, + ) { + if (lastSelected) { + client.deinitPlugin(lastSelected); + } + store.dispatch( + selectPlugin({ + selectedPlugin: id, + selectedApp: theClient.query.app, + deepLinkPayload, + selectedDevice: theDevice, + }), + ); + client.initPlugin(pluginClazz.id); // simulates plugin being mounted + lastSelected = pluginClazz.id; + } + + selectPluginImpl(); return { client, device: device as any, store, + selectPlugin: selectPluginImpl, sendError(error: any, actualClient = client) { actualClient.onMessage( JSON.stringify({ diff --git a/desktop/app/src/utils/__tests__/exportData.node.tsx b/desktop/app/src/utils/__tests__/exportData.node.tsx index 911154431..2f6585b34 100644 --- a/desktop/app/src/utils/__tests__/exportData.node.tsx +++ b/desktop/app/src/utils/__tests__/exportData.node.tsx @@ -1208,24 +1208,16 @@ test('Non sandy plugins are exported properly if they are still queued', async ( sendMessage('inc', {}); sendMessage('inc', {}); - // not flushed - expect(store.getState().pluginStates).toMatchInlineSnapshot(`Object {}`); - + // store export will cause flush const storeExport = await exportStore(store); - // flushed - expect(store.getState().pluginStates).toMatchInlineSnapshot(` - Object { - "TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object { - "counter": 3, - }, - } - `); const serial = storeExport.exportStoreData.device!.serial; expect(serial).not.toBeFalsy(); - expect(storeExport.exportStoreData.store.pluginStates).toMatchInlineSnapshot(` + expect(storeExport.exportStoreData.pluginStates2).toMatchInlineSnapshot(` Object { - "TestApp#Android#MockAndroidDevice#${serial}#TestPlugin": "{\\"counter\\":3}", + "TestApp#Android#MockAndroidDevice#00000000-0000-0000-0000-000000000000-serial": Object { + "TestPlugin": "{\\"counter\\":3}", + }, } `); }); diff --git a/desktop/app/src/utils/__tests__/messageQueue.node.tsx b/desktop/app/src/utils/__tests__/messageQueue.node.tsx index 0521107cd..329ae109a 100644 --- a/desktop/app/src/utils/__tests__/messageQueue.node.tsx +++ b/desktop/app/src/utils/__tests__/messageQueue.node.tsx @@ -88,6 +88,9 @@ function selectTestPlugin(store: Store, client: Client) { test('queue - events are processed immediately if plugin is selected', async () => { const {store, client, sendMessage} = await createMockFlipperWithPlugin( TestPlugin, + { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }, ); expect(store.getState().connections.selectedPlugin).toBe('TestPlugin'); sendMessage('noop', {}); @@ -110,7 +113,9 @@ test('queue - events are processed immediately if plugin is selected', async () test('queue - events are NOT processed immediately if plugin is NOT selected (but enabled)', async () => { const {store, client, sendMessage, device} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); expect(store.getState().connections.selectedPlugin).not.toBe('TestPlugin'); @@ -200,7 +205,9 @@ test('queue - events are NOT processed immediately if plugin is NOT selected (bu test('queue - events are queued for plugins that are favorite when app is not selected', async () => { const {device, store, sendMessage, createClient} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); expect(store.getState().connections.selectedPlugin).not.toBe('TestPlugin'); @@ -228,7 +235,9 @@ test('queue - events are queued for plugins that are favorite when app is not se test('queue - events are queued for plugins that are favorite when app is selected on different device', async () => { const {client, store, sendMessage, createDevice, createClient} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); expect(store.getState().connections.selectedPlugin).not.toBe('TestPlugin'); @@ -270,7 +279,9 @@ test('queue - events are queued for plugins that are favorite when app is select test('queue - events processing will be paused', async () => { const {client, device, store, sendMessage} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); sendMessage('inc', {}); @@ -314,7 +325,9 @@ test('queue - events processing will be paused', async () => { test('queue - messages that arrive during processing will be queued', async () => { const {client, device, store, sendMessage} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); sendMessage('inc', {}); @@ -360,7 +373,9 @@ test('queue - messages that arrive during processing will be queued', async () = test('queue - processing can be cancelled', async () => { const {client, device, store, sendMessage} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); sendMessage('inc', {}); @@ -391,7 +406,9 @@ test('queue - processing can be cancelled', async () => { test('queue - make sure resetting plugin state clears the message queue', async () => { const {client, device, store, sendMessage} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); sendMessage('inc', {}); @@ -458,7 +475,9 @@ test('client - incoming messages are buffered and flushed together', async () => } const {client, store, device, sendMessage} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); store.dispatch(registerPlugins([StubDeviceLogs])); @@ -614,7 +633,9 @@ test('client - incoming messages are buffered and flushed together', async () => test('queue - messages that have not yet flushed be lost when disabling the plugin', async () => { const {client, store, sendMessage, pluginKey} = - await createMockFlipperWithPlugin(TestPlugin); + await createMockFlipperWithPlugin(TestPlugin, { + disableLegacyWrapper: true, // Sandy is already tested in messageQueueSandy.node.tsx + }); selectDeviceLogs(store); sendMessage('inc', {}); diff --git a/desktop/app/src/utils/__tests__/pluginUtils.node.tsx b/desktop/app/src/utils/__tests__/pluginUtils.node.tsx index ab594a6da..cd2e8a4f0 100644 --- a/desktop/app/src/utils/__tests__/pluginUtils.node.tsx +++ b/desktop/app/src/utils/__tests__/pluginUtils.node.tsx @@ -99,10 +99,10 @@ test('getActivePersistentPlugins, where the non persistent plugins getting exclu id: 'ClientPlugin4', label: 'ClientPlugin4', }, - { - id: 'ClientPlugin5', - label: 'ClientPlugin5', - }, + // { Never activated, and no data received + // id: 'ClientPlugin5', + // label: 'ClientPlugin5', + // }, ]); }); @@ -140,5 +140,11 @@ test('getActivePersistentPlugins, where the plugins not in pluginState or queue id: 'ClientPlugin3', // queued label: 'ClientPlugin3', }, + { + // in Sandy wrapper, a plugin is either persistable or not, but it doesn't depend on the current state. + // So this plugin will show up, even though its state is still the default + id: 'Plugin1', + label: 'Plugin1', + }, ]); }); diff --git a/desktop/app/src/utils/createSandyPluginWrapper.tsx b/desktop/app/src/utils/createSandyPluginWrapper.tsx index 4f2737d1b..0001452e0 100644 --- a/desktop/app/src/utils/createSandyPluginWrapper.tsx +++ b/desktop/app/src/utils/createSandyPluginWrapper.tsx @@ -37,11 +37,13 @@ export function createSandyPluginWrapper( Plugin: typeof FlipperPlugin | typeof FlipperDevicePlugin, ): SandyPluginModule { const isDevicePlugin = Plugin.prototype instanceof FlipperDevicePlugin; - console.warn( - `Loading ${isDevicePlugin ? 'device' : 'client'} plugin ${ - Plugin.id - } in legacy mode. Please visit https://fbflipper.com/docs/extending/sandy-migration to learn how to migrate this plugin to the new Sandy architecture`, - ); + if (process.env.NODE_ENV !== 'test') { + console.warn( + `Loading ${isDevicePlugin ? 'device' : 'client'} plugin ${ + Plugin.id + } in legacy mode. Please visit https://fbflipper.com/docs/extending/sandy-migration to learn how to migrate this plugin to the new Sandy architecture`, + ); + } function legacyPluginWrapper(client: PluginClient | DevicePluginClient) { const store = getStore(); diff --git a/desktop/app/src/utils/testUtils.tsx b/desktop/app/src/utils/testUtils.tsx index 4708ac96a..7381d6dc0 100644 --- a/desktop/app/src/utils/testUtils.tsx +++ b/desktop/app/src/utils/testUtils.tsx @@ -7,7 +7,10 @@ * @format */ -import {DownloadablePluginDetails} from 'flipper-plugin-lib'; +import { + ActivatablePluginDetails, + DownloadablePluginDetails, +} from 'flipper-plugin-lib'; export function createMockDownloadablePluginDetails( params: { @@ -58,3 +61,23 @@ export function createMockDownloadablePluginDetails( }; return details; } + +export function createMockActivatablePluginDetails( + base: Partial, +): ActivatablePluginDetails { + return { + id: 'Hello', + specVersion: 2, + isBundled: false, + isActivatable: true, + dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-sample1', + entry: './test/index.js', + name: 'flipper-plugin-hello', + version: '0.1.0', + pluginType: 'client', + source: 'src/index.js', + main: 'dist/bundle.js', + title: 'Hello', + ...base, + }; +}