Fix condition on processing message queues for sandy plugins
Summary: While converting Bloks-Script plugin, Timur found a bug where the message queue wasn't processed. Although queue processing was unit tested, the integration into the rendering lifecycle wasn't explicitly tested and missed a TODO that already signalled this should have been implemented. Added a unit test to verify the bug and fix. Also tested in a running Flipper instance with the converted plugin (next diff) Reviewed By: jknoxville Differential Revision: D23263909 fbshipit-source-id: 63783c980247bdf6c93d00a46881d7d0eb291d09
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6c7748238d
commit
76b72f3d77
@@ -48,6 +48,7 @@ import {Idler} from './utils/Idler';
|
|||||||
import {processMessageQueue} from './utils/messageQueue';
|
import {processMessageQueue} from './utils/messageQueue';
|
||||||
import {ToggleButton, SmallText} from './ui';
|
import {ToggleButton, SmallText} from './ui';
|
||||||
import {SandyPluginRenderer} from 'flipper-plugin';
|
import {SandyPluginRenderer} from 'flipper-plugin';
|
||||||
|
import {isDevicePluginDefinition} from './utils/pluginUtils';
|
||||||
|
|
||||||
const Container = styled(FlexColumn)({
|
const Container = styled(FlexColumn)({
|
||||||
width: 0,
|
width: 0,
|
||||||
@@ -193,24 +194,30 @@ class PluginContainer extends PureComponent<Props, State> {
|
|||||||
pendingMessages,
|
pendingMessages,
|
||||||
activePlugin,
|
activePlugin,
|
||||||
pluginIsEnabled,
|
pluginIsEnabled,
|
||||||
|
target,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (pluginKey !== this.pluginBeingProcessed) {
|
if (pluginKey !== this.pluginBeingProcessed) {
|
||||||
this.pluginBeingProcessed = pluginKey;
|
this.pluginBeingProcessed = pluginKey;
|
||||||
this.cancelCurrentQueue();
|
this.cancelCurrentQueue();
|
||||||
this.setState({progress: {current: 0, total: 0}});
|
this.setState({progress: {current: 0, total: 0}});
|
||||||
|
// device plugins don't have connections so no message queues
|
||||||
|
if (!activePlugin || isDevicePluginDefinition(activePlugin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
pluginIsEnabled &&
|
pluginIsEnabled &&
|
||||||
|
target instanceof Client &&
|
||||||
activePlugin &&
|
activePlugin &&
|
||||||
// TODO: support sandy: T68683442
|
(isSandyPlugin(activePlugin) || activePlugin.persistedStateReducer) &&
|
||||||
!isSandyPlugin(activePlugin) &&
|
|
||||||
activePlugin.persistedStateReducer &&
|
|
||||||
pluginKey &&
|
pluginKey &&
|
||||||
pendingMessages?.length
|
pendingMessages?.length
|
||||||
) {
|
) {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
this.idler = new Idler();
|
this.idler = new Idler();
|
||||||
processMessageQueue(
|
processMessageQueue(
|
||||||
activePlugin,
|
isSandyPlugin(activePlugin)
|
||||||
|
? target.sandyPluginStates.get(activePlugin.id)!
|
||||||
|
: activePlugin,
|
||||||
pluginKey,
|
pluginKey,
|
||||||
this.store,
|
this.store,
|
||||||
(progress) => {
|
(progress) => {
|
||||||
|
|||||||
@@ -98,11 +98,13 @@ test('PluginContainer can render Sandy plugins', async () => {
|
|||||||
function MySandyPlugin() {
|
function MySandyPlugin() {
|
||||||
renders++;
|
renders++;
|
||||||
const sandyApi = usePlugin(plugin);
|
const sandyApi = usePlugin(plugin);
|
||||||
|
const count = useValue(sandyApi.count);
|
||||||
expect(Object.keys(sandyApi)).toEqual([
|
expect(Object.keys(sandyApi)).toEqual([
|
||||||
'connectedStub',
|
'connectedStub',
|
||||||
'disconnectedStub',
|
'disconnectedStub',
|
||||||
'activatedStub',
|
'activatedStub',
|
||||||
'deactivatedStub',
|
'deactivatedStub',
|
||||||
|
'count',
|
||||||
]);
|
]);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@@ -110,10 +112,15 @@ test('PluginContainer can render Sandy plugins', async () => {
|
|||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
}).toThrowError(/didn't match the type of the requested plugin/);
|
}).toThrowError(/didn't match the type of the requested plugin/);
|
||||||
return <div>Hello from Sandy</div>;
|
return <div>Hello from Sandy{count}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugin = (client: PluginClient) => {
|
type Events = {
|
||||||
|
inc: {delta: number};
|
||||||
|
};
|
||||||
|
|
||||||
|
const plugin = (client: PluginClient<Events>) => {
|
||||||
|
const count = createState(0);
|
||||||
const connectedStub = jest.fn();
|
const connectedStub = jest.fn();
|
||||||
const disconnectedStub = jest.fn();
|
const disconnectedStub = jest.fn();
|
||||||
const activatedStub = jest.fn();
|
const activatedStub = jest.fn();
|
||||||
@@ -122,7 +129,16 @@ test('PluginContainer can render Sandy plugins', async () => {
|
|||||||
client.onDisconnect(disconnectedStub);
|
client.onDisconnect(disconnectedStub);
|
||||||
client.onActivate(activatedStub);
|
client.onActivate(activatedStub);
|
||||||
client.onDeactivate(deactivatedStub);
|
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(
|
const definition = new SandyPluginDefinition(
|
||||||
@@ -143,29 +159,54 @@ test('PluginContainer can render Sandy plugins', async () => {
|
|||||||
expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'});
|
expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'});
|
||||||
|
|
||||||
expect(renderer.baseElement).toMatchInlineSnapshot(`
|
expect(renderer.baseElement).toMatchInlineSnapshot(`
|
||||||
<body>
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="css-1orvm1g-View-FlexBox-FlexColumn"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<div
|
Hello from Sandy
|
||||||
class="css-1orvm1g-View-FlexBox-FlexColumn"
|
0
|
||||||
>
|
|
||||||
<div>
|
|
||||||
Hello from Sandy
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="css-bxcvv9-View-FlexBox-FlexRow"
|
|
||||||
id="detailsSidebar"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</div>
|
||||||
`);
|
<div
|
||||||
|
class="css-bxcvv9-View-FlexBox-FlexRow"
|
||||||
|
id="detailsSidebar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
expect(renders).toBe(1);
|
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(() => {
|
act(() => {
|
||||||
sendMessage('inc', {delta: 2});
|
sendMessage('inc', {delta: 2});
|
||||||
});
|
});
|
||||||
expect(renders).toBe(1);
|
expect(renders).toBe(2);
|
||||||
|
expect(renderer.baseElement).toMatchInlineSnapshot(`
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="css-1orvm1g-View-FlexBox-FlexColumn"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Hello from Sandy
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="css-bxcvv9-View-FlexBox-FlexRow"
|
||||||
|
id="detailsSidebar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
|
|
||||||
// make sure the plugin gets connected
|
// make sure the plugin gets connected
|
||||||
const pluginInstance: ReturnType<typeof plugin> = client.sandyPluginStates.get(
|
const pluginInstance: ReturnType<typeof plugin> = client.sandyPluginStates.get(
|
||||||
@@ -198,6 +239,14 @@ test('PluginContainer can render Sandy plugins', async () => {
|
|||||||
expect(pluginInstance.activatedStub).toBeCalledTimes(1);
|
expect(pluginInstance.activatedStub).toBeCalledTimes(1);
|
||||||
expect(pluginInstance.deactivatedStub).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
|
// go back
|
||||||
act(() => {
|
act(() => {
|
||||||
store.dispatch(
|
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(`
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="css-1orvm1g-View-FlexBox-FlexColumn"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Hello from Sandy
|
||||||
|
9
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="css-bxcvv9-View-FlexBox-FlexRow"
|
||||||
|
id="detailsSidebar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(pluginInstance.count.get()).toBe(9);
|
||||||
expect(pluginInstance.connectedStub).toBeCalledTimes(2);
|
expect(pluginInstance.connectedStub).toBeCalledTimes(2);
|
||||||
expect(pluginInstance.disconnectedStub).toBeCalledTimes(1);
|
expect(pluginInstance.disconnectedStub).toBeCalledTimes(1);
|
||||||
expect(pluginInstance.activatedStub).toBeCalledTimes(2);
|
expect(pluginInstance.activatedStub).toBeCalledTimes(2);
|
||||||
@@ -247,6 +317,9 @@ test('PluginContainer can render Sandy plugins', async () => {
|
|||||||
client.sandyPluginStates.get('TestPlugin')!.instanceApi.connectedStub,
|
client.sandyPluginStates.get('TestPlugin')!.instanceApi.connectedStub,
|
||||||
).toBeCalledTimes(1);
|
).toBeCalledTimes(1);
|
||||||
expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'});
|
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 () => {
|
test('PluginContainer triggers correct lifecycles for background plugin', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user