Move RenderHost initialisation to Jest
Summary: This diff moves RenderHost initialisation to jest, which is thereby treated as just another 'Host' like flipper-ui, the electron app etc. A benefit is that it provides a mocked flipperServer by default that can be used to mock or intercept requests. See LaunchEmulator.spec as example. Also made the jest setup scripts strongly typed by converting them to TS. This change allows the test stub configuration, which was OS dependent, out of flipper-ui-core. Reviewed By: nikoant Differential Revision: D32668632 fbshipit-source-id: fac0c09812b000fd7d1acb75010c35573087c99f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e7f841b6d2
commit
f9b72ac69e
@@ -22,18 +22,10 @@ import {
|
|||||||
clipboard,
|
clipboard,
|
||||||
shell,
|
shell,
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import type {RenderHost} from 'flipper-ui-core';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import {setupMenuBar} from './setupMenuBar';
|
import {setupMenuBar} from './setupMenuBar';
|
||||||
import {FlipperServer, FlipperServerConfig} from 'flipper-common';
|
import {FlipperServer, FlipperServerConfig} from 'flipper-common';
|
||||||
|
import type {RenderHost} from 'flipper-ui-core';
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
// We store this as a global, to make sure the renderHost is available
|
|
||||||
// before flipper-ui-core is loaded and needs those during module initialisation
|
|
||||||
FlipperRenderHostInstance: RenderHost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initializeElectron(
|
export function initializeElectron(
|
||||||
flipperServer: FlipperServer,
|
flipperServer: FlipperServer,
|
||||||
@@ -185,7 +177,7 @@ export function initializeElectron(
|
|||||||
return flipperServerConfig.gatekeepers[gatekeeper] ?? false;
|
return flipperServerConfig.gatekeepers[gatekeeper] ?? false;
|
||||||
},
|
},
|
||||||
flipperServer,
|
flipperServer,
|
||||||
};
|
} as RenderHost;
|
||||||
|
|
||||||
setupMenuBar();
|
setupMenuBar();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -596,13 +596,14 @@ export function createFlipperServerMock(
|
|||||||
exec: jest
|
exec: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(
|
.mockImplementation(
|
||||||
(cmd: keyof FlipperServerCommands, ...args: any[]) => {
|
async (cmd: keyof FlipperServerCommands, ...args: any[]) => {
|
||||||
if (overrides?.[cmd]) {
|
if (overrides?.[cmd]) {
|
||||||
return (overrides[cmd] as any)(...args);
|
return (overrides[cmd] as any)(...args);
|
||||||
}
|
}
|
||||||
return Promise.reject(
|
console.warn(
|
||||||
new Error(`FlipperServerMock exec not implemented: ${cmd}}`),
|
`Empty server response stubbed for command '${cmd}', set 'getRenderHostInstance().flipperServer.exec' in your test to override the behavior.`,
|
||||||
);
|
);
|
||||||
|
return undefined;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
|
|||||||
@@ -11,12 +11,7 @@ import type {NotificationEvents} from './dispatcher/notifications';
|
|||||||
import type {PluginNotification} from './reducers/notifications';
|
import type {PluginNotification} from './reducers/notifications';
|
||||||
import type {NotificationConstructorOptions} from 'electron';
|
import type {NotificationConstructorOptions} from 'electron';
|
||||||
import {FlipperLib} from 'flipper-plugin';
|
import {FlipperLib} from 'flipper-plugin';
|
||||||
import {
|
import {FlipperServer, FlipperServerConfig} from 'flipper-common';
|
||||||
FlipperServer,
|
|
||||||
FlipperServerConfig,
|
|
||||||
ReleaseChannel,
|
|
||||||
Tristate,
|
|
||||||
} from 'flipper-common';
|
|
||||||
|
|
||||||
// Events that are emitted from the main.ts ovr the IPC process bridge in Electron
|
// Events that are emitted from the main.ts ovr the IPC process bridge in Electron
|
||||||
type MainProcessEvents = {
|
type MainProcessEvents = {
|
||||||
@@ -101,7 +96,7 @@ export interface RenderHost {
|
|||||||
openLink(url: string): void;
|
openLink(url: string): void;
|
||||||
loadDefaultPlugins(): Record<string, any>;
|
loadDefaultPlugins(): Record<string, any>;
|
||||||
GK(gatekeeper: string): boolean;
|
GK(gatekeeper: string): boolean;
|
||||||
flipperServer?: FlipperServer;
|
flipperServer: FlipperServer;
|
||||||
serverConfig: FlipperServerConfig;
|
serverConfig: FlipperServerConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,87 +106,3 @@ export function getRenderHostInstance(): RenderHost {
|
|||||||
}
|
}
|
||||||
return window.FlipperRenderHostInstance;
|
return window.FlipperRenderHostInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'test') {
|
|
||||||
const {tmpdir} = require('os');
|
|
||||||
const {resolve} = require('path');
|
|
||||||
|
|
||||||
const rootPath = resolve(__dirname, '..', '..');
|
|
||||||
const stubConfig: FlipperServerConfig = {
|
|
||||||
env: {...process.env},
|
|
||||||
gatekeepers: {
|
|
||||||
TEST_PASSING_GK: true,
|
|
||||||
TEST_FAILING_GK: false,
|
|
||||||
},
|
|
||||||
isProduction: false,
|
|
||||||
launcherSettings: {
|
|
||||||
ignoreLocalPin: false,
|
|
||||||
releaseChannel: ReleaseChannel.DEFAULT,
|
|
||||||
},
|
|
||||||
paths: {
|
|
||||||
appPath: rootPath,
|
|
||||||
desktopPath: `/dev/null`,
|
|
||||||
execPath: process.execPath,
|
|
||||||
homePath: `/dev/null`,
|
|
||||||
staticPath: resolve(rootPath, 'static'),
|
|
||||||
tempPath: tmpdir(),
|
|
||||||
},
|
|
||||||
processConfig: {
|
|
||||||
disabledPlugins: new Set(),
|
|
||||||
lastWindowPosition: null,
|
|
||||||
launcherEnabled: false,
|
|
||||||
launcherMsg: null,
|
|
||||||
screenCapturePath: `/dev/null`,
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
androidHome: `/dev/null`,
|
|
||||||
darkMode: 'light',
|
|
||||||
enableAndroid: false,
|
|
||||||
enableIOS: false,
|
|
||||||
enablePhysicalIOS: false,
|
|
||||||
enablePrefetching: Tristate.False,
|
|
||||||
idbPath: `/dev/null`,
|
|
||||||
reactNative: {
|
|
||||||
shortcuts: {enabled: false, openDevMenu: '', reload: ''},
|
|
||||||
},
|
|
||||||
showWelcomeAtStartup: false,
|
|
||||||
suppressPluginErrors: false,
|
|
||||||
},
|
|
||||||
validWebSocketOrigins: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
window.FlipperRenderHostInstance = {
|
|
||||||
processId: -1,
|
|
||||||
isProduction: false,
|
|
||||||
readTextFromClipboard() {
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
writeTextToClipboard() {},
|
|
||||||
async importFile() {
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
async exportFile() {
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
registerShortcut() {
|
|
||||||
return () => undefined;
|
|
||||||
},
|
|
||||||
hasFocus() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
onIpcEvent() {},
|
|
||||||
sendIpcEvent() {},
|
|
||||||
shouldUseDarkColors() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
restartFlipper() {},
|
|
||||||
openLink() {},
|
|
||||||
serverConfig: stubConfig,
|
|
||||||
loadDefaultPlugins() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
GK(gk) {
|
|
||||||
return stubConfig.gatekeepers[gk] ?? false;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,13 +35,6 @@ Object {
|
|||||||
"TestPlugin",
|
"TestPlugin",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"flipperServer": Object {
|
|
||||||
"close": [MockFunction],
|
|
||||||
"connect": [Function],
|
|
||||||
"exec": [MockFunction],
|
|
||||||
"off": [MockFunction],
|
|
||||||
"on": [MockFunction],
|
|
||||||
},
|
|
||||||
"pluginMenuEntries": Array [],
|
"pluginMenuEntries": Array [],
|
||||||
"selectedAppId": "TestApp#Android#MockAndroidDevice#serial",
|
"selectedAppId": "TestApp#Android#MockAndroidDevice#serial",
|
||||||
"selectedAppPluginListRevision": 0,
|
"selectedAppPluginListRevision": 0,
|
||||||
|
|||||||
@@ -27,11 +27,6 @@ export function connectFlipperServerToStore(
|
|||||||
store: Store,
|
store: Store,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
store.dispatch({
|
|
||||||
type: 'SET_FLIPPER_SERVER',
|
|
||||||
payload: server,
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on('notification', ({type, title, description}) => {
|
server.on('notification', ({type, title, description}) => {
|
||||||
const text = `[$type] ${title}: ${description}`;
|
const text = `[$type] ${title}: ${description}`;
|
||||||
console.warn(text);
|
console.warn(text);
|
||||||
|
|||||||
@@ -12,12 +12,7 @@ import {produce} from 'immer';
|
|||||||
|
|
||||||
import type BaseDevice from '../devices/BaseDevice';
|
import type BaseDevice from '../devices/BaseDevice';
|
||||||
import type Client from '../Client';
|
import type Client from '../Client';
|
||||||
import type {
|
import type {UninitializedClient, DeviceOS, Logger} from 'flipper-common';
|
||||||
UninitializedClient,
|
|
||||||
DeviceOS,
|
|
||||||
Logger,
|
|
||||||
FlipperServer,
|
|
||||||
} from 'flipper-common';
|
|
||||||
import type {Actions} from '.';
|
import type {Actions} from '.';
|
||||||
import {WelcomeScreenStaticView} from '../sandy-chrome/WelcomeScreen';
|
import {WelcomeScreenStaticView} from '../sandy-chrome/WelcomeScreen';
|
||||||
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
||||||
@@ -79,7 +74,6 @@ type StateV2 = {
|
|||||||
deepLinkPayload: unknown;
|
deepLinkPayload: unknown;
|
||||||
staticView: StaticView;
|
staticView: StaticView;
|
||||||
selectedAppPluginListRevision: number;
|
selectedAppPluginListRevision: number;
|
||||||
flipperServer: FlipperServer | undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateV1 = Omit<StateV2, 'enabledPlugins' | 'enabledDevicePlugins'> & {
|
type StateV1 = Omit<StateV2, 'enabledPlugins' | 'enabledDevicePlugins'> & {
|
||||||
@@ -165,10 +159,6 @@ export type Action =
|
|||||||
| {
|
| {
|
||||||
type: 'APP_PLUGIN_LIST_CHANGED';
|
type: 'APP_PLUGIN_LIST_CHANGED';
|
||||||
}
|
}
|
||||||
| {
|
|
||||||
type: 'SET_FLIPPER_SERVER';
|
|
||||||
payload: FlipperServer;
|
|
||||||
}
|
|
||||||
| RegisterPluginAction;
|
| RegisterPluginAction;
|
||||||
|
|
||||||
const DEFAULT_PLUGIN = 'DeviceLogs';
|
const DEFAULT_PLUGIN = 'DeviceLogs';
|
||||||
@@ -195,18 +185,10 @@ const INITAL_STATE: State = {
|
|||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
staticView: WelcomeScreenStaticView,
|
staticView: WelcomeScreenStaticView,
|
||||||
selectedAppPluginListRevision: 0,
|
selectedAppPluginListRevision: 0,
|
||||||
flipperServer: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (state: State = INITAL_STATE, action: Actions): State => {
|
export default (state: State = INITAL_STATE, action: Actions): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_FLIPPER_SERVER': {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
flipperServer: action.payload,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'SET_STATIC_VIEW': {
|
case 'SET_STATIC_VIEW': {
|
||||||
const {payload, deepLinkPayload} = action;
|
const {payload, deepLinkPayload} = action;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {useStore} from '../../utils/useStore';
|
|||||||
import {Layout, renderReactRoot, withTrackingScope} from 'flipper-plugin';
|
import {Layout, renderReactRoot, withTrackingScope} from 'flipper-plugin';
|
||||||
import {Provider} from 'react-redux';
|
import {Provider} from 'react-redux';
|
||||||
import {IOSDeviceParams} from 'flipper-common';
|
import {IOSDeviceParams} from 'flipper-common';
|
||||||
|
import {getRenderHostInstance} from '../../RenderHost';
|
||||||
|
|
||||||
const COLD_BOOT = 'cold-boot';
|
const COLD_BOOT = 'cold-boot';
|
||||||
|
|
||||||
@@ -37,7 +38,6 @@ function LaunchEmulatorContainer({onClose}: {onClose: () => void}) {
|
|||||||
|
|
||||||
export const LaunchEmulatorDialog = withTrackingScope(
|
export const LaunchEmulatorDialog = withTrackingScope(
|
||||||
function LaunchEmulatorDialog({onClose}: {onClose: () => void}) {
|
function LaunchEmulatorDialog({onClose}: {onClose: () => void}) {
|
||||||
const flipperServer = useStore((state) => state.connections.flipperServer);
|
|
||||||
const iosEnabled = useStore((state) => state.settingsState.enableIOS);
|
const iosEnabled = useStore((state) => state.settingsState.enableIOS);
|
||||||
const androidEnabled = useStore(
|
const androidEnabled = useStore(
|
||||||
(state) => state.settingsState.enableAndroid,
|
(state) => state.settingsState.enableAndroid,
|
||||||
@@ -49,8 +49,8 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
|||||||
if (!iosEnabled) {
|
if (!iosEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
flipperServer!
|
getRenderHostInstance()
|
||||||
.exec('ios-get-simulators', false)
|
.flipperServer.exec('ios-get-simulators', false)
|
||||||
.then((emulators) => {
|
.then((emulators) => {
|
||||||
setIosEmulators(
|
setIosEmulators(
|
||||||
emulators.filter(
|
emulators.filter(
|
||||||
@@ -63,21 +63,21 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
|||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.warn('Failed to find simulators', e);
|
console.warn('Failed to find simulators', e);
|
||||||
});
|
});
|
||||||
}, [iosEnabled, flipperServer]);
|
}, [iosEnabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!androidEnabled) {
|
if (!androidEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
flipperServer!
|
getRenderHostInstance()
|
||||||
.exec('android-get-emulators')
|
.flipperServer.exec('android-get-emulators')
|
||||||
.then((emulators) => {
|
.then((emulators) => {
|
||||||
setAndroidEmulators(emulators);
|
setAndroidEmulators(emulators);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.warn('Failed to find emulators', e);
|
console.warn('Failed to find emulators', e);
|
||||||
});
|
});
|
||||||
}, [androidEnabled, flipperServer]);
|
}, [androidEnabled]);
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
...(androidEmulators.length > 0
|
...(androidEmulators.length > 0
|
||||||
@@ -85,8 +85,8 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
|||||||
: []),
|
: []),
|
||||||
...androidEmulators.map((name) => {
|
...androidEmulators.map((name) => {
|
||||||
const launch = (coldBoot: boolean) => {
|
const launch = (coldBoot: boolean) => {
|
||||||
flipperServer!
|
getRenderHostInstance()
|
||||||
.exec('android-launch-emulator', name, coldBoot)
|
.flipperServer.exec('android-launch-emulator', name, coldBoot)
|
||||||
.then(onClose)
|
.then(onClose)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('Failed to start emulator: ', e);
|
console.error('Failed to start emulator: ', e);
|
||||||
@@ -123,8 +123,8 @@ export const LaunchEmulatorDialog = withTrackingScope(
|
|||||||
<Button
|
<Button
|
||||||
key={device.udid}
|
key={device.udid}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
flipperServer!
|
getRenderHostInstance()
|
||||||
.exec('ios-launch-simulator', device.udid)
|
.flipperServer.exec('ios-launch-simulator', device.udid)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('Failed to start simulator: ', e);
|
console.error('Failed to start simulator: ', e);
|
||||||
message.error('Failed to start simulator: ' + e);
|
message.error('Failed to start simulator: ' + e);
|
||||||
|
|||||||
@@ -14,18 +14,19 @@ import {createStore} from 'redux';
|
|||||||
import {LaunchEmulatorDialog} from '../LaunchEmulator';
|
import {LaunchEmulatorDialog} from '../LaunchEmulator';
|
||||||
|
|
||||||
import {createRootReducer} from '../../../reducers';
|
import {createRootReducer} from '../../../reducers';
|
||||||
import {sleep, TestUtils} from 'flipper-plugin';
|
import {sleep} from 'flipper-plugin';
|
||||||
|
import {getRenderHostInstance} from '../../../RenderHost';
|
||||||
|
|
||||||
test('Can render and launch android apps - empty', async () => {
|
test('Can render and launch android apps - empty', async () => {
|
||||||
const store = createStore(createRootReducer());
|
const store = createStore(createRootReducer());
|
||||||
const mockServer = TestUtils.createFlipperServerMock({
|
|
||||||
'ios-get-simulators': () => Promise.resolve([]),
|
const responses: any = {
|
||||||
'android-get-emulators': () => Promise.resolve([]),
|
'ios-get-simulators': [],
|
||||||
});
|
'android-get-emulators': [],
|
||||||
store.dispatch({
|
};
|
||||||
type: 'SET_FLIPPER_SERVER',
|
getRenderHostInstance().flipperServer.exec = async function (cmd: any) {
|
||||||
payload: mockServer,
|
return responses[cmd];
|
||||||
});
|
} as any;
|
||||||
const onClose = jest.fn();
|
const onClose = jest.fn();
|
||||||
|
|
||||||
const renderer = render(
|
const renderer = render(
|
||||||
@@ -44,21 +45,16 @@ test('Can render and launch android apps - empty', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Can render and launch android apps', async () => {
|
test('Can render and launch android apps', async () => {
|
||||||
let p: Promise<any> | undefined = undefined;
|
|
||||||
|
|
||||||
const store = createStore(createRootReducer());
|
const store = createStore(createRootReducer());
|
||||||
const launch = jest.fn().mockImplementation(() => Promise.resolve());
|
|
||||||
const mockServer = TestUtils.createFlipperServerMock({
|
const exec = jest.fn().mockImplementation(async (cmd) => {
|
||||||
'ios-get-simulators': () => Promise.resolve([]),
|
if (cmd === 'android-get-emulators') {
|
||||||
'android-get-emulators': () =>
|
return ['emulator1', 'emulator2'];
|
||||||
(p = Promise.resolve(['emulator1', 'emulator2'])),
|
}
|
||||||
'android-launch-emulator': launch,
|
|
||||||
});
|
|
||||||
store.dispatch({
|
|
||||||
type: 'SET_FLIPPER_SERVER',
|
|
||||||
payload: mockServer,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
getRenderHostInstance().flipperServer.exec = exec;
|
||||||
|
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: 'UPDATE_SETTINGS',
|
type: 'UPDATE_SETTINGS',
|
||||||
payload: {
|
payload: {
|
||||||
@@ -74,7 +70,7 @@ test('Can render and launch android apps', async () => {
|
|||||||
</Provider>,
|
</Provider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
await p!;
|
await sleep(1); // give exec time to resolve
|
||||||
|
|
||||||
expect(await renderer.findAllByText(/emulator/)).toMatchInlineSnapshot(`
|
expect(await renderer.findAllByText(/emulator/)).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
@@ -91,5 +87,16 @@ test('Can render and launch android apps', async () => {
|
|||||||
fireEvent.click(renderer.getByText('emulator2'));
|
fireEvent.click(renderer.getByText('emulator2'));
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
expect(onClose).toBeCalled();
|
expect(onClose).toBeCalled();
|
||||||
expect(launch).toBeCalledWith('emulator2', false);
|
expect(exec.mock.calls).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
"android-get-emulators",
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
"android-launch-emulator",
|
||||||
|
"emulator2",
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import ArchivedDevice from '../devices/ArchivedDevice';
|
|||||||
import {ClientQuery, DeviceOS} from 'flipper-common';
|
import {ClientQuery, DeviceOS} from 'flipper-common';
|
||||||
import {TestDevice} from './TestDevice';
|
import {TestDevice} from './TestDevice';
|
||||||
import {getRenderHostInstance} from '../RenderHost';
|
import {getRenderHostInstance} from '../RenderHost';
|
||||||
import {TestUtils} from 'flipper-plugin';
|
|
||||||
|
|
||||||
export interface AppOptions {
|
export interface AppOptions {
|
||||||
plugins?: PluginDefinition[];
|
plugins?: PluginDefinition[];
|
||||||
@@ -58,7 +57,7 @@ export default class MockFlipper {
|
|||||||
private _clients: Client[] = [];
|
private _clients: Client[] = [];
|
||||||
private _deviceCounter: number = 0;
|
private _deviceCounter: number = 0;
|
||||||
private _clientCounter: number = 0;
|
private _clientCounter: number = 0;
|
||||||
flipperServer: FlipperServer = TestUtils.createFlipperServerMock();
|
flipperServer: FlipperServer = getRenderHostInstance().flipperServer;
|
||||||
|
|
||||||
public get store(): Store {
|
public get store(): Store {
|
||||||
return this._store;
|
return this._store;
|
||||||
@@ -96,10 +95,6 @@ export default class MockFlipper {
|
|||||||
this._logger,
|
this._logger,
|
||||||
);
|
);
|
||||||
this._store.dispatch(registerPlugins(plugins ?? []));
|
this._store.dispatch(registerPlugins(plugins ?? []));
|
||||||
this._store.dispatch({
|
|
||||||
type: 'SET_FLIPPER_SERVER',
|
|
||||||
payload: this.flipperServer,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initWithDeviceAndClient(
|
public async initWithDeviceAndClient(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
import {DeviceOS, DeviceType} from 'flipper-plugin';
|
import {DeviceOS, DeviceType} from 'flipper-plugin';
|
||||||
import {DeviceSpec} from 'flipper-common';
|
import {DeviceSpec} from 'flipper-common';
|
||||||
import BaseDevice from '../devices/BaseDevice';
|
import BaseDevice from '../devices/BaseDevice';
|
||||||
|
import {getRenderHostInstance} from '../RenderHost';
|
||||||
|
|
||||||
export class TestDevice extends BaseDevice {
|
export class TestDevice extends BaseDevice {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -19,21 +20,12 @@ export class TestDevice extends BaseDevice {
|
|||||||
os: DeviceOS,
|
os: DeviceOS,
|
||||||
specs?: DeviceSpec[],
|
specs?: DeviceSpec[],
|
||||||
) {
|
) {
|
||||||
super(
|
super(getRenderHostInstance().flipperServer, {
|
||||||
{
|
serial,
|
||||||
async connect() {},
|
deviceType,
|
||||||
on: jest.fn(),
|
title,
|
||||||
off: jest.fn(),
|
os,
|
||||||
exec: jest.fn(),
|
specs,
|
||||||
close: jest.fn(),
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
serial,
|
|
||||||
deviceType,
|
|
||||||
title,
|
|
||||||
os,
|
|
||||||
specs,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ module.exports = {
|
|||||||
'^.*__tests__(/|\\\\).*\\.tsx?$': 'ts-jest',
|
'^.*__tests__(/|\\\\).*\\.tsx?$': 'ts-jest',
|
||||||
'\\.(js|tsx?)$': '<rootDir>/scripts/jest-transform.js',
|
'\\.(js|tsx?)$': '<rootDir>/scripts/jest-transform.js',
|
||||||
},
|
},
|
||||||
setupFiles: ['<rootDir>/scripts/jest-setup.js'],
|
setupFiles: ['<rootDir>/scripts/jest-setup.ts'],
|
||||||
setupFilesAfterEnv: ['<rootDir>/scripts/jest-setup-after.js'],
|
setupFilesAfterEnv: ['<rootDir>/scripts/jest-setup-after.ts'],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'^flipper$': '<rootDir>/app/src',
|
'^flipper$': '<rootDir>/app/src',
|
||||||
'^flipper-plugin$': '<rootDir>/flipper-plugin/src',
|
'^flipper-plugin$': '<rootDir>/flipper-plugin/src',
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
// jest-setup-after will run after Jest has been initialized, so that it can be adapted.
|
|
||||||
import {cleanup} from '@testing-library/react';
|
|
||||||
|
|
||||||
const test = global.test;
|
|
||||||
if (!test) {
|
|
||||||
throw new Error('Failed jest test object');
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This test will not be executed on Github / SandCastle,
|
|
||||||
* since, for example, it relies on precise timer reliability
|
|
||||||
*/
|
|
||||||
test.local = function local() {
|
|
||||||
const fn = process.env.SANDCASTLE || process.env.CI ? test.skip : test;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
return fn.apply(null, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test will only run on non-windows machines
|
|
||||||
*/
|
|
||||||
test.unix = function local() {
|
|
||||||
const fn = process.platform === 'win32' ? test.skip : test;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
return fn.apply(null, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(cleanup);
|
|
||||||
|
|
||||||
console.debug = function () {
|
|
||||||
// Intentional noop, we don't want debug statements in Jest runs
|
|
||||||
};
|
|
||||||
|
|
||||||
// make perf tools available in Node (it is available in Browser / Electron just fine)
|
|
||||||
const {PerformanceObserver, performance} = require('perf_hooks');
|
|
||||||
Object.freeze(performance);
|
|
||||||
Object.freeze(Object.getPrototypeOf(performance));
|
|
||||||
// Something in our unit tests is messing with the performance global
|
|
||||||
// This fixes that.....
|
|
||||||
Object.defineProperty(global, 'performance', {
|
|
||||||
get() {
|
|
||||||
return performance;
|
|
||||||
},
|
|
||||||
set() {
|
|
||||||
throw new Error('Attempt to overwrite global.performance');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
global.PerformanceObserver = PerformanceObserver;
|
|
||||||
|
|
||||||
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
|
||||||
Object.defineProperty(window, 'matchMedia', {
|
|
||||||
writable: true,
|
|
||||||
value: jest.fn().mockImplementation((query) => ({
|
|
||||||
matches: false,
|
|
||||||
media: query,
|
|
||||||
onchange: null,
|
|
||||||
addListener: jest.fn(), // deprecated
|
|
||||||
removeListener: jest.fn(), // deprecated
|
|
||||||
addEventListener: jest.fn(),
|
|
||||||
removeEventListener: jest.fn(),
|
|
||||||
dispatchEvent: jest.fn(),
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
172
desktop/scripts/jest-setup-after.ts
Normal file
172
desktop/scripts/jest-setup-after.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
// jest-setup-after will run after Jest has been initialized, so that it can be adapted.
|
||||||
|
|
||||||
|
import {cleanup} from '@testing-library/react';
|
||||||
|
import {resolve} from 'path';
|
||||||
|
import {tmpdir} from 'os';
|
||||||
|
|
||||||
|
window.FlipperRenderHostInstance = createStubRenderHost();
|
||||||
|
|
||||||
|
require('../flipper-ui-core/src/fb-stubs/Logger').init(undefined, {
|
||||||
|
isTest: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
import {TestUtils} from 'flipper-plugin';
|
||||||
|
import {FlipperServerConfig, ReleaseChannel, Tristate} from 'flipper-common';
|
||||||
|
import type {RenderHost} from 'flipper-ui-core';
|
||||||
|
|
||||||
|
const test = global.test;
|
||||||
|
if (!test) {
|
||||||
|
throw new Error('Failed jest test object');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This test will not be executed on Github / SandCastle,
|
||||||
|
* since, for example, it relies on precise timer reliability
|
||||||
|
*/
|
||||||
|
(test as any).local = function local() {
|
||||||
|
const fn = process.env.SANDCASTLE || process.env.CI ? test.skip : test;
|
||||||
|
// eslint-disable-next-line
|
||||||
|
return fn.apply(null, arguments as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test will only run on non-windows machines
|
||||||
|
*/
|
||||||
|
(test as any).unix = function local() {
|
||||||
|
const fn = process.platform === 'win32' ? test.skip : test;
|
||||||
|
// eslint-disable-next-line
|
||||||
|
return fn.apply(null, arguments as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Fresh mock flipperServer for every test
|
||||||
|
window.FlipperRenderHostInstance = createStubRenderHost();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
console.debug = function () {
|
||||||
|
// Intentional noop, we don't want debug statements in Jest runs
|
||||||
|
};
|
||||||
|
|
||||||
|
// make perf tools available in Node (it is available in Browser / Electron just fine)
|
||||||
|
const {PerformanceObserver, performance} = require('perf_hooks');
|
||||||
|
Object.freeze(performance);
|
||||||
|
Object.freeze(Object.getPrototypeOf(performance));
|
||||||
|
// Something in our unit tests is messing with the performance global
|
||||||
|
// This fixes that.....
|
||||||
|
Object.defineProperty(global, 'performance', {
|
||||||
|
get() {
|
||||||
|
return performance;
|
||||||
|
},
|
||||||
|
set() {
|
||||||
|
throw new Error('Attempt to overwrite global.performance');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
global.PerformanceObserver = PerformanceObserver;
|
||||||
|
|
||||||
|
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
||||||
|
Object.defineProperty(window, 'matchMedia', {
|
||||||
|
writable: true,
|
||||||
|
value: jest.fn().mockImplementation((query) => ({
|
||||||
|
matches: false,
|
||||||
|
media: query,
|
||||||
|
onchange: null,
|
||||||
|
addListener: jest.fn(), // deprecated
|
||||||
|
removeListener: jest.fn(), // deprecated
|
||||||
|
addEventListener: jest.fn(),
|
||||||
|
removeEventListener: jest.fn(),
|
||||||
|
dispatchEvent: jest.fn(),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
function createStubRenderHost(): RenderHost {
|
||||||
|
const rootPath = resolve(__dirname, '..');
|
||||||
|
const stubConfig: FlipperServerConfig = {
|
||||||
|
env: {...process.env},
|
||||||
|
gatekeepers: {
|
||||||
|
TEST_PASSING_GK: true,
|
||||||
|
TEST_FAILING_GK: false,
|
||||||
|
},
|
||||||
|
isProduction: false,
|
||||||
|
launcherSettings: {
|
||||||
|
ignoreLocalPin: false,
|
||||||
|
releaseChannel: ReleaseChannel.DEFAULT,
|
||||||
|
},
|
||||||
|
paths: {
|
||||||
|
appPath: rootPath,
|
||||||
|
desktopPath: `/dev/null`,
|
||||||
|
execPath: process.execPath,
|
||||||
|
homePath: `/dev/null`,
|
||||||
|
staticPath: resolve(rootPath, 'static'),
|
||||||
|
tempPath: tmpdir(),
|
||||||
|
},
|
||||||
|
processConfig: {
|
||||||
|
disabledPlugins: new Set(),
|
||||||
|
lastWindowPosition: null,
|
||||||
|
launcherEnabled: false,
|
||||||
|
launcherMsg: null,
|
||||||
|
screenCapturePath: `/dev/null`,
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
androidHome: `/dev/null`,
|
||||||
|
darkMode: 'light',
|
||||||
|
enableAndroid: false,
|
||||||
|
enableIOS: false,
|
||||||
|
enablePhysicalIOS: false,
|
||||||
|
enablePrefetching: Tristate.False,
|
||||||
|
idbPath: `/dev/null`,
|
||||||
|
reactNative: {
|
||||||
|
shortcuts: {enabled: false, openDevMenu: '', reload: ''},
|
||||||
|
},
|
||||||
|
showWelcomeAtStartup: false,
|
||||||
|
suppressPluginErrors: false,
|
||||||
|
},
|
||||||
|
validWebSocketOrigins: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
processId: -1,
|
||||||
|
isProduction: false,
|
||||||
|
readTextFromClipboard() {
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
writeTextToClipboard() {},
|
||||||
|
async importFile() {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
async exportFile() {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
registerShortcut() {
|
||||||
|
return () => undefined;
|
||||||
|
},
|
||||||
|
hasFocus() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
onIpcEvent() {},
|
||||||
|
sendIpcEvent() {},
|
||||||
|
shouldUseDarkColors() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
restartFlipper() {},
|
||||||
|
openLink() {},
|
||||||
|
serverConfig: stubConfig,
|
||||||
|
loadDefaultPlugins() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
GK(gk: string) {
|
||||||
|
return stubConfig.gatekeepers[gk] ?? false;
|
||||||
|
},
|
||||||
|
flipperServer: TestUtils.createFlipperServerMock(),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,12 +23,11 @@ if (process.env.TZ !== timezone) {
|
|||||||
// Make sure we have identical formatting of Dates everywhere
|
// Make sure we have identical formatting of Dates everywhere
|
||||||
const toLocaleString = Date.prototype.toLocaleString;
|
const toLocaleString = Date.prototype.toLocaleString;
|
||||||
// eslint-disable-next-line no-extend-native
|
// eslint-disable-next-line no-extend-native
|
||||||
Date.prototype.toLocaleString = function (_locale, ...args) {
|
(Date as any).prototype.toLocaleString = function (
|
||||||
|
_locale: any,
|
||||||
|
...args: any[]
|
||||||
|
) {
|
||||||
return toLocaleString.call(this, 'en-US', ...args);
|
return toLocaleString.call(this, 'en-US', ...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
require('immer').enableMapSet();
|
require('immer').enableMapSet();
|
||||||
|
|
||||||
require('../flipper-ui-core/src/fb-stubs/Logger').init(undefined, {
|
|
||||||
isTest: true,
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user