Make sure sandy device plugins are rendered
Summary: Now that we can load device plugins, let's make sure they are rendered as well. Reviewed By: passy, nikoant Differential Revision: D22693927 fbshipit-source-id: 22574ec6e629e6dd66e42193b406ceb7dfcf1836
This commit is contained in:
committed by
Facebook GitHub Bot
parent
489dd1521e
commit
b621dcf754
@@ -343,18 +343,13 @@ class PluginContainer extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
let pluginElement: null | React.ReactElement<any>;
|
let pluginElement: null | React.ReactElement<any>;
|
||||||
if (isSandyPlugin(activePlugin)) {
|
if (isSandyPlugin(activePlugin)) {
|
||||||
if (target instanceof Client) {
|
// Make sure we throw away the container for different pluginKey!
|
||||||
// Make sure we throw away the container for different pluginKey!
|
pluginElement = (
|
||||||
pluginElement = (
|
<SandyPluginRenderer
|
||||||
<SandyPluginRenderer
|
key={pluginKey}
|
||||||
key={pluginKey}
|
plugin={target.sandyPluginStates.get(activePlugin.id)!}
|
||||||
plugin={target.sandyPluginStates.get(activePlugin.id)!}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// TODO: target might be a device as well, support that T68738317
|
|
||||||
pluginElement = null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const props: PluginProps<Object> & {
|
const props: PluginProps<Object> & {
|
||||||
key: string;
|
key: string;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import {
|
|||||||
TestUtils,
|
TestUtils,
|
||||||
usePlugin,
|
usePlugin,
|
||||||
createState,
|
createState,
|
||||||
|
DevicePluginClient,
|
||||||
|
DeviceLogEntry,
|
||||||
useValue,
|
useValue,
|
||||||
} from 'flipper-plugin';
|
} from 'flipper-plugin';
|
||||||
import {selectPlugin, starPlugin} from '../reducers/connections';
|
import {selectPlugin, starPlugin} from '../reducers/connections';
|
||||||
@@ -367,3 +369,139 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => {
|
|||||||
});
|
});
|
||||||
expect(linksSeen).toEqual(['universe!', 'london!', 'london!']);
|
expect(linksSeen).toEqual(['universe!', 'london!', 'london!']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('PluginContainer can render Sandy device plugins', async () => {
|
||||||
|
let renders = 0;
|
||||||
|
|
||||||
|
function MySandyPlugin() {
|
||||||
|
renders++;
|
||||||
|
const sandyApi = usePlugin(devicePlugin);
|
||||||
|
expect(Object.keys(sandyApi)).toEqual([
|
||||||
|
'activatedStub',
|
||||||
|
'deactivatedStub',
|
||||||
|
'lastLogMessage',
|
||||||
|
]);
|
||||||
|
expect(() => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
usePlugin(function bla() {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}).toThrowError(/didn't match the type of the requested plugin/);
|
||||||
|
const lastLogMessage = useValue(sandyApi.lastLogMessage);
|
||||||
|
return <div>Hello from Sandy: {lastLogMessage?.message}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const devicePlugin = (client: DevicePluginClient) => {
|
||||||
|
const lastLogMessage = createState<undefined | DeviceLogEntry>(undefined);
|
||||||
|
const activatedStub = jest.fn();
|
||||||
|
const deactivatedStub = jest.fn();
|
||||||
|
client.onActivate(activatedStub);
|
||||||
|
client.onDeactivate(deactivatedStub);
|
||||||
|
client.device.onLogEntry((e) => {
|
||||||
|
lastLogMessage.set(e);
|
||||||
|
});
|
||||||
|
return {activatedStub, deactivatedStub, lastLogMessage};
|
||||||
|
};
|
||||||
|
|
||||||
|
const definition = new SandyPluginDefinition(
|
||||||
|
TestUtils.createMockPluginDetails(),
|
||||||
|
{
|
||||||
|
supportsDevice: () => true,
|
||||||
|
devicePlugin,
|
||||||
|
Component: MySandyPlugin,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// any cast because this plugin is not enriched with the meta data that the plugin loader
|
||||||
|
// normally adds. Our further sandy plugin test infra won't need this, but
|
||||||
|
// for this test we do need to act a s a loaded plugin, to make sure PluginContainer itself can handle it
|
||||||
|
const {renderer, act, store, device} = await renderMockFlipperWithPlugin(
|
||||||
|
definition,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(renderer.baseElement).toMatchInlineSnapshot(`
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="css-1orvm1g-View-FlexBox-FlexColumn"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Hello from Sandy:
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="css-bxcvv9-View-FlexBox-FlexRow"
|
||||||
|
id="detailsSidebar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
|
expect(renders).toBe(1);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
device.addLogEntry({
|
||||||
|
date: new Date(),
|
||||||
|
message: 'helleuh',
|
||||||
|
pid: 0,
|
||||||
|
tid: 0,
|
||||||
|
type: 'info',
|
||||||
|
tag: 'test',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
expect(renders).toBe(2);
|
||||||
|
|
||||||
|
expect(renderer.baseElement).toMatchInlineSnapshot(`
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="css-1orvm1g-View-FlexBox-FlexColumn"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Hello from Sandy:
|
||||||
|
helleuh
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="css-bxcvv9-View-FlexBox-FlexRow"
|
||||||
|
id="detailsSidebar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// make sure the plugin gets connected
|
||||||
|
const pluginInstance: ReturnType<typeof devicePlugin> = device.sandyPluginStates.get(
|
||||||
|
definition.id,
|
||||||
|
)!.instanceApi;
|
||||||
|
expect(pluginInstance.activatedStub).toBeCalledTimes(1);
|
||||||
|
expect(pluginInstance.deactivatedStub).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
// select non existing plugin
|
||||||
|
act(() => {
|
||||||
|
store.dispatch(
|
||||||
|
selectPlugin({
|
||||||
|
selectedPlugin: 'Logs',
|
||||||
|
deepLinkPayload: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(renderer.baseElement).toMatchInlineSnapshot(`
|
||||||
|
<body>
|
||||||
|
<div />
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
|
expect(pluginInstance.activatedStub).toBeCalledTimes(1);
|
||||||
|
expect(pluginInstance.deactivatedStub).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
// go back
|
||||||
|
act(() => {
|
||||||
|
store.dispatch(
|
||||||
|
selectPlugin({
|
||||||
|
selectedPlugin: definition.id,
|
||||||
|
deepLinkPayload: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(pluginInstance.activatedStub).toBeCalledTimes(2);
|
||||||
|
expect(pluginInstance.deactivatedStub).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|||||||
@@ -216,12 +216,21 @@ export async function renderMockFlipperWithPlugin(
|
|||||||
|
|
||||||
function selectTestPlugin(store: Store, client: Client) {
|
function selectTestPlugin(store: Store, client: Client) {
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
selectPlugin({
|
selectPlugin(
|
||||||
selectedPlugin: pluginClazz.id,
|
isDevicePluginDefinition(pluginClazz)
|
||||||
selectedApp: client.query.app,
|
? {
|
||||||
deepLinkPayload: null,
|
selectedPlugin: pluginClazz.id,
|
||||||
selectedDevice: store.getState().connections.selectedDevice!,
|
selectedApp: null,
|
||||||
}),
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: store.getState().connections.selectedDevice!,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
selectedPlugin: pluginClazz.id,
|
||||||
|
selectedApp: client.query.app,
|
||||||
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: store.getState().connections.selectedDevice!,
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export type DevicePluginPredicate = (device: Device) => boolean;
|
|||||||
|
|
||||||
export type DevicePluginFactory = (client: DevicePluginClient) => object;
|
export type DevicePluginFactory = (client: DevicePluginClient) => object;
|
||||||
|
|
||||||
|
// TODO: better name?
|
||||||
export interface DevicePluginClient {
|
export interface DevicePluginClient {
|
||||||
readonly device: Device;
|
readonly device: Device;
|
||||||
|
|
||||||
@@ -59,6 +60,8 @@ export interface DevicePluginClient {
|
|||||||
* The counterpart of the `onActivate` handler.
|
* The counterpart of the `onActivate` handler.
|
||||||
*/
|
*/
|
||||||
onDeactivate(cb: () => void): void;
|
onDeactivate(cb: () => void): void;
|
||||||
|
|
||||||
|
// TODO: support onDeeplink!
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RealFlipperDevice {
|
export interface RealFlipperDevice {
|
||||||
|
|||||||
Reference in New Issue
Block a user