diff --git a/desktop/app/src/PluginContainer.tsx b/desktop/app/src/PluginContainer.tsx index 47adfd8fb..5ec9644b1 100644 --- a/desktop/app/src/PluginContainer.tsx +++ b/desktop/app/src/PluginContainer.tsx @@ -48,6 +48,7 @@ import {Idler} from './utils/Idler'; import {processMessageQueue} from './utils/messageQueue'; import {ToggleButton, SmallText} from './ui'; import {SandyPluginRenderer} from 'flipper-plugin'; +import {isDevicePluginDefinition} from './utils/pluginUtils'; const Container = styled(FlexColumn)({ width: 0, @@ -193,24 +194,30 @@ class PluginContainer extends PureComponent { pendingMessages, activePlugin, pluginIsEnabled, + target, } = this.props; if (pluginKey !== this.pluginBeingProcessed) { this.pluginBeingProcessed = pluginKey; this.cancelCurrentQueue(); this.setState({progress: {current: 0, total: 0}}); + // device plugins don't have connections so no message queues + if (!activePlugin || isDevicePluginDefinition(activePlugin)) { + return; + } if ( pluginIsEnabled && + target instanceof Client && activePlugin && - // TODO: support sandy: T68683442 - !isSandyPlugin(activePlugin) && - activePlugin.persistedStateReducer && + (isSandyPlugin(activePlugin) || activePlugin.persistedStateReducer) && pluginKey && pendingMessages?.length ) { const start = Date.now(); this.idler = new Idler(); processMessageQueue( - activePlugin, + isSandyPlugin(activePlugin) + ? target.sandyPluginStates.get(activePlugin.id)! + : activePlugin, pluginKey, this.store, (progress) => { diff --git a/desktop/app/src/__tests__/PluginContainer.node.tsx b/desktop/app/src/__tests__/PluginContainer.node.tsx index 9d3367713..eed1a5a0f 100644 --- a/desktop/app/src/__tests__/PluginContainer.node.tsx +++ b/desktop/app/src/__tests__/PluginContainer.node.tsx @@ -98,11 +98,13 @@ test('PluginContainer can render Sandy plugins', async () => { function MySandyPlugin() { renders++; const sandyApi = usePlugin(plugin); + const count = useValue(sandyApi.count); expect(Object.keys(sandyApi)).toEqual([ 'connectedStub', 'disconnectedStub', 'activatedStub', 'deactivatedStub', + 'count', ]); expect(() => { // eslint-disable-next-line @@ -110,10 +112,15 @@ test('PluginContainer can render Sandy plugins', async () => { return {}; }); }).toThrowError(/didn't match the type of the requested plugin/); - return
Hello from Sandy
; + return
Hello from Sandy{count}
; } - const plugin = (client: PluginClient) => { + type Events = { + inc: {delta: number}; + }; + + const plugin = (client: PluginClient) => { + const count = createState(0); const connectedStub = jest.fn(); const disconnectedStub = jest.fn(); const activatedStub = jest.fn(); @@ -122,7 +129,16 @@ test('PluginContainer can render Sandy plugins', async () => { client.onDisconnect(disconnectedStub); client.onActivate(activatedStub); client.onDeactivate(deactivatedStub); - return {connectedStub, disconnectedStub, activatedStub, deactivatedStub}; + client.onMessage('inc', ({delta}) => { + count.set(count.get() + delta); + }); + return { + connectedStub, + disconnectedStub, + activatedStub, + deactivatedStub, + count, + }; }; const definition = new SandyPluginDefinition( @@ -143,29 +159,54 @@ test('PluginContainer can render Sandy plugins', async () => { expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); expect(renderer.baseElement).toMatchInlineSnapshot(` - + +
+
-
-
- Hello from Sandy -
-
-
+ Hello from Sandy + 0
- - `); +
+
+
+ + `); expect(renders).toBe(1); - // sending a new message doesn't cause a re-render + // sending irrelevant message does not cause a re-render + act(() => { + sendMessage('oops', {delta: 2}); + }); + expect(renders).toBe(1); + + // sending a new message cause a re-render act(() => { sendMessage('inc', {delta: 2}); }); - expect(renders).toBe(1); + expect(renders).toBe(2); + expect(renderer.baseElement).toMatchInlineSnapshot(` + +
+
+
+ Hello from Sandy + 2 +
+
+
+
+ + `); // make sure the plugin gets connected const pluginInstance: ReturnType = client.sandyPluginStates.get( @@ -198,6 +239,14 @@ test('PluginContainer can render Sandy plugins', async () => { expect(pluginInstance.activatedStub).toBeCalledTimes(1); expect(pluginInstance.deactivatedStub).toBeCalledTimes(1); + // send some messages while in BG + act(() => { + sendMessage('inc', {delta: 3}); + sendMessage('inc', {delta: 4}); + }); + expect(renders).toBe(2); + expect(pluginInstance.count.get()).toBe(2); + // go back act(() => { store.dispatch( @@ -207,6 +256,27 @@ test('PluginContainer can render Sandy plugins', async () => { }), ); }); + // Might be needed, but seems to work reliable without: await sleep(1000); + expect(renderer.baseElement).toMatchInlineSnapshot(` + +
+
+
+ Hello from Sandy + 9 +
+
+
+
+ +`); + + expect(pluginInstance.count.get()).toBe(9); expect(pluginInstance.connectedStub).toBeCalledTimes(2); expect(pluginInstance.disconnectedStub).toBeCalledTimes(1); expect(pluginInstance.activatedStub).toBeCalledTimes(2); @@ -247,6 +317,9 @@ test('PluginContainer can render Sandy plugins', async () => { client.sandyPluginStates.get('TestPlugin')!.instanceApi.connectedStub, ).toBeCalledTimes(1); expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); + expect( + client.sandyPluginStates.get('TestPlugin')!.instanceApi.count.get(), + ).toBe(0); }); test('PluginContainer triggers correct lifecycles for background plugin', async () => {