Reviewed By: nikoant Differential Revision: D28064540 fbshipit-source-id: 43f05c4348a33e9633751bb9f69cd8d17ddd13c4
246 lines
6.3 KiB
TypeScript
246 lines
6.3 KiB
TypeScript
/**
|
|
* 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 React from 'react';
|
|
import {Provider} from 'react-redux';
|
|
import {
|
|
render,
|
|
RenderResult,
|
|
act as testingLibAct,
|
|
} from '@testing-library/react';
|
|
import {queries} from '@testing-library/dom';
|
|
|
|
import {
|
|
selectPlugin,
|
|
selectDevice,
|
|
selectClient,
|
|
} from '../reducers/connections';
|
|
import BaseDevice from '../devices/BaseDevice';
|
|
|
|
import {Store} from '../reducers/index';
|
|
import Client, {ClientQuery} from '../Client';
|
|
|
|
import {Logger} from '../fb-interfaces/Logger';
|
|
import {PluginDefinition} from '../plugin';
|
|
import PluginContainer from '../PluginContainer';
|
|
import {getPluginKey, isDevicePluginDefinition} from '../utils/pluginUtils';
|
|
import MockFlipper from './MockFlipper';
|
|
import {switchPlugin} from '../reducers/pluginManager';
|
|
|
|
export type MockFlipperResult = {
|
|
client: Client;
|
|
device: BaseDevice;
|
|
store: Store;
|
|
pluginKey: string;
|
|
sendError(error: any, client?: Client): void;
|
|
sendMessage(method: string, params: any, client?: Client): void;
|
|
createDevice(serial: string): BaseDevice;
|
|
createClient(
|
|
device: BaseDevice,
|
|
name: string,
|
|
query?: ClientQuery,
|
|
skipRegister?: boolean,
|
|
): Promise<Client>;
|
|
logger: Logger;
|
|
togglePlugin(plugin?: string): void;
|
|
};
|
|
|
|
type MockOptions = Partial<{
|
|
/**
|
|
* can be used to intercept outgoing calls. If it returns undefined
|
|
* the base implementation will be used
|
|
*/
|
|
onSend?: (pluginId: string, method: string, params?: object) => any;
|
|
additionalPlugins?: PluginDefinition[];
|
|
dontEnableAdditionalPlugins?: true;
|
|
asBackgroundPlugin?: true;
|
|
supportedPlugins?: string[];
|
|
device?: BaseDevice;
|
|
archivedDevice?: boolean;
|
|
}>;
|
|
|
|
function isPluginEnabled(
|
|
store: Store,
|
|
pluginClazz: PluginDefinition,
|
|
selectedApp: string,
|
|
) {
|
|
return (
|
|
(!isDevicePluginDefinition(pluginClazz) &&
|
|
store
|
|
.getState()
|
|
.connections.enabledPlugins[selectedApp]?.includes(pluginClazz.id)) ||
|
|
(isDevicePluginDefinition(pluginClazz) &&
|
|
store.getState().connections.enabledDevicePlugins.has(pluginClazz.id))
|
|
);
|
|
}
|
|
|
|
export async function createMockFlipperWithPlugin(
|
|
pluginClazz: PluginDefinition,
|
|
options?: MockOptions,
|
|
): Promise<MockFlipperResult> {
|
|
const mockFlipper = new MockFlipper();
|
|
await mockFlipper.init({
|
|
plugins: [pluginClazz, ...(options?.additionalPlugins ?? [])],
|
|
});
|
|
const logger = mockFlipper.logger;
|
|
const store = mockFlipper.store;
|
|
|
|
const createDevice = (serial: string, archived?: boolean) =>
|
|
mockFlipper.createDevice({serial, archived});
|
|
const createClient = async (
|
|
device: BaseDevice,
|
|
name: string,
|
|
query?: ClientQuery,
|
|
skipRegister?: boolean,
|
|
) => {
|
|
const client = await mockFlipper.createClient(device, {
|
|
name,
|
|
query,
|
|
skipRegister,
|
|
onSend: options?.onSend,
|
|
supportedPlugins: options?.supportedPlugins,
|
|
backgroundPlugins: options?.asBackgroundPlugin ? [pluginClazz.id] : [],
|
|
});
|
|
// enable the plugin
|
|
if (!isPluginEnabled(store, pluginClazz, name)) {
|
|
store.dispatch(
|
|
switchPlugin({
|
|
plugin: pluginClazz,
|
|
selectedApp: client.query.app,
|
|
}),
|
|
);
|
|
}
|
|
if (!options?.dontEnableAdditionalPlugins) {
|
|
options?.additionalPlugins?.forEach((plugin) => {
|
|
if (!isPluginEnabled(store, plugin, name)) {
|
|
store.dispatch(
|
|
switchPlugin({
|
|
plugin,
|
|
selectedApp: client.query.app,
|
|
}),
|
|
);
|
|
}
|
|
});
|
|
}
|
|
return client;
|
|
};
|
|
|
|
const device = options?.device
|
|
? mockFlipper.loadDevice(options?.device)
|
|
: createDevice('serial', options?.archivedDevice);
|
|
const client = await createClient(device, 'TestApp');
|
|
|
|
store.dispatch(selectDevice(device));
|
|
store.dispatch(selectClient(client.id));
|
|
|
|
store.dispatch(
|
|
selectPlugin({
|
|
selectedPlugin: pluginClazz.id,
|
|
selectedApp: client.query.app,
|
|
deepLinkPayload: null,
|
|
selectedDevice: device,
|
|
}),
|
|
);
|
|
|
|
return {
|
|
client,
|
|
device: device as any,
|
|
store,
|
|
sendError(error: any, actualClient = client) {
|
|
actualClient.onMessage(
|
|
JSON.stringify({
|
|
error,
|
|
}),
|
|
);
|
|
},
|
|
sendMessage(method, params, actualClient = client) {
|
|
actualClient.onMessage(
|
|
JSON.stringify({
|
|
method: 'execute',
|
|
params: {
|
|
api: pluginClazz.id,
|
|
method,
|
|
params,
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
createDevice,
|
|
createClient,
|
|
logger,
|
|
pluginKey: getPluginKey(client.id, device, pluginClazz.id),
|
|
togglePlugin(id?: string) {
|
|
const plugin = id
|
|
? store.getState().plugins.clientPlugins.get(id) ??
|
|
store.getState().plugins.devicePlugins.get(id)
|
|
: pluginClazz;
|
|
if (!plugin) {
|
|
throw new Error('unknown plugin ' + id);
|
|
}
|
|
store.dispatch(
|
|
switchPlugin({
|
|
plugin,
|
|
selectedApp: client.query.app,
|
|
}),
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
type Renderer = RenderResult<typeof queries>;
|
|
|
|
export async function renderMockFlipperWithPlugin(
|
|
pluginClazz: PluginDefinition,
|
|
options?: MockOptions,
|
|
): Promise<
|
|
MockFlipperResult & {
|
|
renderer: Renderer;
|
|
act: (cb: () => void) => void;
|
|
}
|
|
> {
|
|
const args = await createMockFlipperWithPlugin(pluginClazz, options);
|
|
|
|
function selectTestPlugin(store: Store, client: Client) {
|
|
store.dispatch(
|
|
selectPlugin(
|
|
isDevicePluginDefinition(pluginClazz)
|
|
? {
|
|
selectedPlugin: pluginClazz.id,
|
|
selectedApp: null,
|
|
deepLinkPayload: null,
|
|
selectedDevice: store.getState().connections.selectedDevice!,
|
|
}
|
|
: {
|
|
selectedPlugin: pluginClazz.id,
|
|
selectedApp: client.query.app,
|
|
deepLinkPayload: null,
|
|
selectedDevice: store.getState().connections.selectedDevice!,
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
selectTestPlugin(args.store, args.client);
|
|
|
|
const renderer = render(
|
|
<Provider store={args.store}>
|
|
<PluginContainer logger={args.logger} />
|
|
</Provider>,
|
|
);
|
|
|
|
return {
|
|
...args,
|
|
renderer: renderer as any,
|
|
act(cb) {
|
|
testingLibAct(cb);
|
|
args.client.flushMessageBuffer();
|
|
},
|
|
};
|
|
}
|