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:
committed by
Facebook GitHub Bot
parent
1029a6c97c
commit
12ac29685d
24
desktop/app/src/dispatcher/__tests__/SandyTestPlugin.tsx
Normal file
24
desktop/app/src/dispatcher/__tests__/SandyTestPlugin.tsx
Normal 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>;
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import configureStore from 'redux-mock-store';
|
|||||||
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
|
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
|
||||||
import TestPlugin from './TestPlugin';
|
import TestPlugin from './TestPlugin';
|
||||||
import {resetConfigForTesting} from '../../utils/processConfig';
|
import {resetConfigForTesting} from '../../utils/processConfig';
|
||||||
|
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||||
|
|
||||||
const mockStore = configureStore<State, {}>([])(
|
const mockStore = configureStore<State, {}>([])(
|
||||||
reducers(undefined, {type: 'INIT'}),
|
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;
|
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'"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import * as FlipperPluginSDK from 'flipper-plugin';
|
|||||||
|
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import getPluginIndex from '../utils/getDefaultPluginsIndex';
|
import getPluginIndex from '../utils/getDefaultPluginsIndex';
|
||||||
|
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||||
|
|
||||||
const Paragraph = styled.p({
|
const Paragraph = styled.p({
|
||||||
marginBottom: '0.1em',
|
marginBottom: '0.1em',
|
||||||
@@ -271,23 +272,30 @@ const requirePluginInternal = (
|
|||||||
let plugin = pluginDetails.isDefault
|
let plugin = pluginDetails.isDefault
|
||||||
? defaultPluginsIndex[pluginDetails.name]
|
? defaultPluginsIndex[pluginDetails.name]
|
||||||
: reqFn(pluginDetails.entry);
|
: reqFn(pluginDetails.entry);
|
||||||
if (plugin.default) {
|
|
||||||
plugin = plugin.default;
|
|
||||||
}
|
|
||||||
if (!(plugin.prototype instanceof FlipperBasePlugin)) {
|
|
||||||
throw new Error(`Plugin ${plugin.name} is not a FlipperBasePlugin`);
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.id = plugin.id || pluginDetails.id;
|
if (pluginDetails.flipperSDKVersion) {
|
||||||
plugin.packageName = pluginDetails.name;
|
// Sandy plugin
|
||||||
plugin.flipperSDKVersion = pluginDetails.flipperSDKVersion;
|
// TODO: suppor device Plugins T68738317
|
||||||
plugin.details = pluginDetails;
|
return new SandyPluginDefinition(pluginDetails, plugin);
|
||||||
|
} else {
|
||||||
// set values from package.json as static variables on class
|
// classic plugin
|
||||||
Object.keys(pluginDetails).forEach((key) => {
|
if (plugin.default) {
|
||||||
if (key !== 'name' && key !== 'id') {
|
plugin = plugin.default;
|
||||||
plugin[key] = plugin[key] || pluginDetails[key as keyof PluginDetails];
|
|
||||||
}
|
}
|
||||||
});
|
if (!(plugin.prototype instanceof FlipperBasePlugin)) {
|
||||||
|
throw new Error(`Plugin ${plugin.name} is not a FlipperBasePlugin`);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.id = plugin.id || pluginDetails.id;
|
||||||
|
plugin.packageName = pluginDetails.name;
|
||||||
|
plugin.details = pluginDetails;
|
||||||
|
|
||||||
|
// set values from package.json as static variables on class
|
||||||
|
Object.keys(pluginDetails).forEach((key) => {
|
||||||
|
if (key !== 'name' && key !== 'id') {
|
||||||
|
plugin[key] = plugin[key] || pluginDetails[key as keyof PluginDetails];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return plugin;
|
return plugin;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ export abstract class FlipperBasePlugin<
|
|||||||
static category: string | null = null;
|
static category: string | null = null;
|
||||||
static id: string = '';
|
static id: string = '';
|
||||||
static packageName: string = '';
|
static packageName: string = '';
|
||||||
static flipperSDKVersion: string | undefined = undefined;
|
|
||||||
static version: string = '';
|
static version: string = '';
|
||||||
static icon: string | null = null;
|
static icon: string | null = null;
|
||||||
static gatekeeper: string | null = null;
|
static gatekeeper: string | null = null;
|
||||||
|
|||||||
@@ -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 {
|
export class SandyPluginDefinition {
|
||||||
id: string;
|
id: string;
|
||||||
module: FlipperPluginModule;
|
module: FlipperPluginModule;
|
||||||
@@ -86,12 +92,12 @@ export class SandyPluginDefinition {
|
|||||||
this.details = details;
|
this.details = details;
|
||||||
if (!module.plugin || typeof module.plugin !== 'function') {
|
if (!module.plugin || typeof module.plugin !== 'function') {
|
||||||
throw new Error(
|
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') {
|
if (!module.Component || typeof module.Component !== 'function') {
|
||||||
throw new Error(
|
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;
|
this.module = module;
|
||||||
|
|||||||
Reference in New Issue
Block a user