flipper-pkg template will now use sandy
Summary: This diff updates plugin scaffolding by using Sandy and closely following the internal Scarf templates (see D24949452, D24949452) By using `flipper-plugin`, it is now also possible to write unit tests for a plugin, and the default infra for that is generated (babel / jest) For now there is still a dependency on `flipper` to support fancy components not yet available in Sandy, this will be updated in the future: T79632585 Changelog: `flipper-pkg init` now uses the new Sandy plugin infrastructure ant Ant.design component system Reviewed By: nikoant Differential Revision: D24950080 fbshipit-source-id: afc5e7ac728b20cb84fdbbdcb76cd45968736c01
This commit is contained in:
committed by
Facebook GitHub Bot
parent
69504252de
commit
dc82ec2885
@@ -43,6 +43,14 @@ test('It generates the correct files', async () => {
|
|||||||
Object {
|
Object {
|
||||||
"/dev/null/.gitignore": "node_modules
|
"/dev/null/.gitignore": "node_modules
|
||||||
dist/
|
dist/
|
||||||
|
",
|
||||||
|
"/dev/null/babel.config.js": "module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-typescript',
|
||||||
|
'@babel/preset-react',
|
||||||
|
['@babel/preset-env', {targets: {node: 'current'}}]
|
||||||
|
],
|
||||||
|
};
|
||||||
",
|
",
|
||||||
"/dev/null/package.json": "{
|
"/dev/null/package.json": "{
|
||||||
\\"$schema\\": \\"https://fbflipper.com/schemas/plugin-package/v2.json\\",
|
\\"$schema\\": \\"https://fbflipper.com/schemas/plugin-package/v2.json\\",
|
||||||
@@ -61,65 +69,121 @@ test('It generates the correct files', async () => {
|
|||||||
\\"lint\\": \\"flipper-pkg lint\\",
|
\\"lint\\": \\"flipper-pkg lint\\",
|
||||||
\\"prepack\\": \\"flipper-pkg lint && flipper-pkg bundle\\",
|
\\"prepack\\": \\"flipper-pkg lint && flipper-pkg bundle\\",
|
||||||
\\"build\\": \\"flipper-pkg bundle\\",
|
\\"build\\": \\"flipper-pkg bundle\\",
|
||||||
\\"watch\\": \\"flipper-pkg bundle --watch\\"
|
\\"watch\\": \\"flipper-pkg bundle --watch\\",
|
||||||
|
\\"test\\": \\"jest\\"
|
||||||
},
|
},
|
||||||
\\"peerDependencies\\": {
|
\\"peerDependencies\\": {
|
||||||
\\"flipper\\": \\"latest\\"
|
\\"flipper\\": \\"latest\\",
|
||||||
|
\\"flipper-plugin\\": \\"latest\\",
|
||||||
|
\\"antd\\": \\"latest\\"
|
||||||
},
|
},
|
||||||
\\"devDependencies\\": {
|
\\"devDependencies\\": {
|
||||||
|
\\"@babel/preset-react\\": \\"latest\\",
|
||||||
|
\\"@babel/preset-typescript\\": \\"latest\\",
|
||||||
|
\\"@types/jest\\": \\"latest\\",
|
||||||
\\"@types/react\\": \\"latest\\",
|
\\"@types/react\\": \\"latest\\",
|
||||||
\\"@types/react-dom\\": \\"latest\\",
|
\\"@types/react-dom\\": \\"latest\\",
|
||||||
|
\\"antd\\": \\"latest\\",
|
||||||
\\"flipper\\": \\"latest\\",
|
\\"flipper\\": \\"latest\\",
|
||||||
\\"flipper-pkg\\": \\"latest\\"
|
\\"flipper-plugin\\": \\"latest\\",
|
||||||
|
\\"flipper-pkg\\": \\"latest\\",
|
||||||
|
\\"jest\\": \\"latest\\"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
",
|
||||||
|
"/dev/null/src/__tests__/test.spec.tsx": "import {TestUtils} from 'flipper-plugin';
|
||||||
|
import * as Plugin from '..';
|
||||||
|
|
||||||
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
// API: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
test('It can store data', () => {
|
||||||
|
const {instance, sendEvent} = TestUtils.startPlugin(Plugin);
|
||||||
|
|
||||||
|
expect(instance.data.get()).toEqual({});
|
||||||
|
|
||||||
|
sendEvent('newData', {id: 'firstID'});
|
||||||
|
sendEvent('newData', {id: 'secondID'});
|
||||||
|
|
||||||
|
expect(instance.data.get()).toMatchInlineSnapshot(\`
|
||||||
|
Object {
|
||||||
|
\\"firstID\\": Object {
|
||||||
|
\\"id\\": \\"firstID\\",
|
||||||
|
},
|
||||||
|
\\"secondID\\": Object {
|
||||||
|
\\"id\\": \\"secondID\\",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
\`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
// API: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
test('It can render data', async () => {
|
||||||
|
const {instance, renderer, sendEvent} = TestUtils.renderPlugin(Plugin);
|
||||||
|
|
||||||
|
expect(instance.data.get()).toEqual({});
|
||||||
|
|
||||||
|
sendEvent('newData', {id: 'firstID'});
|
||||||
|
sendEvent('newData', {id: 'secondID'});
|
||||||
|
|
||||||
|
expect(await renderer.findByTestId('firstID')).not.toBeNull();
|
||||||
|
expect(await renderer.findByTestId('secondID')).toMatchInlineSnapshot(\`
|
||||||
|
<pre
|
||||||
|
data-testid=\\"secondID\\"
|
||||||
|
>
|
||||||
|
{\\"id\\":\\"secondID\\"}
|
||||||
|
</pre>
|
||||||
|
\`);
|
||||||
|
});
|
||||||
",
|
",
|
||||||
"/dev/null/src/index.tsx": "import React from 'react';
|
"/dev/null/src/index.tsx": "import React from 'react';
|
||||||
import {FlipperPlugin, View, KeyboardActions} from 'flipper';
|
import {PluginClient, usePlugin, createState, useValue, Layout} from 'flipper-plugin';
|
||||||
|
|
||||||
type State = {};
|
type Data = {
|
||||||
|
id: string;
|
||||||
type Data = {};
|
message?: string;
|
||||||
|
|
||||||
type PersistedState = {
|
|
||||||
data: Array<Data>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class extends FlipperPlugin<State, any, PersistedState> {
|
type Events = {
|
||||||
static keyboardActions: KeyboardActions = ['clear'];
|
newData: Data;
|
||||||
|
};
|
||||||
|
|
||||||
static defaultPersistedState: PersistedState = {
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#creating-a-first-plugin
|
||||||
data: [],
|
// API: https://fbflipper.com/docs/extending/flipper-plugin#pluginclient
|
||||||
};
|
export function plugin(client: PluginClient<Events, {}>) {
|
||||||
|
const data = createState<Record<string, Data>>({}, {persist: 'data'});
|
||||||
|
|
||||||
static persistedStateReducer = (
|
client.onMessage('newData', (newData) => {
|
||||||
persistedState: PersistedState,
|
data.update((draft) => {
|
||||||
method: string,
|
draft[newData.id] = newData;
|
||||||
data: Data,
|
});
|
||||||
): PersistedState => {
|
});
|
||||||
return {
|
|
||||||
...persistedState,
|
|
||||||
data: persistedState.data.concat([data]),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {};
|
client.addMenuEntry({
|
||||||
|
action: 'clear',
|
||||||
|
handler: async () => {
|
||||||
|
data.set({});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
onKeyboardAction = (action: string) => {
|
return {data};
|
||||||
if (action === 'clear') {
|
}
|
||||||
this.props.setPersistedState({data: []});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#building-a-user-interface-for-the-plugin
|
||||||
return (
|
// API: https://fbflipper.com/docs/extending/flipper-plugin#react-hooks
|
||||||
<View scrollable>
|
export function Component() {
|
||||||
{this.props.persistedState.data.map((d) => (
|
const instance = usePlugin(plugin);
|
||||||
<div>{JSON.stringify(d, null, 2)}<hr/></div>
|
const data = useValue(instance.data);
|
||||||
))}
|
|
||||||
</View>
|
return (
|
||||||
)
|
<Layout.ScrollContainer>
|
||||||
}
|
{Object.entries(data).map(([id, d]) => (
|
||||||
|
<pre key={id} data-testid={id}>
|
||||||
|
{JSON.stringify(d)}
|
||||||
|
</pre>
|
||||||
|
))}
|
||||||
|
</Layout.ScrollContainer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
"/dev/null/tsconfig.json": "{
|
"/dev/null/tsconfig.json": "{
|
||||||
|
|||||||
7
desktop/pkg/templates/plugin/babel.config.js.template
Normal file
7
desktop/pkg/templates/plugin/babel.config.js.template
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-typescript',
|
||||||
|
'@babel/preset-react',
|
||||||
|
['@babel/preset-env', {targets: {node: 'current'}}]
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -15,15 +15,24 @@
|
|||||||
"lint": "flipper-pkg lint",
|
"lint": "flipper-pkg lint",
|
||||||
"prepack": "flipper-pkg lint && flipper-pkg bundle",
|
"prepack": "flipper-pkg lint && flipper-pkg bundle",
|
||||||
"build": "flipper-pkg bundle",
|
"build": "flipper-pkg bundle",
|
||||||
"watch": "flipper-pkg bundle --watch"
|
"watch": "flipper-pkg bundle --watch",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"flipper": "latest"
|
"flipper": "latest",
|
||||||
|
"flipper-plugin": "latest",
|
||||||
|
"antd": "latest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/preset-react": "latest",
|
||||||
|
"@babel/preset-typescript": "latest",
|
||||||
|
"@types/jest": "latest",
|
||||||
"@types/react": "latest",
|
"@types/react": "latest",
|
||||||
"@types/react-dom": "latest",
|
"@types/react-dom": "latest",
|
||||||
|
"antd": "latest",
|
||||||
"flipper": "latest",
|
"flipper": "latest",
|
||||||
"flipper-pkg": "latest"
|
"flipper-plugin": "latest",
|
||||||
|
"flipper-pkg": "latest",
|
||||||
|
"jest": "latest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import {TestUtils} from 'flipper-plugin';
|
||||||
|
import * as Plugin from '..';
|
||||||
|
|
||||||
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
// API: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
test('It can store data', () => {
|
||||||
|
const {instance, sendEvent} = TestUtils.startPlugin(Plugin);
|
||||||
|
|
||||||
|
expect(instance.data.get()).toEqual({});
|
||||||
|
|
||||||
|
sendEvent('newData', {id: 'firstID'});
|
||||||
|
sendEvent('newData', {id: 'secondID'});
|
||||||
|
|
||||||
|
expect(instance.data.get()).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"firstID": Object {
|
||||||
|
"id": "firstID",
|
||||||
|
},
|
||||||
|
"secondID": Object {
|
||||||
|
"id": "secondID",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
// API: https://fbflipper.com/docs/extending/desktop-plugins#testing-plugin-logic
|
||||||
|
test('It can render data', async () => {
|
||||||
|
const {instance, renderer, sendEvent} = TestUtils.renderPlugin(Plugin);
|
||||||
|
|
||||||
|
expect(instance.data.get()).toEqual({});
|
||||||
|
|
||||||
|
sendEvent('newData', {id: 'firstID'});
|
||||||
|
sendEvent('newData', {id: 'secondID'});
|
||||||
|
|
||||||
|
expect(await renderer.findByTestId('firstID')).not.toBeNull();
|
||||||
|
expect(await renderer.findByTestId('secondID')).toMatchInlineSnapshot(`
|
||||||
|
<pre
|
||||||
|
data-testid="secondID"
|
||||||
|
>
|
||||||
|
{"id":"secondID"}
|
||||||
|
</pre>
|
||||||
|
`);
|
||||||
|
});
|
||||||
@@ -1,47 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {FlipperPlugin, View, KeyboardActions} from 'flipper';
|
import {PluginClient, usePlugin, createState, useValue, Layout} from 'flipper-plugin';
|
||||||
|
|
||||||
type State = {};
|
type Data = {
|
||||||
|
id: string;
|
||||||
type Data = {};
|
message?: string;
|
||||||
|
|
||||||
type PersistedState = {
|
|
||||||
data: Array<Data>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class extends FlipperPlugin<State, any, PersistedState> {
|
type Events = {
|
||||||
static keyboardActions: KeyboardActions = ['clear'];
|
newData: Data;
|
||||||
|
};
|
||||||
|
|
||||||
static defaultPersistedState: PersistedState = {
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#creating-a-first-plugin
|
||||||
data: [],
|
// API: https://fbflipper.com/docs/extending/flipper-plugin#pluginclient
|
||||||
};
|
export function plugin(client: PluginClient<Events, {}>) {
|
||||||
|
const data = createState<Record<string, Data>>({}, {persist: 'data'});
|
||||||
|
|
||||||
static persistedStateReducer = (
|
client.onMessage('newData', (newData) => {
|
||||||
persistedState: PersistedState,
|
data.update((draft) => {
|
||||||
method: string,
|
draft[newData.id] = newData;
|
||||||
data: Data,
|
});
|
||||||
): PersistedState => {
|
});
|
||||||
return {
|
|
||||||
...persistedState,
|
|
||||||
data: persistedState.data.concat([data]),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {};
|
client.addMenuEntry({
|
||||||
|
action: 'clear',
|
||||||
|
handler: async () => {
|
||||||
|
data.set({});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
onKeyboardAction = (action: string) => {
|
return {data};
|
||||||
if (action === 'clear') {
|
}
|
||||||
this.props.setPersistedState({data: []});
|
|
||||||
}
|
// Read more: https://fbflipper.com/docs/extending/desktop-plugins#building-a-user-interface-for-the-plugin
|
||||||
};
|
// API: https://fbflipper.com/docs/extending/flipper-plugin#react-hooks
|
||||||
|
export function Component() {
|
||||||
render() {
|
const instance = usePlugin(plugin);
|
||||||
return (
|
const data = useValue(instance.data);
|
||||||
<View scrollable>
|
|
||||||
{this.props.persistedState.data.map((d) => (
|
return (
|
||||||
<div>{JSON.stringify(d, null, 2)}<hr/></div>
|
<Layout.ScrollContainer>
|
||||||
))}
|
{Object.entries(data).map(([id, d]) => (
|
||||||
</View>
|
<pre key={id} data-testid={id}>
|
||||||
)
|
{JSON.stringify(d)}
|
||||||
}
|
</pre>
|
||||||
|
))}
|
||||||
|
</Layout.ScrollContainer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user