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:
Michel Weststrate
2021-11-16 05:25:40 -08:00
committed by Facebook GitHub Bot
parent 54b7ce9308
commit 7e50c0466a
293 changed files with 483 additions and 497 deletions

View 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');
},
};
}