Support custom data processing during import

Summary: Per title, this allows for pre-processing data after it is deserialized and before it is stored in the plugin

Reviewed By: nikoant

Differential Revision: D26126423

fbshipit-source-id: bc08a6ab205d2a0d551515563cd85a197595ddb2
This commit is contained in:
Michel Weststrate
2021-02-01 11:40:20 -08:00
committed by Facebook GitHub Bot
parent 34c915a739
commit f2ade40239
9 changed files with 340 additions and 21 deletions

View File

@@ -12,6 +12,8 @@ import * as testPlugin from './TestPlugin';
import {createState} from '../state/atom';
import {PluginClient} from '../plugin/Plugin';
import {DevicePluginClient} from '../plugin/DevicePlugin';
import mockConsole from 'jest-mock-console';
import {sleep} from '../utils/sleep';
test('it can start a plugin and lifecycle events', () => {
const {instance, ...p} = TestUtils.startPlugin(testPlugin);
@@ -217,16 +219,17 @@ test('plugins support non-serializable state', async () => {
});
test('plugins support restoring state', async () => {
const {exportState} = TestUtils.startPlugin(
const {exportState, instance} = TestUtils.startPlugin(
{
plugin() {
const field1 = createState(1, {persist: 'field1'});
const field2 = createState(2);
const field3 = createState(3, {persist: 'field3'});
expect(field1.get()).toBe('a');
expect(field2.get()).toBe(2);
expect(field3.get()).toBe('b');
return {};
return {
field1,
field2,
field3,
};
},
Component() {
return null;
@@ -236,6 +239,12 @@ test('plugins support restoring state', async () => {
initialState: {field1: 'a', field3: 'b'},
},
);
const {field1, field2, field3} = instance;
expect(field1.get()).toBe('a');
expect(field2.get()).toBe(2);
expect(field3.get()).toBe('b');
expect(exportState()).toEqual({field1: 'a', field3: 'b'});
});
@@ -256,6 +265,125 @@ test('plugins cannot use a persist key twice', async () => {
);
});
test('plugins can have custom import handler', () => {
const {instance} = TestUtils.startPlugin(
{
plugin(client: PluginClient) {
const field1 = createState(0);
const field2 = createState(0);
client.onImport((data) => {
field1.set(data.a);
field2.set(data.b);
});
return {field1, field2};
},
Component() {
return null;
},
},
{
initialState: {
a: 1,
b: 2,
},
},
);
expect(instance.field1.get()).toBe(1);
expect(instance.field2.get()).toBe(2);
});
test('plugins cannot combine import handler with persist option', async () => {
expect(() => {
TestUtils.startPlugin({
plugin(client: PluginClient) {
const field1 = createState(1, {persist: 'f1'});
const field2 = createState(1, {persist: 'f2'});
client.onImport(() => {});
return {field1, field2};
},
Component() {
return null;
},
});
}).toThrowErrorMatchingInlineSnapshot(
`"A custom onImport handler was defined for plugin 'TestPlugin', the 'persist' option of states f1, f2 should not be set."`,
);
});
test('plugins can handle import errors', async () => {
const restoreConsole = mockConsole();
let instance: any;
try {
instance = TestUtils.startPlugin(
{
plugin(client: PluginClient) {
const field1 = createState(0);
const field2 = createState(0);
client.onImport(() => {
throw new Error('Oops');
});
return {field1, field2};
},
Component() {
return null;
},
},
{
initialState: {
a: 1,
b: 2,
},
},
).instance;
// @ts-ignore
expect(console.error.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"Error occurred when importing date for plugin 'TestPlugin': 'Error: Oops",
[Error: Oops],
],
]
`);
} finally {
restoreConsole();
}
expect(instance.field1.get()).toBe(0);
expect(instance.field2.get()).toBe(0);
});
test('plugins can have custom export handler', async () => {
const {exportStateAsync} = TestUtils.startPlugin(
{
plugin(client: PluginClient) {
const field1 = createState(0, {persist: 'field1'});
client.onExport(async () => {
await sleep(10);
return {
b: 3,
};
});
return {field1};
},
Component() {
return null;
},
},
{
initialState: {
a: 1,
b: 2,
},
},
);
expect(await exportStateAsync()).toEqual({b: 3});
});
test('plugins can receive deeplinks', async () => {
const plugin = TestUtils.startPlugin({
plugin(client: PluginClient) {