Move app/src (mostly) to flipper-ui-core/src
Summary: This diff moves all UI code from app/src to app/flipper-ui-core. That is now slightly too much (e.g. node deps are not removed yet), but from here it should be easier to move things out again, as I don't want this diff to be open for too long to avoid too much merge conflicts. * But at least flipper-ui-core is Electron free :) * Killed all cross module imports as well, as they where now even more in the way * Some unit test needed some changes, most not too big (but emotion hashes got renumbered in the snapshots, feel free to ignore that) * Found some files that were actually meaningless (tsconfig in plugins, WatchTools files, that start generating compile errors, removed those Follow up work: * make flipper-ui-core configurable, and wire up flipper-server-core in Electron instead of here * remove node deps (aigoncharov) * figure out correct place to load GKs, plugins, make intern requests etc., and move to the correct module * clean up deps Reviewed By: aigoncharov Differential Revision: D32427722 fbshipit-source-id: 14fe92e1ceb15b9dcf7bece367c8ab92df927a70
This commit is contained in:
committed by
Facebook GitHub Bot
parent
54b7ce9308
commit
7e50c0466a
261
desktop/flipper-ui-core/src/test-utils/MockFlipper.tsx
Normal file
261
desktop/flipper-ui-core/src/test-utils/MockFlipper.tsx
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* 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 {createStore} from 'redux';
|
||||
import BaseDevice from '../devices/BaseDevice';
|
||||
import {createRootReducer} from '../reducers';
|
||||
import {Store} from '../reducers/index';
|
||||
import Client, {ClientConnection} from '../Client';
|
||||
import {
|
||||
Logger,
|
||||
buildClientId,
|
||||
FlipperServer,
|
||||
ClientResponseType,
|
||||
} from 'flipper-common';
|
||||
import {PluginDefinition} from '../plugin';
|
||||
import {registerPlugins} from '../reducers/plugins';
|
||||
import {getLogger} from 'flipper-common';
|
||||
import {initializeFlipperLibImplementation} from '../utils/flipperLibImplementation';
|
||||
import pluginManager from '../dispatcher/pluginManager';
|
||||
import {PluginDetails} from 'flipper-plugin-lib';
|
||||
import ArchivedDevice from '../devices/ArchivedDevice';
|
||||
import {ClientQuery, DeviceOS} from 'flipper-common';
|
||||
import {TestDevice} from './TestDevice';
|
||||
import {createFlipperServerMock} from './createFlipperServerMock';
|
||||
import {getRenderHostInstance} from '../RenderHost';
|
||||
|
||||
export interface AppOptions {
|
||||
plugins?: PluginDefinition[];
|
||||
}
|
||||
|
||||
export interface ClientOptions {
|
||||
name?: string;
|
||||
supportedPlugins?: string[];
|
||||
backgroundPlugins?: string[];
|
||||
onSend?: (pluginId: string, method: string, params?: object) => any;
|
||||
query?: ClientQuery;
|
||||
skipRegister?: boolean;
|
||||
}
|
||||
|
||||
export interface DeviceOptions {
|
||||
serial?: string;
|
||||
isSupportedByPlugin?: (p: PluginDetails) => boolean;
|
||||
archived?: boolean;
|
||||
os?: DeviceOS;
|
||||
}
|
||||
|
||||
export default class MockFlipper {
|
||||
private unsubscribePluginManager!: () => Promise<void>;
|
||||
private _store!: Store;
|
||||
private _logger!: Logger;
|
||||
private _devices: BaseDevice[] = [];
|
||||
private _clients: Client[] = [];
|
||||
private _deviceCounter: number = 0;
|
||||
private _clientCounter: number = 0;
|
||||
flipperServer: FlipperServer = createFlipperServerMock();
|
||||
|
||||
public get store(): Store {
|
||||
return this._store;
|
||||
}
|
||||
|
||||
public get logger(): Logger {
|
||||
return this._logger;
|
||||
}
|
||||
|
||||
public get devices(): ReadonlyArray<BaseDevice> {
|
||||
return this._devices;
|
||||
}
|
||||
|
||||
public get clients(): ReadonlyArray<Client> {
|
||||
return this._clients;
|
||||
}
|
||||
|
||||
public get dispatch() {
|
||||
return this._store.dispatch;
|
||||
}
|
||||
|
||||
public getState() {
|
||||
return this._store.getState();
|
||||
}
|
||||
|
||||
public async init({plugins}: AppOptions = {}) {
|
||||
this._store = createStore(createRootReducer());
|
||||
this._logger = getLogger();
|
||||
this.unsubscribePluginManager = pluginManager(this._store, this._logger, {
|
||||
runSideEffectsSynchronously: true,
|
||||
});
|
||||
initializeFlipperLibImplementation(
|
||||
getRenderHostInstance(),
|
||||
this._store,
|
||||
this._logger,
|
||||
);
|
||||
this._store.dispatch(registerPlugins(plugins ?? []));
|
||||
this._store.dispatch({
|
||||
type: 'SET_FLIPPER_SERVER',
|
||||
payload: this.flipperServer,
|
||||
});
|
||||
}
|
||||
|
||||
public async initWithDeviceAndClient(
|
||||
{
|
||||
appOptions = {},
|
||||
deviceOptions = {},
|
||||
clientOptions = {},
|
||||
}: {
|
||||
appOptions?: AppOptions;
|
||||
deviceOptions?: DeviceOptions;
|
||||
clientOptions?: ClientOptions;
|
||||
} = {appOptions: {}, deviceOptions: {}, clientOptions: {}},
|
||||
): Promise<{flipper: MockFlipper; device: BaseDevice; client: Client}> {
|
||||
await this.init(appOptions);
|
||||
const device = this.createDevice(deviceOptions);
|
||||
const client = await this.createClient(device, clientOptions);
|
||||
return {
|
||||
flipper: this,
|
||||
device,
|
||||
client,
|
||||
};
|
||||
}
|
||||
|
||||
public async destroy() {
|
||||
this.unsubscribePluginManager && this.unsubscribePluginManager();
|
||||
}
|
||||
|
||||
public createDevice({
|
||||
serial,
|
||||
isSupportedByPlugin,
|
||||
archived,
|
||||
os,
|
||||
}: DeviceOptions = {}): BaseDevice {
|
||||
const s = serial ?? `serial_${++this._deviceCounter}`;
|
||||
const device = archived
|
||||
? new ArchivedDevice({
|
||||
serial: s,
|
||||
deviceType: 'emulator',
|
||||
title: 'archived device',
|
||||
os: 'Android',
|
||||
})
|
||||
: new TestDevice(s, 'physical', 'MockAndroidDevice', os ?? 'Android');
|
||||
device.supportsPlugin = !isSupportedByPlugin
|
||||
? () => true
|
||||
: isSupportedByPlugin;
|
||||
this.loadDevice(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
public loadDevice(device: BaseDevice) {
|
||||
this._store.dispatch({
|
||||
type: 'REGISTER_DEVICE',
|
||||
payload: device,
|
||||
});
|
||||
device.loadDevicePlugins(
|
||||
this._store.getState().plugins.devicePlugins,
|
||||
this.store.getState().connections.enabledDevicePlugins,
|
||||
);
|
||||
this._devices.push(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
public async createClient(
|
||||
device: BaseDevice,
|
||||
{
|
||||
name,
|
||||
supportedPlugins,
|
||||
backgroundPlugins,
|
||||
onSend,
|
||||
skipRegister,
|
||||
query,
|
||||
}: ClientOptions = {},
|
||||
): Promise<Client> {
|
||||
if (!this._devices.includes(device)) {
|
||||
throw new Error('The provided device does not exist');
|
||||
}
|
||||
query = query ?? {
|
||||
app: name ?? `serial_${++this._clientCounter}`,
|
||||
os: 'Android',
|
||||
device: device.title,
|
||||
device_id: device.serial,
|
||||
sdk_version: 4,
|
||||
};
|
||||
const id = buildClientId({
|
||||
app: query.app,
|
||||
os: query.os,
|
||||
device: query.device,
|
||||
device_id: query.device_id,
|
||||
});
|
||||
supportedPlugins =
|
||||
supportedPlugins ??
|
||||
[...this._store.getState().plugins.clientPlugins.values()].map(
|
||||
(p) => p.id,
|
||||
);
|
||||
const client = new Client(
|
||||
id,
|
||||
query,
|
||||
device.isArchived ? null : createStubConnection(),
|
||||
this._logger,
|
||||
this._store,
|
||||
new Set(supportedPlugins),
|
||||
device,
|
||||
);
|
||||
client.rawCall = async (
|
||||
method: string,
|
||||
_fromPlugin: boolean,
|
||||
params: any,
|
||||
): Promise<any> => {
|
||||
const intercepted = onSend?.(method, params);
|
||||
if (intercepted !== undefined) {
|
||||
return intercepted;
|
||||
}
|
||||
switch (method) {
|
||||
case 'getPlugins':
|
||||
// assuming this plugin supports all plugins for now
|
||||
return {
|
||||
plugins: supportedPlugins,
|
||||
};
|
||||
case 'getBackgroundPlugins':
|
||||
return {
|
||||
plugins: backgroundPlugins ?? [],
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Test client doesn't support rawCall method '${method}'`,
|
||||
);
|
||||
}
|
||||
};
|
||||
client.rawSend = jest.fn();
|
||||
if (!device.isArchived) {
|
||||
await client.init();
|
||||
} else {
|
||||
await client.initFromImport({});
|
||||
}
|
||||
|
||||
// As convenience, by default we select the new client, star the plugin, and select it
|
||||
if (!skipRegister) {
|
||||
this._store.dispatch({
|
||||
type: 'NEW_CLIENT',
|
||||
payload: client,
|
||||
});
|
||||
}
|
||||
|
||||
this._clients.push(client);
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
function createStubConnection(): ClientConnection {
|
||||
return {
|
||||
send(_: any) {
|
||||
throw new Error('Should not be called in test');
|
||||
},
|
||||
sendExpectResponse(_: any): Promise<ClientResponseType> {
|
||||
throw new Error('Should not be called in test');
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user