make sure plugins can be loaded into Flipper

Summary: Make sure Sandy plugins are loaded properly from disk

Reviewed By: jknoxville

Differential Revision: D22186275

fbshipit-source-id: fd2f560a7bed959b18e05db2a087909ad876ab9d
This commit is contained in:
Michel Weststrate
2020-07-01 08:58:40 -07:00
committed by Facebook GitHub Bot
parent 1029a6c97c
commit 12ac29685d
5 changed files with 104 additions and 19 deletions

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import * as React from 'react';
import {FlipperClient} from 'flipper-plugin';
type Events = {
inc: {delta: number};
};
export function plugin(_client: FlipperClient<Events, {}>) {
return {};
}
export function Component() {
return <h1>Sandy high fives Flipper</h1>;
}

View File

@@ -29,6 +29,7 @@ import configureStore from 'redux-mock-store';
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
import TestPlugin from './TestPlugin';
import {resetConfigForTesting} from '../../utils/processConfig';
import {SandyPluginDefinition} from 'flipper-plugin';
const mockStore = configureStore<State, {}>([])(
reducers(undefined, {type: 'INIT'}),
@@ -239,3 +240,50 @@ test('bundled versions are used when env var FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE
delete process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE;
}
});
test('requirePlugin loads valid Sandy plugin', () => {
const name = 'pluginID';
const requireFn = requirePlugin([], {}, require);
const plugin = requireFn({
...samplePluginDetails,
name,
entry: path.join(__dirname, 'SandyTestPlugin'),
version: '1.0.0',
flipperSDKVersion: '0.0.0',
}) as SandyPluginDefinition;
expect(plugin).not.toBeNull();
// @ts-ignore
expect(plugin).toBeInstanceOf(SandyPluginDefinition);
expect(plugin.id).toBe('Sample');
expect(plugin.details).toMatchObject({
flipperSDKVersion: '0.0.0',
id: 'Sample',
isDefault: false,
main: 'dist/bundle.js',
name: 'pluginID',
source: 'src/index.js',
specVersion: 2,
title: 'Sample',
version: '1.0.0',
});
expect(typeof plugin.module.Component).toBe('function');
expect(plugin.module.Component.displayName).toBe('FlipperPlugin(Sample)');
expect(typeof plugin.module.plugin).toBe('function');
});
test('requirePlugin errors on invalid Sandy plugin', () => {
const name = 'pluginID';
const failedPlugins: any[] = [];
const requireFn = requirePlugin(failedPlugins, {}, require);
requireFn({
...samplePluginDetails,
name,
// Intentionally the wrong file:
entry: path.join(__dirname, 'TestPlugin'),
version: '1.0.0',
flipperSDKVersion: '0.0.0',
});
expect(failedPlugins[0][1]).toMatchInlineSnapshot(
`"Flipper plugin 'Sample' should export named function called 'plugin'"`,
);
});

View File

@@ -38,6 +38,7 @@ import * as FlipperPluginSDK from 'flipper-plugin';
// eslint-disable-next-line import/no-unresolved
import getPluginIndex from '../utils/getDefaultPluginsIndex';
import {SandyPluginDefinition} from 'flipper-plugin';
const Paragraph = styled.p({
marginBottom: '0.1em',
@@ -271,6 +272,13 @@ const requirePluginInternal = (
let plugin = pluginDetails.isDefault
? defaultPluginsIndex[pluginDetails.name]
: reqFn(pluginDetails.entry);
if (pluginDetails.flipperSDKVersion) {
// Sandy plugin
// TODO: suppor device Plugins T68738317
return new SandyPluginDefinition(pluginDetails, plugin);
} else {
// classic plugin
if (plugin.default) {
plugin = plugin.default;
}
@@ -280,7 +288,6 @@ const requirePluginInternal = (
plugin.id = plugin.id || pluginDetails.id;
plugin.packageName = pluginDetails.name;
plugin.flipperSDKVersion = pluginDetails.flipperSDKVersion;
plugin.details = pluginDetails;
// set values from package.json as static variables on class
@@ -289,5 +296,6 @@ const requirePluginInternal = (
plugin[key] = plugin[key] || pluginDetails[key as keyof PluginDetails];
}
});
}
return plugin;
};

View File

@@ -113,7 +113,6 @@ export abstract class FlipperBasePlugin<
static category: string | null = null;
static id: string = '';
static packageName: string = '';
static flipperSDKVersion: string | undefined = undefined;
static version: string = '';
static icon: string | null = null;
static gatekeeper: string | null = null;

View File

@@ -64,6 +64,12 @@ export class FlipperPluginInstance {
}
}
/**
* A sandy plugin definitions represents a loaded plugin definition, storing two things:
* the loaded JS module, and the meta data (typically coming from package.json).
*
* Also delegates some of the standard plugin functionality to have a similar public static api as FlipperPlugin
*/
export class SandyPluginDefinition {
id: string;
module: FlipperPluginModule;
@@ -86,12 +92,12 @@ export class SandyPluginDefinition {
this.details = details;
if (!module.plugin || typeof module.plugin !== 'function') {
throw new Error(
`Sandy plugin ${this.id} doesn't export a named function called 'plugin'`,
`Flipper plugin '${this.id}' should export named function called 'plugin'`,
);
}
if (!module.Component || typeof module.Component !== 'function') {
throw new Error(
`Sandy plugin ${this.id} doesn't export a named function called 'Component'`,
`Flipper plugin '${this.id}' should export named function called 'Component'`,
);
}
this.module = module;