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
85
desktop/flipper-ui-core/src/devices/ArchivedDevice.tsx
Normal file
85
desktop/flipper-ui-core/src/devices/ArchivedDevice.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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 BaseDevice from './BaseDevice';
|
||||
import type {DeviceOS, DeviceType} from 'flipper-plugin';
|
||||
import {DeviceShell} from './BaseDevice';
|
||||
import {SupportFormRequestDetailsState} from '../reducers/supportForm';
|
||||
|
||||
export default class ArchivedDevice extends BaseDevice {
|
||||
isArchived = true;
|
||||
|
||||
constructor(options: {
|
||||
serial: string;
|
||||
deviceType: DeviceType;
|
||||
title: string;
|
||||
os: DeviceOS;
|
||||
screenshotHandle?: string | null;
|
||||
source?: string;
|
||||
supportRequestDetails?: SupportFormRequestDetailsState;
|
||||
}) {
|
||||
super(
|
||||
{
|
||||
close() {},
|
||||
exec(command, ..._args: any[]) {
|
||||
throw new Error(
|
||||
`[Archived device] Cannot invoke command ${command} on an archived device`,
|
||||
);
|
||||
},
|
||||
on(event) {
|
||||
console.warn(
|
||||
`Cannot subscribe to server events from an Archived device: ${event}`,
|
||||
);
|
||||
},
|
||||
off() {},
|
||||
},
|
||||
{
|
||||
deviceType: options.deviceType,
|
||||
title: options.title,
|
||||
os: options.os,
|
||||
serial: options.serial,
|
||||
icon: 'box',
|
||||
},
|
||||
);
|
||||
this.connected.set(false);
|
||||
this.source = options.source || '';
|
||||
this.supportRequestDetails = options.supportRequestDetails;
|
||||
this.archivedScreenshotHandle = options.screenshotHandle ?? null;
|
||||
}
|
||||
|
||||
archivedScreenshotHandle: string | null;
|
||||
|
||||
displayTitle(): string {
|
||||
return `${this.title} ${this.source ? '(Imported)' : '(Offline)'}`;
|
||||
}
|
||||
|
||||
supportRequestDetails?: SupportFormRequestDetailsState;
|
||||
|
||||
spawnShell(): DeviceShell | undefined | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
getArchivedScreenshotHandle(): string | null {
|
||||
return this.archivedScreenshotHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async startLogging() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async stopLogging() {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
350
desktop/flipper-ui-core/src/devices/BaseDevice.tsx
Normal file
350
desktop/flipper-ui-core/src/devices/BaseDevice.tsx
Normal file
@@ -0,0 +1,350 @@
|
||||
/**
|
||||
* 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 stream from 'stream';
|
||||
import {
|
||||
Device,
|
||||
_SandyDevicePluginInstance,
|
||||
_SandyPluginDefinition,
|
||||
DeviceLogListener,
|
||||
Idler,
|
||||
createState,
|
||||
getFlipperLib,
|
||||
} from 'flipper-plugin';
|
||||
import {
|
||||
DeviceLogEntry,
|
||||
DeviceOS,
|
||||
DeviceType,
|
||||
DeviceDescription,
|
||||
FlipperServer,
|
||||
} from 'flipper-common';
|
||||
import {DeviceSpec, PluginDetails} from 'flipper-plugin-lib';
|
||||
import {getPluginKey} from '../utils/pluginKey';
|
||||
import {Base64} from 'js-base64';
|
||||
|
||||
export type DeviceShell = {
|
||||
stdout: stream.Readable;
|
||||
stderr: stream.Readable;
|
||||
stdin: stream.Writable;
|
||||
};
|
||||
|
||||
type PluginDefinition = _SandyPluginDefinition;
|
||||
type PluginMap = Map<string, PluginDefinition>;
|
||||
|
||||
export type DeviceExport = {
|
||||
os: DeviceOS;
|
||||
title: string;
|
||||
deviceType: DeviceType;
|
||||
serial: string;
|
||||
pluginStates: Record<string, any>;
|
||||
};
|
||||
|
||||
export default class BaseDevice implements Device {
|
||||
description: DeviceDescription;
|
||||
flipperServer: FlipperServer;
|
||||
isArchived = false;
|
||||
hasDevicePlugins = false; // true if there are device plugins for this device (not necessarily enabled)
|
||||
|
||||
constructor(flipperServer: FlipperServer, description: DeviceDescription) {
|
||||
this.flipperServer = flipperServer;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
get isConnected(): boolean {
|
||||
return this.connected.get();
|
||||
}
|
||||
|
||||
// operating system of this device
|
||||
get os() {
|
||||
return this.description.os;
|
||||
}
|
||||
|
||||
// human readable name for this device
|
||||
get title(): string {
|
||||
return this.description.title;
|
||||
}
|
||||
|
||||
// type of this device
|
||||
get deviceType() {
|
||||
return this.description.deviceType;
|
||||
}
|
||||
|
||||
// serial number for this device
|
||||
get serial() {
|
||||
return this.description.serial;
|
||||
}
|
||||
|
||||
// additional device specs used for plugin compatibility checks
|
||||
get specs(): DeviceSpec[] {
|
||||
return this.description.specs ?? [];
|
||||
}
|
||||
|
||||
// possible src of icon to display next to the device title
|
||||
get icon() {
|
||||
return this.description.icon;
|
||||
}
|
||||
|
||||
logListeners: Map<Symbol, DeviceLogListener> = new Map();
|
||||
|
||||
readonly connected = createState(true);
|
||||
|
||||
// if imported, stores the original source location
|
||||
source = '';
|
||||
|
||||
// TODO: ideally we don't want BasePlugin to know about the concept of plugins
|
||||
sandyPluginStates: Map<string, _SandyDevicePluginInstance> = new Map<
|
||||
string,
|
||||
_SandyDevicePluginInstance
|
||||
>();
|
||||
|
||||
supportsOS(os: DeviceOS) {
|
||||
return os.toLowerCase() === this.os.toLowerCase();
|
||||
}
|
||||
|
||||
displayTitle(): string {
|
||||
return this.connected.get() ? this.title : `${this.title} (Offline)`;
|
||||
}
|
||||
|
||||
async exportState(
|
||||
idler: Idler,
|
||||
onStatusMessage: (msg: string) => void,
|
||||
selectedPlugins: string[],
|
||||
): Promise<Record<string, any>> {
|
||||
const pluginStates: Record<string, any> = {};
|
||||
|
||||
for (const instance of this.sandyPluginStates.values()) {
|
||||
if (
|
||||
selectedPlugins.includes(instance.definition.id) &&
|
||||
instance.isPersistable()
|
||||
) {
|
||||
pluginStates[instance.definition.id] = await instance.exportState(
|
||||
idler,
|
||||
onStatusMessage,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return pluginStates;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
os: this.os,
|
||||
title: this.title,
|
||||
deviceType: this.deviceType,
|
||||
serial: this.serial,
|
||||
};
|
||||
}
|
||||
|
||||
private deviceLogEventHandler = (payload: {
|
||||
serial: string;
|
||||
entry: DeviceLogEntry;
|
||||
}) => {
|
||||
if (payload.serial === this.serial && this.logListeners.size > 0) {
|
||||
this.addLogEntry(payload.entry);
|
||||
}
|
||||
};
|
||||
|
||||
addLogEntry(entry: DeviceLogEntry) {
|
||||
this.logListeners.forEach((listener) => {
|
||||
// prevent breaking other listeners, if one listener doesn't work.
|
||||
try {
|
||||
listener(entry);
|
||||
} catch (e) {
|
||||
console.error(`Log listener exception:`, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async startLogging() {
|
||||
await this.flipperServer.exec('device-start-logging', this.serial);
|
||||
this.flipperServer.on('device-log', this.deviceLogEventHandler);
|
||||
}
|
||||
|
||||
stopLogging() {
|
||||
this.flipperServer.off('device-log', this.deviceLogEventHandler);
|
||||
return this.flipperServer.exec('device-stop-logging', this.serial);
|
||||
}
|
||||
|
||||
addLogListener(callback: DeviceLogListener): Symbol {
|
||||
if (this.logListeners.size === 0) {
|
||||
this.startLogging();
|
||||
}
|
||||
const id = Symbol();
|
||||
this.logListeners.set(id, callback);
|
||||
return id;
|
||||
}
|
||||
|
||||
removeLogListener(id: Symbol) {
|
||||
this.logListeners.delete(id);
|
||||
if (this.logListeners.size === 0) {
|
||||
this.stopLogging();
|
||||
}
|
||||
}
|
||||
|
||||
async navigateToLocation(location: string) {
|
||||
return this.flipperServer.exec('device-navigate', this.serial, location);
|
||||
}
|
||||
|
||||
async screenshotAvailable(): Promise<boolean> {
|
||||
if (this.isArchived) {
|
||||
return false;
|
||||
}
|
||||
return this.flipperServer.exec('device-supports-screenshot', this.serial);
|
||||
}
|
||||
|
||||
async screenshot(): Promise<Buffer> {
|
||||
if (this.isArchived) {
|
||||
return Buffer.from([]);
|
||||
}
|
||||
return Buffer.from(
|
||||
Base64.toUint8Array(
|
||||
await this.flipperServer.exec('device-take-screenshot', this.serial),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async screenCaptureAvailable(): Promise<boolean> {
|
||||
if (this.isArchived) {
|
||||
return false;
|
||||
}
|
||||
return this.flipperServer.exec(
|
||||
'device-supports-screencapture',
|
||||
this.serial,
|
||||
);
|
||||
}
|
||||
|
||||
async startScreenCapture(destination: string): Promise<void> {
|
||||
return this.flipperServer.exec(
|
||||
'device-start-screencapture',
|
||||
this.serial,
|
||||
destination,
|
||||
);
|
||||
}
|
||||
|
||||
async stopScreenCapture(): Promise<string | null> {
|
||||
return this.flipperServer.exec('device-stop-screencapture', this.serial);
|
||||
}
|
||||
|
||||
async executeShell(command: string): Promise<string> {
|
||||
return this.flipperServer.exec('device-shell-exec', this.serial, command);
|
||||
}
|
||||
|
||||
async sendMetroCommand(command: string): Promise<void> {
|
||||
return this.flipperServer.exec('metro-command', this.serial, command);
|
||||
}
|
||||
|
||||
async forwardPort(local: string, remote: string): Promise<boolean> {
|
||||
return this.flipperServer.exec(
|
||||
'device-forward-port',
|
||||
this.serial,
|
||||
local,
|
||||
remote,
|
||||
);
|
||||
}
|
||||
|
||||
async clearLogs() {
|
||||
return this.flipperServer.exec('device-clear-logs', this.serial);
|
||||
}
|
||||
|
||||
supportsPlugin(plugin: PluginDefinition | PluginDetails) {
|
||||
let pluginDetails: PluginDetails;
|
||||
if (plugin instanceof _SandyPluginDefinition) {
|
||||
pluginDetails = plugin.details;
|
||||
if (!pluginDetails.pluginType && !pluginDetails.supportedDevices) {
|
||||
// TODO T84453692: this branch is to support plugins defined with the legacy approach. Need to remove this branch after some transition period when
|
||||
// all the plugins will be migrated to the new approach with static compatibility metadata in package.json.
|
||||
if (plugin instanceof _SandyPluginDefinition) {
|
||||
return (
|
||||
plugin.isDevicePlugin &&
|
||||
(plugin.asDevicePluginModule().supportsDevice?.(this as any) ??
|
||||
false)
|
||||
);
|
||||
} else {
|
||||
return (plugin as any).supportsDevice(this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pluginDetails = plugin;
|
||||
}
|
||||
return (
|
||||
pluginDetails.pluginType === 'device' &&
|
||||
(!pluginDetails.supportedDevices ||
|
||||
pluginDetails.supportedDevices?.some(
|
||||
(d) =>
|
||||
(!d.os || d.os === this.os) &&
|
||||
(!d.type || d.type === this.deviceType) &&
|
||||
(d.archived === undefined || d.archived === this.isArchived) &&
|
||||
(!d.specs || d.specs.every((spec) => this.specs.includes(spec))),
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
loadDevicePlugins(
|
||||
devicePlugins: PluginMap,
|
||||
enabledDevicePlugins: Set<string>,
|
||||
pluginStates?: Record<string, any>,
|
||||
) {
|
||||
if (!devicePlugins) {
|
||||
return;
|
||||
}
|
||||
const plugins = Array.from(devicePlugins.values()).filter((p) =>
|
||||
enabledDevicePlugins?.has(p.id),
|
||||
);
|
||||
for (const plugin of plugins) {
|
||||
this.loadDevicePlugin(plugin, pluginStates?.[plugin.id]);
|
||||
}
|
||||
}
|
||||
|
||||
loadDevicePlugin(plugin: PluginDefinition, initialState?: any) {
|
||||
if (!this.supportsPlugin(plugin)) {
|
||||
return;
|
||||
}
|
||||
this.hasDevicePlugins = true;
|
||||
if (plugin instanceof _SandyPluginDefinition) {
|
||||
try {
|
||||
this.sandyPluginStates.set(
|
||||
plugin.id,
|
||||
new _SandyDevicePluginInstance(
|
||||
getFlipperLib(),
|
||||
plugin,
|
||||
this,
|
||||
// break circular dep, one of those days again...
|
||||
getPluginKey(undefined, {serial: this.serial}, plugin.id),
|
||||
initialState,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(`Failed to start device plugin '${plugin.id}': `, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unloadDevicePlugin(pluginId: string) {
|
||||
const instance = this.sandyPluginStates.get(pluginId);
|
||||
if (instance) {
|
||||
instance.destroy();
|
||||
this.sandyPluginStates.delete(pluginId);
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.logListeners.clear();
|
||||
this.stopLogging();
|
||||
this.connected.set(false);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.disconnect();
|
||||
this.sandyPluginStates.forEach((instance) => {
|
||||
instance.destroy();
|
||||
});
|
||||
this.sandyPluginStates.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* 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 * as DeviceTestPluginModule from '../../test-utils/DeviceTestPlugin';
|
||||
import {TestUtils, _SandyPluginDefinition} from 'flipper-plugin';
|
||||
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
|
||||
import {TestDevice} from '../../test-utils/TestDevice';
|
||||
import ArchivedDevice from '../../devices/ArchivedDevice';
|
||||
|
||||
const physicalDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'physicalDevicePlugin',
|
||||
name: 'flipper-plugin-physical-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'iOS',
|
||||
type: 'physical',
|
||||
archived: false,
|
||||
},
|
||||
{
|
||||
os: 'Android',
|
||||
type: 'physical',
|
||||
},
|
||||
],
|
||||
});
|
||||
const physicalDevicePlugin = new _SandyPluginDefinition(
|
||||
physicalDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const iosPhysicalDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'iosPhysicalDevicePlugin',
|
||||
name: 'flipper-plugin-ios-physical-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'iOS',
|
||||
type: 'physical',
|
||||
},
|
||||
],
|
||||
});
|
||||
const iosPhysicalDevicePlugin = new _SandyPluginDefinition(
|
||||
iosPhysicalDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const iosEmulatorlDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'iosEmulatorDevicePlugin',
|
||||
name: 'flipper-plugin-ios-emulator-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'iOS',
|
||||
type: 'emulator',
|
||||
},
|
||||
],
|
||||
});
|
||||
const iosEmulatorDevicePlugin = new _SandyPluginDefinition(
|
||||
iosEmulatorlDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
const androiKaiosPhysicalDevicePluginDetails =
|
||||
TestUtils.createMockPluginDetails({
|
||||
id: 'androidPhysicalDevicePlugin',
|
||||
name: 'flipper-plugin-android-physical-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'Android',
|
||||
type: 'physical',
|
||||
specs: ['KaiOS'],
|
||||
},
|
||||
],
|
||||
});
|
||||
const androidKaiosPhysicalDevicePlugin = new _SandyPluginDefinition(
|
||||
androiKaiosPhysicalDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const androidEmulatorlDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'androidEmulatorDevicePlugin',
|
||||
name: 'flipper-plugin-android-emulator-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'Android',
|
||||
type: 'emulator',
|
||||
},
|
||||
],
|
||||
});
|
||||
const androidEmulatorDevicePlugin = new _SandyPluginDefinition(
|
||||
androidEmulatorlDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const androidOnlyDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'androidEmulatorDevicePlugin',
|
||||
name: 'flipper-plugin-android-emulator-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'Android',
|
||||
},
|
||||
],
|
||||
});
|
||||
const androidOnlyDevicePlugin = new _SandyPluginDefinition(
|
||||
androidOnlyDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
test('ios physical device compatibility', () => {
|
||||
const device = new TestDevice('serial', 'physical', 'test device', 'iOS');
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('archived device compatibility', () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'physical',
|
||||
title: 'test device',
|
||||
os: 'iOS',
|
||||
screenshotHandle: null,
|
||||
});
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('android emulator device compatibility', () => {
|
||||
const device = new TestDevice('serial', 'emulator', 'test device', 'Android');
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('android KaiOS device compatibility', () => {
|
||||
const device = new TestDevice(
|
||||
'serial',
|
||||
'physical',
|
||||
'test device',
|
||||
'Android',
|
||||
['KaiOS'],
|
||||
);
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('android dummy device compatibility', () => {
|
||||
const device = new TestDevice('serial', 'dummy', 'test device', 'Android');
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidOnlyDevicePlugin)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('log listeners are resumed and suspended automatically - 1', async () => {
|
||||
const message = {
|
||||
date: new Date(),
|
||||
message: 'test',
|
||||
pid: 0,
|
||||
tid: 1,
|
||||
type: 'info',
|
||||
tag: 'tag',
|
||||
} as const;
|
||||
const device = new TestDevice('serial', 'physical', 'test device', 'Android');
|
||||
device.startLogging = jest.fn();
|
||||
device.stopLogging = jest.fn();
|
||||
|
||||
const DevicePlugin = TestUtils.createTestDevicePlugin({
|
||||
devicePlugin(client) {
|
||||
const entries: any[] = [];
|
||||
let disposer: any;
|
||||
|
||||
function start() {
|
||||
disposer = client.onDeviceLogEntry((entry) => {
|
||||
entries.push(entry);
|
||||
});
|
||||
}
|
||||
function stop() {
|
||||
disposer?.();
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
return {start, stop, entries};
|
||||
},
|
||||
});
|
||||
|
||||
await createMockFlipperWithPlugin(DevicePlugin, {
|
||||
device,
|
||||
});
|
||||
const instance = device.sandyPluginStates.get(DevicePlugin.id);
|
||||
expect(instance).toBeDefined();
|
||||
const entries = instance?.instanceApi.entries as any[];
|
||||
|
||||
// logging set up, messages arrive
|
||||
expect(device.startLogging).toBeCalledTimes(1);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(1);
|
||||
|
||||
// stop, messages don't arrive
|
||||
instance?.instanceApi.stop();
|
||||
expect(device.stopLogging).toBeCalledTimes(1);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(1);
|
||||
|
||||
// resume, messsages arrive again
|
||||
instance?.instanceApi.start();
|
||||
expect(device.startLogging).toBeCalledTimes(2);
|
||||
expect(device.stopLogging).toBeCalledTimes(1);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(2);
|
||||
|
||||
// device disconnects, loggers are disposed
|
||||
device.disconnect();
|
||||
expect(device.stopLogging).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
test('log listeners are resumed and suspended automatically - 2', async () => {
|
||||
const message = {
|
||||
date: new Date(),
|
||||
message: 'test',
|
||||
pid: 0,
|
||||
tid: 1,
|
||||
type: 'info',
|
||||
tag: 'tag',
|
||||
} as const;
|
||||
const device = new TestDevice('serial', 'physical', 'test device', 'Android');
|
||||
device.startLogging = jest.fn();
|
||||
device.stopLogging = jest.fn();
|
||||
|
||||
const entries: any[] = [];
|
||||
|
||||
const DevicePlugin = TestUtils.createTestDevicePlugin({
|
||||
devicePlugin(client) {
|
||||
client.onDeviceLogEntry((entry) => {
|
||||
entries.push(entry);
|
||||
});
|
||||
return {};
|
||||
},
|
||||
});
|
||||
|
||||
const Plugin = TestUtils.createTestPlugin(
|
||||
{
|
||||
plugin(client) {
|
||||
client.onDeviceLogEntry((entry) => {
|
||||
entries.push(entry);
|
||||
});
|
||||
return {};
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'AnotherPlugin',
|
||||
},
|
||||
);
|
||||
|
||||
const flipper = await createMockFlipperWithPlugin(DevicePlugin, {
|
||||
device,
|
||||
additionalPlugins: [Plugin],
|
||||
});
|
||||
const instance = device.sandyPluginStates.get(DevicePlugin.id);
|
||||
expect(instance).toBeDefined();
|
||||
|
||||
// logging set up, messages arrives in both
|
||||
expect(device.startLogging).toBeCalledTimes(1);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(2);
|
||||
|
||||
// disable one plugin
|
||||
flipper.togglePlugin(Plugin.id);
|
||||
expect(device.stopLogging).toBeCalledTimes(0);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(3);
|
||||
|
||||
// disable the other plugin
|
||||
flipper.togglePlugin(DevicePlugin.id);
|
||||
|
||||
expect(device.stopLogging).toBeCalledTimes(1);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(3);
|
||||
|
||||
// re-enable plugn
|
||||
flipper.togglePlugin(Plugin.id);
|
||||
expect(device.startLogging).toBeCalledTimes(2);
|
||||
device.addLogEntry(message);
|
||||
expect(entries.length).toBe(4);
|
||||
});
|
||||
Reference in New Issue
Block a user