Yarn workspaces
Summary: 1) moved "sonar/desktop/src" to "sonar/desktop/app/src", so "app" is now a separate package containing the core Flipper app code 2) Configured yarn workspaces with the root in "sonar/desktop": app, static, pkg, doctor, headless-tests. Plugins are not included for now, I plan to do this later. Reviewed By: jknoxville Differential Revision: D20535782 fbshipit-source-id: 600b2301960f37c7d72166e0d04eba462bec9fc1
This commit is contained in:
committed by
Facebook GitHub Bot
parent
676d7bbd24
commit
863f89351e
76
desktop/app/src/utils/__tests__/Idler.node.js
Normal file
76
desktop/app/src/utils/__tests__/Idler.node.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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 {Idler, TestIdler} from '../Idler.tsx';
|
||||
import {sleep} from '../promiseTimeout.tsx';
|
||||
|
||||
test('Idler should interrupt', async () => {
|
||||
const idler = new Idler();
|
||||
let i = 0;
|
||||
try {
|
||||
for (; i < 500; i++) {
|
||||
if (i == 100) {
|
||||
expect(idler.shouldIdle()).toBe(false);
|
||||
idler.cancel();
|
||||
expect(idler.isCancelled()).toBe(true);
|
||||
expect(idler.shouldIdle()).toBe(true);
|
||||
}
|
||||
await idler.idle();
|
||||
}
|
||||
expect('error').toBe('thrown');
|
||||
} catch (e) {
|
||||
expect(i).toEqual(100);
|
||||
}
|
||||
});
|
||||
|
||||
test('Idler should want to idle', async () => {
|
||||
const idler = new Idler(100);
|
||||
expect(idler.shouldIdle()).toBe(false);
|
||||
await sleep(10);
|
||||
expect(idler.shouldIdle()).toBe(false);
|
||||
await sleep(200);
|
||||
expect(idler.shouldIdle()).toBe(true);
|
||||
await idler.idle();
|
||||
expect(idler.shouldIdle()).toBe(false);
|
||||
});
|
||||
|
||||
test('TestIdler can be controlled', async () => {
|
||||
const idler = new TestIdler();
|
||||
|
||||
expect(idler.shouldIdle()).toBe(false);
|
||||
expect(idler.shouldIdle()).toBe(true);
|
||||
let resolved = false;
|
||||
idler.idle().then(() => {
|
||||
resolved = true;
|
||||
});
|
||||
expect(resolved).toBe(false);
|
||||
await idler.next();
|
||||
expect(resolved).toBe(true);
|
||||
|
||||
expect(idler.shouldIdle()).toBe(false);
|
||||
expect(idler.shouldIdle()).toBe(true);
|
||||
idler.idle();
|
||||
await idler.next();
|
||||
|
||||
expect(idler.isCancelled()).toBe(false);
|
||||
idler.cancel();
|
||||
expect(idler.isCancelled()).toBe(true);
|
||||
expect(idler.shouldIdle()).toBe(true);
|
||||
|
||||
let threw = false;
|
||||
const p = idler.idle().catch(e => {
|
||||
threw = true;
|
||||
expect(e).toMatchInlineSnapshot(
|
||||
`[CancelledPromiseError: Idler got killed]`,
|
||||
);
|
||||
});
|
||||
|
||||
await p;
|
||||
expect(threw).toBe(true);
|
||||
});
|
||||
47
desktop/app/src/utils/__tests__/adbConfig.node.js
Normal file
47
desktop/app/src/utils/__tests__/adbConfig.node.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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 adbConfig from '../adbConfig.tsx';
|
||||
|
||||
test('get host and port from ADB_SERVER_SOCKET', () => {
|
||||
process.env.ANDROID_ADB_SERVER_PORT = undefined;
|
||||
process.env.ADB_SERVER_SOCKET = 'tcp:127.0.0.1:5037';
|
||||
const {port, host} = adbConfig();
|
||||
expect(port).toBe(5037);
|
||||
expect(host).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
test('get IPv6 address from ADB_SERVER_SOCKET', () => {
|
||||
process.env.ANDROID_ADB_SERVER_PORT = undefined;
|
||||
process.env.ADB_SERVER_SOCKET = 'tcp::::1:5037';
|
||||
const {host} = adbConfig();
|
||||
expect(host).toBe(':::1');
|
||||
});
|
||||
|
||||
test('get port from ANDROID_ADB_SERVER_PORT', () => {
|
||||
process.env.ANDROID_ADB_SERVER_PORT = '1337';
|
||||
process.env.ADB_SERVER_SOCKET = undefined;
|
||||
const {port} = adbConfig();
|
||||
expect(port).toBe(1337);
|
||||
});
|
||||
|
||||
test('prefer ADB_SERVER_SOCKET over ANDROID_ADB_SERVER_PORT', () => {
|
||||
process.env.ANDROID_ADB_SERVER_PORT = '1337';
|
||||
process.env.ADB_SERVER_SOCKET = 'tcp:127.0.0.1:5037';
|
||||
const {port} = adbConfig();
|
||||
expect(port).toBe(5037);
|
||||
});
|
||||
|
||||
test('have defaults', () => {
|
||||
process.env.ANDROID_ADB_SERVER_PORT = undefined;
|
||||
process.env.ADB_SERVER_SOCKET = undefined;
|
||||
const {port, host} = adbConfig();
|
||||
expect(port).toBe(5037);
|
||||
expect(host).toBe('localhost');
|
||||
});
|
||||
50
desktop/app/src/utils/__tests__/clientUtils.node.tsx
Normal file
50
desktop/app/src/utils/__tests__/clientUtils.node.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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 {deconstructClientId, buildClientId} from '../clientUtils';
|
||||
|
||||
test('client id constructed correctly', () => {
|
||||
const consoleErrorSpy = jest.spyOn(global.console, 'error');
|
||||
const clientId = buildClientId({
|
||||
app: 'Instagram',
|
||||
os: 'iOS',
|
||||
device: 'iPhone Simulator',
|
||||
device_id: 'EC431B79-69F1-4705-9FE5-9AE5D96378E1',
|
||||
});
|
||||
expect(clientId).toBe(
|
||||
'Instagram#iOS#iPhone Simulator#EC431B79-69F1-4705-9FE5-9AE5D96378E1',
|
||||
);
|
||||
expect(consoleErrorSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('client id deconstructed correctly', () => {
|
||||
const deconstructedClientId = deconstructClientId(
|
||||
'Instagram#iOS#iPhone Simulator#EC431B79-69F1-4705-9FE5-9AE5D96378E1',
|
||||
);
|
||||
expect(deconstructedClientId).toStrictEqual({
|
||||
app: 'Instagram',
|
||||
os: 'iOS',
|
||||
device: 'iPhone Simulator',
|
||||
device_id: 'EC431B79-69F1-4705-9FE5-9AE5D96378E1',
|
||||
});
|
||||
});
|
||||
|
||||
test('client id deconstruction error logged', () => {
|
||||
const consoleErrorSpy = jest.spyOn(global.console, 'error');
|
||||
const deconstructedClientId = deconstructClientId(
|
||||
'Instagram#iPhone Simulator#EC431B79-69F1-4705-9FE5-9AE5D96378E1',
|
||||
);
|
||||
expect(deconstructedClientId).toStrictEqual({
|
||||
app: 'Instagram',
|
||||
os: 'iPhone Simulator',
|
||||
device: 'EC431B79-69F1-4705-9FE5-9AE5D96378E1',
|
||||
device_id: undefined,
|
||||
});
|
||||
expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
76
desktop/app/src/utils/__tests__/crashReporterUtility.node.js
Normal file
76
desktop/app/src/utils/__tests__/crashReporterUtility.node.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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 {shouldParseAndroidLog} from '../crashReporterUtility.tsx';
|
||||
import type {DeviceLogEntry, LogLevel} from 'flipper';
|
||||
|
||||
function getAndroidLog(
|
||||
date: Date,
|
||||
type: LogLevel,
|
||||
tag: string,
|
||||
message: string,
|
||||
): DeviceLogEntry {
|
||||
return {date, type, tag, message, app: 'testapp', pid: 0, tid: 0};
|
||||
}
|
||||
|
||||
test('test shouldParseAndroidLog function for type error and tag is AndroidRuntime', () => {
|
||||
const referenceDate = new Date();
|
||||
const log: DeviceLogEntry = getAndroidLog(
|
||||
new Date(referenceDate.getTime() + 10000), //This log arrives 10 secs after the refernce time
|
||||
'error',
|
||||
'AndroidRuntime',
|
||||
'Possible runtime crash',
|
||||
);
|
||||
const shouldParseTheLog = shouldParseAndroidLog(log, referenceDate);
|
||||
expect(shouldParseTheLog).toEqual(true);
|
||||
});
|
||||
test('test shouldParseAndroidLog function for type non-error', () => {
|
||||
const referenceDate = new Date();
|
||||
const log: DeviceLogEntry = getAndroidLog(
|
||||
new Date(referenceDate.getTime() + 10000), //This log arrives 10 secs after the refernce time
|
||||
'debug',
|
||||
'fb4a.activitymanager',
|
||||
'Possible debug info in activitymanager',
|
||||
);
|
||||
const shouldParseTheLog = shouldParseAndroidLog(log, referenceDate);
|
||||
expect(shouldParseTheLog).toEqual(false);
|
||||
});
|
||||
test('test shouldParseAndroidLog function for the older android log', () => {
|
||||
const referenceDate = new Date();
|
||||
const log: DeviceLogEntry = getAndroidLog(
|
||||
new Date(referenceDate.getTime() - 10000), //This log arrives 10 secs before the refernce time
|
||||
'error',
|
||||
'fb4a.activitymanager',
|
||||
'Possible error info in activitymanager',
|
||||
);
|
||||
const shouldParseTheLog = shouldParseAndroidLog(log, referenceDate);
|
||||
expect(shouldParseTheLog).toEqual(false);
|
||||
});
|
||||
test('test shouldParseAndroidLog function for the fatal log', () => {
|
||||
const referenceDate = new Date();
|
||||
const log: DeviceLogEntry = getAndroidLog(
|
||||
new Date(referenceDate.getTime() + 10000), //This log arrives 10 secs after the refernce time
|
||||
'fatal',
|
||||
'arbitrary tag',
|
||||
'Possible error info in activitymanager',
|
||||
);
|
||||
const shouldParseTheLog = shouldParseAndroidLog(log, referenceDate);
|
||||
expect(shouldParseTheLog).toEqual(true);
|
||||
});
|
||||
test('test shouldParseAndroidLog function for the error log which does not staisfy our tags check', () => {
|
||||
const referenceDate = new Date();
|
||||
const log: DeviceLogEntry = getAndroidLog(
|
||||
new Date(referenceDate.getTime() + 10000), //This log arrives 10 secs after the refernce time
|
||||
'error',
|
||||
'arbitrary tag',
|
||||
'Possible error info in fb4a',
|
||||
);
|
||||
const shouldParseTheLog = shouldParseAndroidLog(log, referenceDate);
|
||||
expect(shouldParseTheLog).toEqual(false);
|
||||
});
|
||||
10
desktop/app/src/utils/__tests__/data/settings-v1-valid.json
Normal file
10
desktop/app/src/utils/__tests__/data/settings-v1-valid.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"androidHome": "/opt/android_sdk",
|
||||
"something": {
|
||||
"else": 4
|
||||
},
|
||||
"_persist": {
|
||||
"version": -1,
|
||||
"rehydrated": true
|
||||
}
|
||||
}
|
||||
38
desktop/app/src/utils/__tests__/environmentVariables.node.js
Normal file
38
desktop/app/src/utils/__tests__/environmentVariables.node.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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 {parseFlipperPorts} from '../environmentVariables.tsx';
|
||||
|
||||
test('Valid port overrides are parsed correctly', () => {
|
||||
const overrides = parseFlipperPorts('1111,2222');
|
||||
expect(overrides).toEqual({insecure: 1111, secure: 2222});
|
||||
});
|
||||
|
||||
test('Malformed numbers are ignored', () => {
|
||||
const malformed1 = parseFlipperPorts('1111,22s22');
|
||||
expect(malformed1).toBe(undefined);
|
||||
|
||||
const malformed2 = parseFlipperPorts('11a11,2222');
|
||||
expect(malformed2).toBe(undefined);
|
||||
});
|
||||
|
||||
test('Wrong number of values is ignored', () => {
|
||||
const overrides = parseFlipperPorts('1111');
|
||||
expect(overrides).toBe(undefined);
|
||||
});
|
||||
|
||||
test('Empty values are ignored', () => {
|
||||
const overrides = parseFlipperPorts('1111,');
|
||||
expect(overrides).toBe(undefined);
|
||||
});
|
||||
|
||||
test('Negative values are ignored', () => {
|
||||
const overrides = parseFlipperPorts('-1111,2222');
|
||||
expect(overrides).toBe(undefined);
|
||||
});
|
||||
951
desktop/app/src/utils/__tests__/exportData.electron.tsx
Normal file
951
desktop/app/src/utils/__tests__/exportData.electron.tsx
Normal file
@@ -0,0 +1,951 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
try {
|
||||
jest.mock('../../fb/Logger');
|
||||
} catch (e) {
|
||||
jest.mock('../../fb-stubs/Logger');
|
||||
}
|
||||
import {State} from '../../reducers/index';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import {default as BaseDevice} from '../../devices/BaseDevice';
|
||||
import {default as ArchivedDevice} from '../../devices/ArchivedDevice';
|
||||
import {processStore, determinePluginsToProcess} from '../exportData';
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from '../../plugin';
|
||||
import {Notification} from '../../plugin';
|
||||
import {default as Client, ClientExport} from '../../Client';
|
||||
import {State as PluginsState} from '../../reducers/plugins';
|
||||
|
||||
class TestPlugin extends FlipperPlugin<any, any, any> {}
|
||||
TestPlugin.title = 'TestPlugin';
|
||||
TestPlugin.id = 'TestPlugin';
|
||||
class TestDevicePlugin extends FlipperDevicePlugin<any, any, any> {}
|
||||
TestDevicePlugin.title = 'TestDevicePlugin';
|
||||
TestDevicePlugin.id = 'TestDevicePlugin';
|
||||
const logger = {
|
||||
track: () => {},
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
debug: () => {},
|
||||
trackTimeSince: () => {},
|
||||
};
|
||||
const mockStore = configureStore<State, {}>([])();
|
||||
|
||||
function generateNotifications(
|
||||
id: string,
|
||||
title: string,
|
||||
message: string,
|
||||
severity: 'warning' | 'error',
|
||||
): Notification {
|
||||
return {id, title, message, severity};
|
||||
}
|
||||
|
||||
function generateClientIdentifier(device: BaseDevice, app: string): string {
|
||||
const {os, deviceType, serial} = device;
|
||||
const identifier = `${app}#${os}#${deviceType}#${serial}`;
|
||||
return identifier;
|
||||
}
|
||||
|
||||
function generateClientIdentifierWithSalt(
|
||||
identifier: string,
|
||||
salt: string,
|
||||
): string {
|
||||
const array = identifier.split('#');
|
||||
const serial = array.pop();
|
||||
return array.join('#') + '#' + salt + '-' + serial;
|
||||
}
|
||||
|
||||
function generateClientFromClientWithSalt(
|
||||
client: ClientExport,
|
||||
salt: string,
|
||||
): ClientExport {
|
||||
const {os, device, device_id, app} = client.query;
|
||||
const identifier = generateClientIdentifierWithSalt(client.id, salt);
|
||||
return {
|
||||
id: identifier,
|
||||
query: {app, os, device, device_id: salt + '-' + device_id},
|
||||
};
|
||||
}
|
||||
function generateClientFromDevice(
|
||||
device: BaseDevice,
|
||||
app: string,
|
||||
): ClientExport {
|
||||
const {os, deviceType, serial} = device;
|
||||
const identifier = generateClientIdentifier(device, app);
|
||||
return {
|
||||
id: identifier,
|
||||
query: {app, os, device: deviceType, device_id: serial},
|
||||
};
|
||||
}
|
||||
|
||||
test('test generateClientIndentifierWithSalt helper function', () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const identifier = generateClientIdentifier(device, 'app');
|
||||
const saltIdentifier = generateClientIdentifierWithSalt(identifier, 'salt');
|
||||
expect(saltIdentifier).toEqual('app#iOS#archivedEmulator#salt-serial');
|
||||
expect(identifier).toEqual('app#iOS#archivedEmulator#serial');
|
||||
});
|
||||
|
||||
test('test generateClientFromClientWithSalt helper function', () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const client = generateClientFromDevice(device, 'app');
|
||||
const saltedClient = generateClientFromClientWithSalt(client, 'salt');
|
||||
expect(saltedClient).toEqual({
|
||||
id: 'app#iOS#archivedEmulator#salt-serial',
|
||||
query: {
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'archivedEmulator',
|
||||
device_id: 'salt-serial',
|
||||
},
|
||||
});
|
||||
expect(client).toEqual({
|
||||
id: 'app#iOS#archivedEmulator#serial',
|
||||
query: {
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'archivedEmulator',
|
||||
device_id: 'serial',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('test generateClientFromDevice helper function', () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const client = generateClientFromDevice(device, 'app');
|
||||
expect(client).toEqual({
|
||||
id: 'app#iOS#archivedEmulator#serial',
|
||||
query: {
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'archivedEmulator',
|
||||
device_id: 'serial',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('test generateClientIdentifier helper function', () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const identifier = generateClientIdentifier(device, 'app');
|
||||
expect(identifier).toEqual('app#iOS#archivedEmulator#serial');
|
||||
});
|
||||
|
||||
test('test generateNotifications helper function', () => {
|
||||
const notification = generateNotifications('id', 'title', 'msg', 'error');
|
||||
expect(notification).toEqual({
|
||||
id: 'id',
|
||||
title: 'title',
|
||||
message: 'msg',
|
||||
severity: 'error',
|
||||
});
|
||||
});
|
||||
|
||||
test('test processStore function for empty state', () => {
|
||||
const json = processStore({
|
||||
activeNotifications: [],
|
||||
device: null,
|
||||
pluginStates: {},
|
||||
clients: [],
|
||||
devicePlugins: new Map(),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
expect(json).resolves.toBeNull();
|
||||
});
|
||||
|
||||
test('test processStore function for an iOS device connected', async () => {
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
}),
|
||||
pluginStates: {},
|
||||
clients: [],
|
||||
devicePlugins: new Map(),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {device, clients} = json;
|
||||
expect(json.device).toBeDefined();
|
||||
expect(clients).toEqual([]);
|
||||
if (!device) {
|
||||
fail('device is undefined');
|
||||
return;
|
||||
}
|
||||
const {serial, deviceType, title, os} = device;
|
||||
expect(serial).toEqual('salt-serial');
|
||||
expect(deviceType).toEqual('archivedEmulator');
|
||||
expect(title).toEqual('TestiPhone');
|
||||
expect(os).toEqual('iOS');
|
||||
const {pluginStates, activeNotifications} = json.store;
|
||||
expect(pluginStates).toEqual({});
|
||||
expect(activeNotifications).toEqual([]);
|
||||
});
|
||||
|
||||
test('test processStore function for an iOS device connected with client plugin data', async () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const clientIdentifier = generateClientIdentifier(device, 'testapp');
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device,
|
||||
pluginStates: {
|
||||
[`${clientIdentifier}#TestPlugin`]: {msg: 'Test plugin'},
|
||||
},
|
||||
clients: [generateClientFromDevice(device, 'testapp')],
|
||||
devicePlugins: new Map(),
|
||||
clientPlugins: new Map([['TestPlugin', TestPlugin]]),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const expectedPluginState = {
|
||||
[`${generateClientIdentifierWithSalt(
|
||||
clientIdentifier,
|
||||
'salt',
|
||||
)}#TestPlugin`]: JSON.stringify({
|
||||
msg: 'Test plugin',
|
||||
}),
|
||||
};
|
||||
expect(pluginStates).toEqual(expectedPluginState);
|
||||
});
|
||||
|
||||
test('test processStore function to have only the client for the selected device', async () => {
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const unselectedDevice = new ArchivedDevice({
|
||||
serial: 'identifier',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
|
||||
const unselectedDeviceClientIdentifier = generateClientIdentifier(
|
||||
unselectedDevice,
|
||||
'testapp',
|
||||
);
|
||||
const selectedDeviceClientIdentifier = generateClientIdentifier(
|
||||
selectedDevice,
|
||||
'testapp',
|
||||
);
|
||||
const selectedDeviceClient = generateClientFromDevice(
|
||||
selectedDevice,
|
||||
'testapp',
|
||||
);
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: selectedDevice,
|
||||
pluginStates: {
|
||||
[unselectedDeviceClientIdentifier + '#TestDevicePlugin']: {
|
||||
msg: 'Test plugin unselected device',
|
||||
},
|
||||
[selectedDeviceClientIdentifier + '#TestDevicePlugin']: {
|
||||
msg: 'Test plugin selected device',
|
||||
},
|
||||
},
|
||||
clients: [
|
||||
selectedDeviceClient,
|
||||
generateClientFromDevice(unselectedDevice, 'testapp'),
|
||||
],
|
||||
devicePlugins: new Map(),
|
||||
clientPlugins: new Map([['TestDevicePlugin', TestPlugin]]),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {clients} = json;
|
||||
const {pluginStates} = json.store;
|
||||
const expectedPluginState = {
|
||||
[generateClientIdentifierWithSalt(selectedDeviceClientIdentifier, 'salt') +
|
||||
'#TestDevicePlugin']: JSON.stringify({
|
||||
msg: 'Test plugin selected device',
|
||||
}),
|
||||
};
|
||||
expect(clients).toEqual([
|
||||
generateClientFromClientWithSalt(selectedDeviceClient, 'salt'),
|
||||
]);
|
||||
expect(pluginStates).toEqual(expectedPluginState);
|
||||
});
|
||||
|
||||
test('test processStore function to have multiple clients for the selected device', async () => {
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
|
||||
const clientIdentifierApp1 = generateClientIdentifier(
|
||||
selectedDevice,
|
||||
'testapp1',
|
||||
);
|
||||
const clientIdentifierApp2 = generateClientIdentifier(
|
||||
selectedDevice,
|
||||
'testapp2',
|
||||
);
|
||||
|
||||
const client1 = generateClientFromDevice(selectedDevice, 'testapp1');
|
||||
const client2 = generateClientFromDevice(selectedDevice, 'testapp2');
|
||||
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: selectedDevice,
|
||||
pluginStates: {
|
||||
[clientIdentifierApp1 + '#TestPlugin']: {
|
||||
msg: 'Test plugin App1',
|
||||
},
|
||||
[clientIdentifierApp2 + '#TestPlugin']: {
|
||||
msg: 'Test plugin App2',
|
||||
},
|
||||
},
|
||||
clients: [
|
||||
generateClientFromDevice(selectedDevice, 'testapp1'),
|
||||
generateClientFromDevice(selectedDevice, 'testapp2'),
|
||||
],
|
||||
devicePlugins: new Map(),
|
||||
clientPlugins: new Map([['TestPlugin', TestPlugin]]),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {clients} = json;
|
||||
const {pluginStates} = json.store;
|
||||
const expectedPluginState = {
|
||||
[generateClientIdentifierWithSalt(clientIdentifierApp1, 'salt') +
|
||||
'#TestPlugin']: JSON.stringify({
|
||||
msg: 'Test plugin App1',
|
||||
}),
|
||||
[generateClientIdentifierWithSalt(clientIdentifierApp2, 'salt') +
|
||||
'#TestPlugin']: JSON.stringify({
|
||||
msg: 'Test plugin App2',
|
||||
}),
|
||||
};
|
||||
expect(clients).toEqual([
|
||||
generateClientFromClientWithSalt(client1, 'salt'),
|
||||
generateClientFromClientWithSalt(client2, 'salt'),
|
||||
]);
|
||||
expect(pluginStates).toEqual(expectedPluginState);
|
||||
});
|
||||
|
||||
test('test processStore function for device plugin state and no clients', async () => {
|
||||
// Test case to verify that device plugin data is exported even if there are no clients
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: selectedDevice,
|
||||
pluginStates: {
|
||||
'serial#TestDevicePlugin': {
|
||||
msg: 'Test Device plugin',
|
||||
},
|
||||
},
|
||||
clients: [],
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const {clients} = json;
|
||||
const expectedPluginState = {
|
||||
'salt-serial#TestDevicePlugin': JSON.stringify({msg: 'Test Device plugin'}),
|
||||
};
|
||||
expect(pluginStates).toEqual(expectedPluginState);
|
||||
expect(clients).toEqual([]);
|
||||
});
|
||||
|
||||
test('test processStore function for unselected device plugin state and no clients', async () => {
|
||||
// Test case to verify that device plugin data is exported even if there are no clients
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: selectedDevice,
|
||||
pluginStates: {
|
||||
'unselectedDeviceIdentifier#TestDevicePlugin': {
|
||||
msg: 'Test Device plugin',
|
||||
},
|
||||
},
|
||||
clients: [],
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const {clients} = json;
|
||||
expect(pluginStates).toEqual({});
|
||||
expect(clients).toEqual([]);
|
||||
});
|
||||
|
||||
test('test processStore function for notifications for selected device', async () => {
|
||||
// Test case to verify that device plugin data is exported even if there are no clients
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const client = generateClientFromDevice(selectedDevice, 'testapp1');
|
||||
const notification = generateNotifications(
|
||||
'notificationID',
|
||||
'title',
|
||||
'Notification Message',
|
||||
'warning',
|
||||
);
|
||||
const activeNotification = {
|
||||
pluginId: 'TestNotification',
|
||||
notification,
|
||||
client: client.id,
|
||||
};
|
||||
const json = await processStore({
|
||||
activeNotifications: [activeNotification],
|
||||
device: selectedDevice,
|
||||
pluginStates: {},
|
||||
clients: [client],
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const {clients} = json;
|
||||
expect(pluginStates).toEqual({});
|
||||
expect(clients).toEqual([generateClientFromClientWithSalt(client, 'salt')]);
|
||||
const {activeNotifications} = json.store;
|
||||
const expectedActiveNotification = {
|
||||
pluginId: 'TestNotification',
|
||||
notification,
|
||||
client: generateClientIdentifierWithSalt(client.id, 'salt'),
|
||||
};
|
||||
expect(activeNotifications).toEqual([expectedActiveNotification]);
|
||||
});
|
||||
|
||||
test('test processStore function for notifications for unselected device', async () => {
|
||||
// Test case to verify that device plugin data is exported even if there are no clients
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const unselectedDevice = new ArchivedDevice({
|
||||
serial: 'identifier',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
|
||||
const client = generateClientFromDevice(selectedDevice, 'testapp1');
|
||||
const unselectedclient = generateClientFromDevice(
|
||||
unselectedDevice,
|
||||
'testapp1',
|
||||
);
|
||||
const notification = generateNotifications(
|
||||
'notificationID',
|
||||
'title',
|
||||
'Notification Message',
|
||||
'warning',
|
||||
);
|
||||
const activeNotification = {
|
||||
pluginId: 'TestNotification',
|
||||
notification,
|
||||
client: unselectedclient.id,
|
||||
};
|
||||
const json = await processStore({
|
||||
activeNotifications: [activeNotification],
|
||||
device: selectedDevice,
|
||||
pluginStates: {},
|
||||
clients: [client, unselectedclient],
|
||||
devicePlugins: new Map(),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const {clients} = json;
|
||||
expect(pluginStates).toEqual({});
|
||||
expect(clients).toEqual([generateClientFromClientWithSalt(client, 'salt')]);
|
||||
const {activeNotifications} = json.store;
|
||||
expect(activeNotifications).toEqual([]);
|
||||
});
|
||||
|
||||
test('test processStore function for selected plugins', async () => {
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
|
||||
const client = generateClientFromDevice(selectedDevice, 'app');
|
||||
const pluginstates = {
|
||||
[generateClientIdentifier(selectedDevice, 'app') + '#TestDevicePlugin1']: {
|
||||
msg: 'Test plugin1',
|
||||
},
|
||||
[generateClientIdentifier(selectedDevice, 'app') + '#TestDevicePlugin2']: {
|
||||
msg: 'Test plugin2',
|
||||
},
|
||||
};
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: selectedDevice,
|
||||
pluginStates: pluginstates,
|
||||
clients: [client],
|
||||
devicePlugins: new Map([
|
||||
['TestDevicePlugin1', TestDevicePlugin],
|
||||
['TestDevicePlugin2', TestDevicePlugin],
|
||||
]),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: ['TestDevicePlugin2'],
|
||||
});
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const {clients} = json;
|
||||
expect(pluginStates).toEqual({
|
||||
[generateClientIdentifierWithSalt(
|
||||
generateClientIdentifier(selectedDevice, 'app'),
|
||||
'salt',
|
||||
) + '#TestDevicePlugin2']: JSON.stringify({
|
||||
msg: 'Test plugin2',
|
||||
}),
|
||||
});
|
||||
expect(clients).toEqual([generateClientFromClientWithSalt(client, 'salt')]);
|
||||
const {activeNotifications} = json.store;
|
||||
expect(activeNotifications).toEqual([]);
|
||||
});
|
||||
|
||||
test('test processStore function for no selected plugins', async () => {
|
||||
const selectedDevice = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const client = generateClientFromDevice(selectedDevice, 'app');
|
||||
const pluginstates = {
|
||||
[generateClientIdentifier(selectedDevice, 'app') + '#TestDevicePlugin1']: {
|
||||
msg: 'Test plugin1',
|
||||
},
|
||||
[generateClientIdentifier(selectedDevice, 'app') + '#TestDevicePlugin2']: {
|
||||
msg: 'Test plugin2',
|
||||
},
|
||||
};
|
||||
const json = await processStore({
|
||||
activeNotifications: [],
|
||||
device: selectedDevice,
|
||||
pluginStates: pluginstates,
|
||||
clients: [client],
|
||||
devicePlugins: new Map([
|
||||
['TestDevicePlugin1', TestDevicePlugin],
|
||||
['TestDevicePlugin2', TestDevicePlugin],
|
||||
]),
|
||||
clientPlugins: new Map(),
|
||||
salt: 'salt',
|
||||
selectedPlugins: [],
|
||||
});
|
||||
|
||||
if (!json) {
|
||||
fail('json is undefined');
|
||||
return;
|
||||
}
|
||||
const {pluginStates} = json.store;
|
||||
const {clients} = json;
|
||||
expect(pluginStates).toEqual({
|
||||
[generateClientIdentifierWithSalt(
|
||||
generateClientIdentifier(selectedDevice, 'app'),
|
||||
'salt',
|
||||
) + '#TestDevicePlugin2']: JSON.stringify({
|
||||
msg: 'Test plugin2',
|
||||
}),
|
||||
[generateClientIdentifierWithSalt(
|
||||
generateClientIdentifier(selectedDevice, 'app'),
|
||||
'salt',
|
||||
) + '#TestDevicePlugin1']: JSON.stringify({
|
||||
msg: 'Test plugin1',
|
||||
}),
|
||||
});
|
||||
expect(clients).toEqual([generateClientFromClientWithSalt(client, 'salt')]);
|
||||
const {activeNotifications} = json.store;
|
||||
expect(activeNotifications).toEqual([]);
|
||||
});
|
||||
|
||||
test('test determinePluginsToProcess for mutilple clients having plugins present', async () => {
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const client2 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app2', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestDevicePlugin'],
|
||||
);
|
||||
const client3 = new Client(
|
||||
generateClientIdentifier(device1, 'app3'),
|
||||
{app: 'app3', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const plugins: PluginsState = {
|
||||
clientPlugins: new Map([
|
||||
['TestPlugin', TestPlugin],
|
||||
['RandomPlugin', TestPlugin],
|
||||
]),
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: ['TestPlugin'],
|
||||
};
|
||||
const op = determinePluginsToProcess(
|
||||
[client1, client2, client3],
|
||||
device1,
|
||||
plugins,
|
||||
);
|
||||
expect(op).toBeDefined();
|
||||
expect(op).toEqual([
|
||||
{
|
||||
pluginKey: `${client1.id}#TestPlugin`,
|
||||
pluginId: 'TestPlugin',
|
||||
pluginName: 'TestPlugin',
|
||||
pluginClass: TestPlugin,
|
||||
client: client1,
|
||||
},
|
||||
{
|
||||
pluginKey: `${client3.id}#TestPlugin`,
|
||||
pluginId: 'TestPlugin',
|
||||
pluginName: 'TestPlugin',
|
||||
pluginClass: TestPlugin,
|
||||
client: client3,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('test determinePluginsToProcess for no selected plugin present in any clients', async () => {
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const client2 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app2', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestDevicePlugin'],
|
||||
);
|
||||
const plugins: PluginsState = {
|
||||
clientPlugins: new Map([
|
||||
['TestPlugin', TestPlugin],
|
||||
['RandomPlugin', TestPlugin],
|
||||
]),
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: ['RandomPlugin'],
|
||||
};
|
||||
const op = determinePluginsToProcess([client1, client2], device1, plugins);
|
||||
expect(op).toBeDefined();
|
||||
expect(op).toEqual([]);
|
||||
});
|
||||
|
||||
test('test determinePluginsToProcess for multiple clients on same device', async () => {
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const client2 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app2', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestDevicePlugin'],
|
||||
);
|
||||
const plugins: PluginsState = {
|
||||
clientPlugins: new Map([['TestPlugin', TestPlugin]]),
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: ['TestPlugin'],
|
||||
};
|
||||
const op = determinePluginsToProcess([client1, client2], device1, plugins);
|
||||
expect(op).toBeDefined();
|
||||
expect(op.length).toEqual(1);
|
||||
expect(op).toEqual([
|
||||
{
|
||||
pluginKey: `${client1.id}#TestPlugin`,
|
||||
pluginId: 'TestPlugin',
|
||||
pluginName: 'TestPlugin',
|
||||
pluginClass: TestPlugin,
|
||||
client: client1,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('test determinePluginsToProcess for multiple clients on different device', async () => {
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const device2 = new BaseDevice('serial2', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1Device1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const client2Device1 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app1', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestDevicePlugin'],
|
||||
);
|
||||
const client1Device2 = new Client(
|
||||
generateClientIdentifier(device2, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial2'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const client2Device2 = new Client(
|
||||
generateClientIdentifier(device2, 'app2'),
|
||||
{app: 'app1', os: 'iOS', device: 'TestiPhone', device_id: 'serial2'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestDevicePlugin'],
|
||||
);
|
||||
const plugins: PluginsState = {
|
||||
clientPlugins: new Map([['TestPlugin', TestPlugin]]),
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: ['TestPlugin'],
|
||||
};
|
||||
const op = determinePluginsToProcess(
|
||||
[client1Device1, client2Device1, client1Device2, client2Device2],
|
||||
device2,
|
||||
plugins,
|
||||
);
|
||||
expect(op).toBeDefined();
|
||||
expect(op.length).toEqual(1);
|
||||
expect(op).toEqual([
|
||||
{
|
||||
pluginKey: `${client1Device2.id}#TestPlugin`,
|
||||
pluginId: 'TestPlugin',
|
||||
pluginName: 'TestPlugin',
|
||||
pluginClass: TestPlugin,
|
||||
client: client1Device2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('test determinePluginsToProcess to ignore archived clients', async () => {
|
||||
const selectedDevice = new BaseDevice(
|
||||
'serial',
|
||||
'emulator',
|
||||
'TestiPhone',
|
||||
'iOS',
|
||||
);
|
||||
const archivedDevice = new ArchivedDevice({
|
||||
serial: 'serial-archived',
|
||||
deviceType: 'emulator',
|
||||
title: 'TestiPhone',
|
||||
os: 'iOS',
|
||||
logEntries: [],
|
||||
screenshotHandle: null,
|
||||
});
|
||||
const logger = {
|
||||
track: () => {},
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
debug: () => {},
|
||||
trackTimeSince: () => {},
|
||||
};
|
||||
const mockStore = configureStore<State, {}>([])();
|
||||
const client = new Client(
|
||||
generateClientIdentifier(selectedDevice, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const archivedClient = new Client(
|
||||
generateClientIdentifier(archivedDevice, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial-archived'},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
['TestPlugin', 'TestDevicePlugin'],
|
||||
);
|
||||
const plugins: PluginsState = {
|
||||
clientPlugins: new Map([['TestPlugin', TestPlugin]]),
|
||||
devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: ['TestPlugin'],
|
||||
};
|
||||
const op = determinePluginsToProcess(
|
||||
[client, archivedClient],
|
||||
selectedDevice,
|
||||
plugins,
|
||||
);
|
||||
expect(op).toBeDefined();
|
||||
expect(op.length).toEqual(1);
|
||||
expect(op).toEqual([
|
||||
{
|
||||
pluginKey: `${client.id}#TestPlugin`,
|
||||
pluginId: 'TestPlugin',
|
||||
pluginName: 'TestPlugin',
|
||||
pluginClass: TestPlugin,
|
||||
client: client,
|
||||
},
|
||||
]);
|
||||
});
|
||||
35
desktop/app/src/utils/__tests__/icons.node.ts
Normal file
35
desktop/app/src/utils/__tests__/icons.node.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 {buildLocalIconPath, buildIconURL} from '../icons';
|
||||
import * as path from 'path';
|
||||
|
||||
test('filled icons get correct local path', () => {
|
||||
const iconPath = buildLocalIconPath('star', 12, 2);
|
||||
expect(iconPath).toBe(path.join('icons', 'star-filled-12@2x.png'));
|
||||
});
|
||||
|
||||
test('outline icons get correct local path', () => {
|
||||
const iconPath = buildLocalIconPath('star-outline', 12, 2);
|
||||
expect(iconPath).toBe(path.join('icons', 'star-outline-12@2x.png'));
|
||||
});
|
||||
|
||||
test('filled icons get correct URL', () => {
|
||||
const iconUrl = buildIconURL('star', 12, 2);
|
||||
expect(iconUrl).toBe(
|
||||
'https://external.xx.fbcdn.net/assets/?name=star&variant=filled&size=12&set=facebook_icons&density=2x',
|
||||
);
|
||||
});
|
||||
|
||||
test('outline icons get correct URL', () => {
|
||||
const iconUrl = buildIconURL('star-outline', 12, 2);
|
||||
expect(iconUrl).toBe(
|
||||
'https://external.xx.fbcdn.net/assets/?name=star&variant=outline&size=12&set=facebook_icons&density=2x',
|
||||
);
|
||||
});
|
||||
40
desktop/app/src/utils/__tests__/jsonFileStorage.node.js
Normal file
40
desktop/app/src/utils/__tests__/jsonFileStorage.node.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 JsonFileStorage from '../jsonFileReduxPersistStorage.tsx';
|
||||
import fs from 'fs';
|
||||
|
||||
const validSerializedData = fs
|
||||
.readFileSync('app/src/utils/__tests__/data/settings-v1-valid.json')
|
||||
.toString()
|
||||
.replace(/\r\n/g, '\n')
|
||||
.trim();
|
||||
|
||||
const validDeserializedData =
|
||||
'{"androidHome":"\\"/opt/android_sdk\\"","something":"{\\"else\\":4}","_persist":"{\\"version\\":-1,\\"rehydrated\\":true}"}';
|
||||
|
||||
const storage = new JsonFileStorage(
|
||||
'app/src/utils/__tests__/data/settings-v1-valid.json',
|
||||
);
|
||||
|
||||
test('A valid settings file gets parsed correctly', () => {
|
||||
return storage
|
||||
.getItem('anykey')
|
||||
.then(result => expect(result).toEqual(validDeserializedData));
|
||||
});
|
||||
|
||||
test('deserialize works as expected', () => {
|
||||
const deserialized = storage.deserializeValue(validSerializedData);
|
||||
expect(deserialized).toEqual(validDeserializedData);
|
||||
});
|
||||
|
||||
test('serialize works as expected', () => {
|
||||
const serialized = storage.serializeValue(validDeserializedData);
|
||||
expect(serialized).toEqual(validSerializedData);
|
||||
});
|
||||
488
desktop/app/src/utils/__tests__/messageQueue.node.tsx
Normal file
488
desktop/app/src/utils/__tests__/messageQueue.node.tsx
Normal file
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* 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 {FlipperPlugin} from '../../plugin';
|
||||
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
|
||||
import {GK, Store, Client} from '../../';
|
||||
import {
|
||||
selectPlugin,
|
||||
starPlugin,
|
||||
selectClient,
|
||||
selectDevice,
|
||||
} from '../../reducers/connections';
|
||||
import {processMessageQueue} from '../messageQueue';
|
||||
import {getPluginKey} from '../pluginUtils';
|
||||
import {TestIdler} from '../Idler';
|
||||
import pluginMessageQueue, {
|
||||
State,
|
||||
queueMessage,
|
||||
} from '../../reducers/pluginMessageQueue';
|
||||
|
||||
interface PersistedState {
|
||||
count: 1;
|
||||
}
|
||||
|
||||
class TestPlugin extends FlipperPlugin<any, any, any> {
|
||||
static id = 'TestPlugin';
|
||||
|
||||
static defaultPersistedState = {
|
||||
count: 0,
|
||||
};
|
||||
|
||||
static persistedStateReducer(
|
||||
persistedState: PersistedState,
|
||||
method: string,
|
||||
payload: {delta?: number},
|
||||
) {
|
||||
if (method === 'inc') {
|
||||
return Object.assign({}, persistedState, {
|
||||
count: persistedState.count + ((payload && payload?.delta) || 1),
|
||||
});
|
||||
}
|
||||
return persistedState;
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function starTestPlugin(store: Store, client: Client) {
|
||||
store.dispatch(
|
||||
starPlugin({
|
||||
selectedPlugin: TestPlugin.id,
|
||||
selectedApp: client.query.app,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function selectDeviceLogs(store: Store) {
|
||||
store.dispatch(
|
||||
selectPlugin({
|
||||
selectedPlugin: 'DeviceLogs',
|
||||
selectedApp: null,
|
||||
deepLinkPayload: null,
|
||||
selectedDevice: store.getState().connections.selectedDevice!,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function selectTestPlugin(store: Store, client: Client) {
|
||||
store.dispatch(
|
||||
selectPlugin({
|
||||
selectedPlugin: TestPlugin.id,
|
||||
selectedApp: client.query.app,
|
||||
deepLinkPayload: null,
|
||||
selectedDevice: store.getState().connections.selectedDevice!,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
test('will process event with GK disabled', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({store, sendMessage}) => {
|
||||
expect(store.getState().connections.selectedPlugin).toBe('TestPlugin');
|
||||
sendMessage('inc', {});
|
||||
expect(store.getState().pluginStates).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object {
|
||||
"count": 1,
|
||||
},
|
||||
}
|
||||
`);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - events are processed immediately if plugin is selected', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({store, sendMessage}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', () => {
|
||||
expect(store.getState().connections.selectedPlugin).toBe('TestPlugin');
|
||||
sendMessage('inc', {});
|
||||
expect(store.getState().pluginStates).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object {
|
||||
"count": 1,
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(
|
||||
`Object {}`,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - events are NOT processed immediately if plugin is NOT selected (but starred)', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({client, device, store, sendMessage}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
expect(store.getState().connections.selectedPlugin).not.toBe(
|
||||
'TestPlugin',
|
||||
);
|
||||
|
||||
sendMessage('inc', {});
|
||||
sendMessage('inc', {delta: 2});
|
||||
expect(store.getState().pluginStates).toMatchInlineSnapshot(
|
||||
`Object {}`,
|
||||
);
|
||||
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Array [
|
||||
Object {
|
||||
"method": "inc",
|
||||
"params": Object {},
|
||||
},
|
||||
Object {
|
||||
"method": "inc",
|
||||
"params": Object {
|
||||
"delta": 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
|
||||
// process the message
|
||||
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
||||
await processMessageQueue(TestPlugin, pluginKey, store);
|
||||
expect(store.getState().pluginStates).toEqual({
|
||||
[pluginKey]: {
|
||||
count: 3,
|
||||
},
|
||||
});
|
||||
|
||||
expect(store.getState().pluginMessageQueue).toEqual({
|
||||
[pluginKey]: [],
|
||||
});
|
||||
|
||||
// unstar, but, messages still arrives because selected
|
||||
starTestPlugin(store, client);
|
||||
selectTestPlugin(store, client);
|
||||
sendMessage('inc', {delta: 3});
|
||||
// active, immediately processed
|
||||
expect(store.getState().pluginStates).toEqual({
|
||||
[pluginKey]: {
|
||||
count: 6,
|
||||
},
|
||||
});
|
||||
|
||||
// different plugin, and not starred, message will never arrive
|
||||
selectDeviceLogs(store);
|
||||
sendMessage('inc', {delta: 4});
|
||||
expect(store.getState().pluginMessageQueue).toEqual({
|
||||
[pluginKey]: [],
|
||||
});
|
||||
|
||||
// star again, plugin still not selected, message is queued
|
||||
starTestPlugin(store, client);
|
||||
sendMessage('inc', {delta: 5});
|
||||
|
||||
expect(store.getState().pluginMessageQueue).toEqual({
|
||||
[pluginKey]: [{method: 'inc', params: {delta: 5}}],
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - events are queued for plugins that are favorite when app is not selected', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({device, store, sendMessage, createClient}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
expect(store.getState().connections.selectedPlugin).not.toBe(
|
||||
'TestPlugin',
|
||||
);
|
||||
|
||||
const client2 = createClient(device, 'TestApp2');
|
||||
store.dispatch(selectClient(client2.id));
|
||||
|
||||
// Now we send a message to the second client, it should arrive,
|
||||
// as the plugin was enabled already on the first client as well
|
||||
sendMessage('inc', {delta: 2});
|
||||
expect(store.getState().pluginStates).toMatchInlineSnapshot(
|
||||
`Object {}`,
|
||||
);
|
||||
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(
|
||||
`
|
||||
Object {
|
||||
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Array [
|
||||
Object {
|
||||
"method": "inc",
|
||||
"params": Object {
|
||||
"delta": 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - events are queued for plugins that are favorite when app is selected on different device', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({client, store, sendMessage, createDevice, createClient}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
expect(store.getState().connections.selectedPlugin).not.toBe(
|
||||
'TestPlugin',
|
||||
);
|
||||
|
||||
const device2 = createDevice('serial2');
|
||||
const client2 = createClient(device2, client.query.app); // same app id
|
||||
store.dispatch(selectDevice(device2));
|
||||
store.dispatch(selectClient(client2.id));
|
||||
|
||||
// Now we send a message to the second client, it should arrive,
|
||||
// as the plugin was enabled already on the first client as well
|
||||
sendMessage('inc', {delta: 2});
|
||||
expect(store.getState().pluginStates).toMatchInlineSnapshot(
|
||||
`Object {}`,
|
||||
);
|
||||
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(
|
||||
`
|
||||
Object {
|
||||
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Array [
|
||||
Object {
|
||||
"method": "inc",
|
||||
"params": Object {
|
||||
"delta": 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - events processing will be paused', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({client, device, store, sendMessage}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
|
||||
sendMessage('inc', {});
|
||||
sendMessage('inc', {delta: 3});
|
||||
sendMessage('inc', {delta: 5});
|
||||
|
||||
// process the message
|
||||
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
||||
|
||||
// controlled idler will signal and and off that idling is needed
|
||||
const idler = new TestIdler();
|
||||
|
||||
const p = processMessageQueue(
|
||||
TestPlugin,
|
||||
pluginKey,
|
||||
store,
|
||||
undefined,
|
||||
idler,
|
||||
);
|
||||
|
||||
expect(store.getState().pluginStates).toEqual({
|
||||
[pluginKey]: {
|
||||
count: 4,
|
||||
},
|
||||
});
|
||||
|
||||
expect(store.getState().pluginMessageQueue).toEqual({
|
||||
[pluginKey]: [{method: 'inc', params: {delta: 5}}],
|
||||
});
|
||||
|
||||
await idler.next();
|
||||
expect(store.getState().pluginStates).toEqual({
|
||||
[pluginKey]: {
|
||||
count: 9,
|
||||
},
|
||||
});
|
||||
|
||||
expect(store.getState().pluginMessageQueue).toEqual({
|
||||
[pluginKey]: [],
|
||||
});
|
||||
|
||||
// don't idle anymore
|
||||
idler.run();
|
||||
await p;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - messages that arrive during processing will be queued', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({client, device, store, sendMessage}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
|
||||
sendMessage('inc', {});
|
||||
sendMessage('inc', {delta: 2});
|
||||
sendMessage('inc', {delta: 3});
|
||||
|
||||
// process the message
|
||||
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
||||
|
||||
const idler = new TestIdler();
|
||||
|
||||
const p = processMessageQueue(
|
||||
TestPlugin,
|
||||
pluginKey,
|
||||
store,
|
||||
undefined,
|
||||
idler,
|
||||
);
|
||||
|
||||
// first message is consumed
|
||||
expect(store.getState().pluginMessageQueue[pluginKey].length).toBe(1);
|
||||
expect(store.getState().pluginStates[pluginKey].count).toBe(3);
|
||||
|
||||
// Select the current plugin as active, still, messages should end up in the queue
|
||||
store.dispatch(
|
||||
selectPlugin({
|
||||
selectedPlugin: TestPlugin.id,
|
||||
selectedApp: client.id,
|
||||
deepLinkPayload: null,
|
||||
selectedDevice: device,
|
||||
}),
|
||||
);
|
||||
expect(store.getState().connections.selectedPlugin).toBe('TestPlugin');
|
||||
|
||||
sendMessage('inc', {delta: 4});
|
||||
// should not be processed yet
|
||||
expect(store.getState().pluginMessageQueue[pluginKey].length).toBe(2);
|
||||
expect(store.getState().pluginStates[pluginKey].count).toBe(3);
|
||||
|
||||
await idler.next();
|
||||
expect(store.getState().pluginMessageQueue[pluginKey].length).toBe(0);
|
||||
expect(store.getState().pluginStates[pluginKey].count).toBe(10);
|
||||
|
||||
idler.run();
|
||||
await p;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - processing can be cancelled', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({client, device, store, sendMessage}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
|
||||
sendMessage('inc', {});
|
||||
sendMessage('inc', {delta: 2});
|
||||
sendMessage('inc', {delta: 3});
|
||||
sendMessage('inc', {delta: 4});
|
||||
sendMessage('inc', {delta: 5});
|
||||
|
||||
// process the message
|
||||
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
||||
|
||||
const idler = new TestIdler();
|
||||
|
||||
const p = processMessageQueue(
|
||||
TestPlugin,
|
||||
pluginKey,
|
||||
store,
|
||||
undefined,
|
||||
idler,
|
||||
);
|
||||
|
||||
// first message is consumed
|
||||
await idler.next();
|
||||
expect(store.getState().pluginMessageQueue[pluginKey].length).toBe(1);
|
||||
expect(store.getState().pluginStates[pluginKey].count).toBe(10);
|
||||
|
||||
idler.cancel();
|
||||
|
||||
expect(store.getState().pluginMessageQueue[pluginKey].length).toBe(1);
|
||||
expect(store.getState().pluginStates[pluginKey].count).toBe(10);
|
||||
await p;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue - make sure resetting plugin state clears the message queue', async () => {
|
||||
await createMockFlipperWithPlugin(
|
||||
TestPlugin,
|
||||
async ({client, device, store, sendMessage}) => {
|
||||
await GK.withWhitelistedGK('flipper_event_queue', async () => {
|
||||
selectDeviceLogs(store);
|
||||
|
||||
sendMessage('inc', {});
|
||||
sendMessage('inc', {delta: 2});
|
||||
|
||||
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
||||
|
||||
expect(store.getState().pluginMessageQueue[pluginKey].length).toBe(2);
|
||||
|
||||
store.dispatch({
|
||||
type: 'CLEAR_PLUGIN_STATE',
|
||||
payload: {clientId: client.id, devicePlugins: new Set()},
|
||||
});
|
||||
|
||||
expect(store.getState().pluginMessageQueue[pluginKey]).toBe(undefined);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('queue will be cleaned up when it exceeds maximum size', () => {
|
||||
let state: State = {};
|
||||
const pluginKey = 'test';
|
||||
const queueSize = 5000;
|
||||
let i = 0;
|
||||
for (i = 0; i < queueSize; i++) {
|
||||
state = pluginMessageQueue(
|
||||
state,
|
||||
queueMessage(pluginKey, 'test', {i}, queueSize),
|
||||
);
|
||||
}
|
||||
// almost full
|
||||
expect(state[pluginKey][0]).toEqual({method: 'test', params: {i: 0}});
|
||||
expect(state[pluginKey].length).toBe(queueSize); // ~5000
|
||||
expect(state[pluginKey][queueSize - 1]).toEqual({
|
||||
method: 'test',
|
||||
params: {i: queueSize - 1}, // ~4999
|
||||
});
|
||||
|
||||
state = pluginMessageQueue(
|
||||
state,
|
||||
queueMessage(pluginKey, 'test', {i: ++i}, queueSize),
|
||||
);
|
||||
|
||||
const newLength = Math.ceil(0.9 * queueSize) + 1; // ~4500
|
||||
expect(state[pluginKey].length).toBe(newLength);
|
||||
expect(state[pluginKey][0]).toEqual({
|
||||
method: 'test',
|
||||
params: {i: queueSize - newLength + 1}, // ~500
|
||||
});
|
||||
expect(state[pluginKey][newLength - 1]).toEqual({
|
||||
method: 'test',
|
||||
params: {i: i}, // ~50001
|
||||
});
|
||||
});
|
||||
15
desktop/app/src/utils/__tests__/packageMetadata.node.js
Normal file
15
desktop/app/src/utils/__tests__/packageMetadata.node.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 {readCurrentRevision} from '../packageMetadata.tsx';
|
||||
|
||||
test('readCurrentRevision does not return something meaningful in dev mode', async () => {
|
||||
const ret = await readCurrentRevision();
|
||||
expect(ret).toBeUndefined();
|
||||
});
|
||||
291
desktop/app/src/utils/__tests__/pluginUtils.node.js
Normal file
291
desktop/app/src/utils/__tests__/pluginUtils.node.js
Normal file
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* 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 {
|
||||
getPersistentPlugins,
|
||||
getActivePersistentPlugins,
|
||||
} from '../pluginUtils.tsx';
|
||||
import type {State as PluginsState} from '../../reducers/plugins.tsx';
|
||||
import type {State as PluginStatesState} from '../../reducers/pluginStates.tsx';
|
||||
import type {PluginDefinition} from '../../dispatcher/plugins.tsx';
|
||||
import type {State as PluginMessageQueueState} from '../../reducers/pluginStates.tsx';
|
||||
import {FlipperBasePlugin} from 'flipper';
|
||||
import type {ReduxState} from '../../reducers/index.tsx';
|
||||
|
||||
function createMockFlipperPluginWithDefaultPersistedState(id: string) {
|
||||
return class MockFlipperPluginWithDefaultPersistedState extends FlipperBasePlugin<
|
||||
*,
|
||||
*,
|
||||
{msg: string},
|
||||
> {
|
||||
static id = id;
|
||||
static defaultPersistedState = {msg: 'MockFlipperPluginWithPersistedState'};
|
||||
};
|
||||
}
|
||||
|
||||
function createMockFlipperPluginWithExportPersistedState(id: string) {
|
||||
return class MockFlipperPluginWithExportPersistedState extends FlipperBasePlugin<
|
||||
*,
|
||||
*,
|
||||
{msg: string},
|
||||
> {
|
||||
static id = id;
|
||||
static exportPersistedState = (
|
||||
callClient: (string, ?Object) => Promise<Object>,
|
||||
persistedState: ?{msg: string},
|
||||
store: ?ReduxState,
|
||||
): Promise<?{msg: string}> => {
|
||||
return Promise.resolve({
|
||||
msg: 'MockFlipperPluginWithExportPersistedState',
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function createMockFlipperPluginWithNoPersistedState(id: string) {
|
||||
return class MockFlipperPluginWithNoPersistedState extends FlipperBasePlugin<
|
||||
*,
|
||||
*,
|
||||
*,
|
||||
> {
|
||||
static id = id;
|
||||
};
|
||||
}
|
||||
|
||||
function mockPluginState(
|
||||
gatekeepedPlugins: Array<PluginDefinition>,
|
||||
disabledPlugins: Array<PluginDefinition>,
|
||||
failedPlugins: Array<[PluginDefinition, string]>,
|
||||
): PluginsState {
|
||||
return {
|
||||
devicePlugins: new Map([
|
||||
[
|
||||
'DevicePlugin1',
|
||||
createMockFlipperPluginWithDefaultPersistedState('DevicePlugin1'),
|
||||
],
|
||||
[
|
||||
'DevicePlugin2',
|
||||
createMockFlipperPluginWithDefaultPersistedState('DevicePlugin2'),
|
||||
],
|
||||
]),
|
||||
clientPlugins: new Map([
|
||||
[
|
||||
'ClientPlugin1',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin1'),
|
||||
],
|
||||
[
|
||||
'ClientPlugin2',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin2'),
|
||||
],
|
||||
]),
|
||||
gatekeepedPlugins,
|
||||
disabledPlugins,
|
||||
failedPlugins,
|
||||
selectedPlugins: [],
|
||||
};
|
||||
}
|
||||
|
||||
function mockPluginDefinition(name: string): PluginDefinition {
|
||||
return {
|
||||
name,
|
||||
out: 'out',
|
||||
};
|
||||
}
|
||||
|
||||
test('getPersistentPlugins with the plugins getting excluded', () => {
|
||||
const state = mockPluginState(
|
||||
[mockPluginDefinition('DevicePlugin1')],
|
||||
[mockPluginDefinition('ClientPlugin1')],
|
||||
[[mockPluginDefinition('DevicePlugin2'), 'DevicePlugin2']],
|
||||
);
|
||||
const list = getPersistentPlugins(state);
|
||||
expect(list).toEqual(['ClientPlugin2']);
|
||||
});
|
||||
|
||||
test('getPersistentPlugins with no plugins getting excluded', () => {
|
||||
const state = mockPluginState([], [], []);
|
||||
const list = getPersistentPlugins(state);
|
||||
expect(list).toEqual([
|
||||
'ClientPlugin1',
|
||||
'ClientPlugin2',
|
||||
'DevicePlugin1',
|
||||
'DevicePlugin2',
|
||||
]);
|
||||
});
|
||||
|
||||
test('getPersistentPlugins, where the plugins with exportPersistedState not getting excluded', () => {
|
||||
const state: PluginsState = {
|
||||
devicePlugins: new Map([
|
||||
[
|
||||
'DevicePlugin1',
|
||||
createMockFlipperPluginWithExportPersistedState('DevicePlugin1'),
|
||||
],
|
||||
[
|
||||
'DevicePlugin2',
|
||||
createMockFlipperPluginWithExportPersistedState('DevicePlugin2'),
|
||||
],
|
||||
]),
|
||||
clientPlugins: new Map([
|
||||
[
|
||||
'ClientPlugin1',
|
||||
createMockFlipperPluginWithExportPersistedState('ClientPlugin1'),
|
||||
],
|
||||
[
|
||||
'ClientPlugin2',
|
||||
createMockFlipperPluginWithExportPersistedState('ClientPlugin2'),
|
||||
],
|
||||
]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: [],
|
||||
};
|
||||
const list = getPersistentPlugins(state);
|
||||
expect(list).toEqual([
|
||||
'ClientPlugin1',
|
||||
'ClientPlugin2',
|
||||
'DevicePlugin1',
|
||||
'DevicePlugin2',
|
||||
]);
|
||||
});
|
||||
|
||||
test('getPersistentPlugins, where the non persistent plugins getting excluded', () => {
|
||||
const state: PluginsState = {
|
||||
devicePlugins: new Map([
|
||||
[
|
||||
'DevicePlugin1',
|
||||
createMockFlipperPluginWithNoPersistedState('DevicePlugin1'),
|
||||
],
|
||||
[
|
||||
'DevicePlugin2',
|
||||
createMockFlipperPluginWithDefaultPersistedState('DevicePlugin2'),
|
||||
],
|
||||
]),
|
||||
clientPlugins: new Map([
|
||||
[
|
||||
'ClientPlugin1',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin1'),
|
||||
],
|
||||
[
|
||||
'ClientPlugin2',
|
||||
createMockFlipperPluginWithNoPersistedState('ClientPlugin2'),
|
||||
],
|
||||
]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: [],
|
||||
};
|
||||
const list = getPersistentPlugins(state);
|
||||
expect(list).toEqual(['ClientPlugin1', 'DevicePlugin2']);
|
||||
});
|
||||
|
||||
test('getActivePersistentPlugins, where the non persistent plugins getting excluded', () => {
|
||||
const state: PluginsState = {
|
||||
devicePlugins: new Map([
|
||||
[
|
||||
'DevicePlugin1',
|
||||
createMockFlipperPluginWithNoPersistedState('DevicePlugin1'),
|
||||
],
|
||||
[
|
||||
'DevicePlugin2',
|
||||
createMockFlipperPluginWithDefaultPersistedState('DevicePlugin2'),
|
||||
],
|
||||
]),
|
||||
clientPlugins: new Map([
|
||||
[
|
||||
'ClientPlugin1',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin1'),
|
||||
],
|
||||
[
|
||||
'ClientPlugin2',
|
||||
createMockFlipperPluginWithNoPersistedState('ClientPlugin2'),
|
||||
],
|
||||
]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: [],
|
||||
};
|
||||
const plugins: PluginStatesState = {
|
||||
'serial#app#DevicePlugin1': {msg: 'DevicePlugin1'},
|
||||
'serial#app#DevicePlugin2': {msg: 'DevicePlugin2'},
|
||||
'serial#app#ClientPlugin1': {msg: 'ClientPlugin1'},
|
||||
'serial#app#ClientPlugin2': {msg: 'ClientPlugin2'},
|
||||
};
|
||||
const queues: PluginMessageQueueState = {};
|
||||
const list = getActivePersistentPlugins(plugins, queues, state);
|
||||
expect(list).toEqual([
|
||||
{
|
||||
id: 'ClientPlugin1',
|
||||
label: 'ClientPlugin1',
|
||||
},
|
||||
{
|
||||
id: 'DevicePlugin2',
|
||||
label: 'DevicePlugin2',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('getActivePersistentPlugins, where the plugins not in pluginState or queue gets excluded', () => {
|
||||
const state: PluginsState = {
|
||||
devicePlugins: new Map([
|
||||
[
|
||||
'DevicePlugin1',
|
||||
createMockFlipperPluginWithDefaultPersistedState('DevicePlugin1'),
|
||||
],
|
||||
[
|
||||
'DevicePlugin2',
|
||||
createMockFlipperPluginWithDefaultPersistedState('DevicePlugin2'),
|
||||
],
|
||||
]),
|
||||
clientPlugins: new Map([
|
||||
[
|
||||
'ClientPlugin1',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin1'),
|
||||
],
|
||||
[
|
||||
'ClientPlugin2',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin2'),
|
||||
],
|
||||
[
|
||||
'ClientPlugin3',
|
||||
createMockFlipperPluginWithDefaultPersistedState('ClientPlugin3'),
|
||||
],
|
||||
]),
|
||||
gatekeepedPlugins: [],
|
||||
disabledPlugins: [],
|
||||
failedPlugins: [],
|
||||
selectedPlugins: [],
|
||||
};
|
||||
const plugins: PluginStatesState = {
|
||||
'serial#app#DevicePlugin1': {msg: 'DevicePlugin1'},
|
||||
'serial#app#ClientPlugin2': {msg: 'ClientPlugin2'},
|
||||
};
|
||||
const queues: PluginMessageQueueState = {
|
||||
'serial#app#ClientPlugin3': [
|
||||
{method: 'msg', params: {msg: 'ClientPlugin3'}},
|
||||
],
|
||||
};
|
||||
const list = getActivePersistentPlugins(plugins, queues, state);
|
||||
expect(list).toEqual([
|
||||
{
|
||||
id: 'ClientPlugin2',
|
||||
label: 'ClientPlugin2',
|
||||
},
|
||||
{
|
||||
id: 'ClientPlugin3',
|
||||
label: 'ClientPlugin3',
|
||||
},
|
||||
{
|
||||
id: 'DevicePlugin1',
|
||||
label: 'DevicePlugin1',
|
||||
},
|
||||
]);
|
||||
});
|
||||
50
desktop/app/src/utils/__tests__/processConfig.node.js
Normal file
50
desktop/app/src/utils/__tests__/processConfig.node.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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 {default as config, resetConfigForTesting} from '../processConfig.tsx';
|
||||
|
||||
afterEach(() => {
|
||||
resetConfigForTesting();
|
||||
});
|
||||
|
||||
test('config is decoded from env', () => {
|
||||
process.env.CONFIG = JSON.stringify({
|
||||
disabledPlugins: ['pluginA', 'pluginB', 'pluginC'],
|
||||
pluginPaths: ['/a/path', 'b/path'],
|
||||
lastWindowPosition: {x: 4, y: 8, width: 15, height: 16},
|
||||
launcherMsg: 'wubba lubba dub dub',
|
||||
updaterEnabled: false,
|
||||
screenCapturePath: '/my/screenshot/path',
|
||||
launcherEnabled: false,
|
||||
});
|
||||
|
||||
expect(config()).toEqual({
|
||||
disabledPlugins: new Set(['pluginA', 'pluginB', 'pluginC']),
|
||||
pluginPaths: ['/a/path', 'b/path'],
|
||||
lastWindowPosition: {x: 4, y: 8, width: 15, height: 16},
|
||||
launcherMsg: 'wubba lubba dub dub',
|
||||
updaterEnabled: false,
|
||||
screenCapturePath: '/my/screenshot/path',
|
||||
launcherEnabled: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('config is decoded from env with defaults', () => {
|
||||
process.env.CONFIG = '{}';
|
||||
|
||||
expect(config()).toEqual({
|
||||
disabledPlugins: new Set([]),
|
||||
pluginPaths: [],
|
||||
lastWindowPosition: undefined,
|
||||
launcherMsg: undefined,
|
||||
updaterEnabled: true,
|
||||
screenCapturePath: undefined,
|
||||
launcherEnabled: true,
|
||||
});
|
||||
});
|
||||
40
desktop/app/src/utils/__tests__/promiseTimeout.node.js
Normal file
40
desktop/app/src/utils/__tests__/promiseTimeout.node.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 promiseTimeout from '../promiseTimeout.tsx';
|
||||
|
||||
test('test promiseTimeout for timeout to happen', () => {
|
||||
const promise = promiseTimeout(
|
||||
200,
|
||||
new Promise((resolve, reject) => {
|
||||
const id = setTimeout(() => {
|
||||
clearTimeout(id);
|
||||
resolve();
|
||||
}, 500);
|
||||
return 'Executed';
|
||||
}),
|
||||
'Timed out',
|
||||
);
|
||||
return expect(promise).rejects.toThrow('Timed out');
|
||||
});
|
||||
|
||||
test('test promiseTimeout for timeout not to happen', () => {
|
||||
const promise = promiseTimeout(
|
||||
200,
|
||||
new Promise((resolve, reject) => {
|
||||
const id = setTimeout(() => {
|
||||
clearTimeout(id);
|
||||
resolve();
|
||||
}, 100);
|
||||
resolve('Executed');
|
||||
}),
|
||||
'Timed out',
|
||||
);
|
||||
return expect(promise).resolves.toBe('Executed');
|
||||
});
|
||||
336
desktop/app/src/utils/__tests__/serialization.node.js
Normal file
336
desktop/app/src/utils/__tests__/serialization.node.js
Normal file
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* 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 {makeObjectSerializable, deserializeObject} from '../serialization.tsx';
|
||||
|
||||
class TestObject extends Object {
|
||||
constructor(title: Object, map: ?Map<any, any>, set: ?Set<any>) {
|
||||
super();
|
||||
this.title = title;
|
||||
this.map = map;
|
||||
this.set = set;
|
||||
}
|
||||
title: Object;
|
||||
map: ?Map<any, any>;
|
||||
set: ?Set<any>;
|
||||
}
|
||||
test('test makeObjectSerializable function for unnested object with no Set and Map', async () => {
|
||||
const obj = {key1: 'value1', key2: 'value2'};
|
||||
const output = await makeObjectSerializable(obj);
|
||||
expect(output).toEqual(obj);
|
||||
|
||||
// Testing numbers
|
||||
const obj2 = {key1: 1, key2: 2};
|
||||
const output2 = await makeObjectSerializable(obj2);
|
||||
expect(output2).toEqual(obj2);
|
||||
});
|
||||
|
||||
test('makeObjectSerializable function for unnested object with values which returns false when put in an if condition', async () => {
|
||||
const obj2 = {key1: 0, key2: ''};
|
||||
const output2 = await makeObjectSerializable(obj2);
|
||||
return expect(output2).toEqual(obj2);
|
||||
});
|
||||
|
||||
test('test deserializeObject function for unnested object with no Set and Map', () => {
|
||||
const obj = {key1: 'value1', key2: 'value2'};
|
||||
const output = deserializeObject(obj);
|
||||
expect(output).toEqual(obj);
|
||||
|
||||
// Testing numbers
|
||||
const obj2 = {key1: 1, key2: 2};
|
||||
const output2 = deserializeObject(obj2);
|
||||
expect(output2).toEqual(obj2);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for nested object with no Set and Map', async () => {
|
||||
const subObj = {key1: 'value1', key2: 'value2'};
|
||||
const subObj2 = {key21: 'value21', key22: 'value22'};
|
||||
const obj = {key1: subObj, key2: subObj2};
|
||||
const output = await makeObjectSerializable(obj);
|
||||
expect(output).toEqual(obj);
|
||||
expect(deserializeObject(output)).toEqual(obj);
|
||||
|
||||
const subObjNum = {key1: 1, key2: 2};
|
||||
const subObjNum2 = {key21: 21, key22: 22};
|
||||
const obj2 = {key1: subObjNum, key2: subObjNum2};
|
||||
const output2 = await makeObjectSerializable(obj2);
|
||||
expect(output2).toEqual(obj2);
|
||||
expect(deserializeObject(output2)).toEqual(obj2);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for Map and Set with no nesting', async () => {
|
||||
const map = new Map([
|
||||
['k1', 'v1'],
|
||||
['k2', 'v2'],
|
||||
]);
|
||||
const output = await makeObjectSerializable(map);
|
||||
const expected = {
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['k1', 'v1'],
|
||||
['k2', 'v2'],
|
||||
],
|
||||
};
|
||||
expect(output).toEqual(expected);
|
||||
expect(deserializeObject(output)).toEqual(map);
|
||||
|
||||
const set = new Set([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]);
|
||||
const outputSet = await makeObjectSerializable(set);
|
||||
const expectedSet = {
|
||||
__flipper_object_type__: 'Set',
|
||||
data: [1, 2, 3, 4, 5, 6],
|
||||
};
|
||||
expect(outputSet).toEqual(expectedSet);
|
||||
expect(deserializeObject(outputSet)).toEqual(set);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for Map and Set with nesting', async () => {
|
||||
const map = new Map([
|
||||
[{title: 'k1'}, {title: 'v1'}],
|
||||
[{title: 'k2'}, {title: 'v2'}],
|
||||
]);
|
||||
const output = await makeObjectSerializable(map);
|
||||
const expected = {
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
[{title: 'k1'}, {title: 'v1'}],
|
||||
[{title: 'k2'}, {title: 'v2'}],
|
||||
],
|
||||
};
|
||||
expect(output).toEqual(expected);
|
||||
expect(deserializeObject(output)).toEqual(map);
|
||||
|
||||
const set = new Set([
|
||||
{title: '1'},
|
||||
{title: '2'},
|
||||
{title: '3'},
|
||||
{title: '4'},
|
||||
{title: '5'},
|
||||
{title: '6'},
|
||||
]);
|
||||
const outputSet = await makeObjectSerializable(set);
|
||||
const expectedSet = {
|
||||
__flipper_object_type__: 'Set',
|
||||
data: [
|
||||
{title: '1'},
|
||||
{title: '2'},
|
||||
{title: '3'},
|
||||
{title: '4'},
|
||||
{title: '5'},
|
||||
{title: '6'},
|
||||
],
|
||||
};
|
||||
expect(outputSet).toEqual(expectedSet);
|
||||
expect(deserializeObject(outputSet)).toEqual(set);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for custom Object', async () => {
|
||||
const obj = new TestObject('title');
|
||||
const output = await makeObjectSerializable(obj);
|
||||
expect(output).toEqual(obj);
|
||||
expect(deserializeObject(output)).toEqual(obj);
|
||||
|
||||
const nestedObj = new TestObject({title: 'nestedTitle'});
|
||||
const nestedoutput = await makeObjectSerializable(nestedObj);
|
||||
expect(nestedoutput).toEqual(nestedObj);
|
||||
expect(deserializeObject(nestedoutput)).toEqual(nestedObj);
|
||||
|
||||
const nestedObjWithMap = new TestObject(
|
||||
{title: 'nestedTitle'},
|
||||
new Map([
|
||||
['k1', 'v1'],
|
||||
['k2', 'v2'],
|
||||
]),
|
||||
);
|
||||
const nestedObjWithMapOutput = await makeObjectSerializable(nestedObjWithMap);
|
||||
const expectedNestedObjWithMapOutput = {
|
||||
title: {title: 'nestedTitle'},
|
||||
map: {
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['k1', 'v1'],
|
||||
['k2', 'v2'],
|
||||
],
|
||||
},
|
||||
set: undefined,
|
||||
};
|
||||
expect(nestedObjWithMapOutput).toEqual(expectedNestedObjWithMapOutput);
|
||||
expect(deserializeObject(nestedObjWithMapOutput)).toEqual(nestedObjWithMap);
|
||||
|
||||
const nestedObjWithMapSet = new TestObject(
|
||||
{title: 'nestedTitle'},
|
||||
new Map([
|
||||
['k1', 'v1'],
|
||||
['k2', 'v2'],
|
||||
]),
|
||||
new Set([
|
||||
{title: '1'},
|
||||
{title: '2'},
|
||||
{title: '3'},
|
||||
{title: '4'},
|
||||
{title: '5'},
|
||||
{title: '6'},
|
||||
]),
|
||||
);
|
||||
const nestedObjWithMapSetOutput = await makeObjectSerializable(
|
||||
nestedObjWithMapSet,
|
||||
);
|
||||
const expectedNestedObjWithMapSetOutput = {
|
||||
title: {title: 'nestedTitle'},
|
||||
map: {
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['k1', 'v1'],
|
||||
['k2', 'v2'],
|
||||
],
|
||||
},
|
||||
set: {
|
||||
__flipper_object_type__: 'Set',
|
||||
data: [
|
||||
{title: '1'},
|
||||
{title: '2'},
|
||||
{title: '3'},
|
||||
{title: '4'},
|
||||
{title: '5'},
|
||||
{title: '6'},
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(nestedObjWithMapSetOutput).toEqual(expectedNestedObjWithMapSetOutput);
|
||||
expect(deserializeObject(nestedObjWithMapSetOutput)).toEqual(
|
||||
nestedObjWithMapSet,
|
||||
);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for Array as input', async () => {
|
||||
const arr = [1, 2, 4, 5];
|
||||
const output = await makeObjectSerializable(arr);
|
||||
expect(output).toEqual(arr);
|
||||
expect(deserializeObject(output)).toEqual(arr);
|
||||
|
||||
const arrMap = [
|
||||
new Map([
|
||||
['a1', 'v1'],
|
||||
['a2', 'v2'],
|
||||
]),
|
||||
new Map([
|
||||
['b1', 'v1'],
|
||||
['b2', 'v2'],
|
||||
]),
|
||||
new Map([
|
||||
['c1', 'v1'],
|
||||
['c2', 'v2'],
|
||||
]),
|
||||
new Map([
|
||||
['d1', 'v1'],
|
||||
['d2', 'v2'],
|
||||
]),
|
||||
];
|
||||
|
||||
const expectedArr = [
|
||||
{
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['a1', 'v1'],
|
||||
['a2', 'v2'],
|
||||
],
|
||||
},
|
||||
{
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['b1', 'v1'],
|
||||
['b2', 'v2'],
|
||||
],
|
||||
},
|
||||
{
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['c1', 'v1'],
|
||||
['c2', 'v2'],
|
||||
],
|
||||
},
|
||||
{
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['d1', 'v1'],
|
||||
['d2', 'v2'],
|
||||
],
|
||||
},
|
||||
];
|
||||
const outputMap = await makeObjectSerializable(arrMap);
|
||||
expect(outputMap).toEqual(expectedArr);
|
||||
expect(deserializeObject(outputMap)).toEqual(arrMap);
|
||||
|
||||
const arrStr = ['first', 'second', 'third', 'fourth'];
|
||||
const outputStr = await makeObjectSerializable(arrStr);
|
||||
expect(outputStr).toEqual(arrStr);
|
||||
expect(deserializeObject(outputStr)).toEqual(arrStr);
|
||||
});
|
||||
|
||||
test('test serialize and deserializeObject function for non Object input', async () => {
|
||||
expect(await makeObjectSerializable('octopus')).toEqual('octopus');
|
||||
expect(deserializeObject(await makeObjectSerializable('octopus'))).toEqual(
|
||||
'octopus',
|
||||
);
|
||||
expect(await makeObjectSerializable(24567)).toEqual(24567);
|
||||
expect(deserializeObject(await makeObjectSerializable(24567))).toEqual(24567);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for Date input', async () => {
|
||||
const date = new Date('2019-02-15');
|
||||
const expectedDate = {
|
||||
__flipper_object_type__: 'Date',
|
||||
data: date.toString(),
|
||||
};
|
||||
expect(await makeObjectSerializable(date)).toEqual(expectedDate);
|
||||
expect(deserializeObject(await makeObjectSerializable(date))).toEqual(date);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for Map of Sets', async () => {
|
||||
const map = new Map([
|
||||
['k1', new Set([1, 2, 3, 4, 5, 6])],
|
||||
[new Set([1, 2]), new Map([['k3', 'v3']])],
|
||||
]);
|
||||
const expectedOutput = {
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['k1', {__flipper_object_type__: 'Set', data: [1, 2, 3, 4, 5, 6]}],
|
||||
[
|
||||
{__flipper_object_type__: 'Set', data: [1, 2]},
|
||||
{__flipper_object_type__: 'Map', data: [['k3', 'v3']]},
|
||||
],
|
||||
],
|
||||
};
|
||||
expect(await makeObjectSerializable(map)).toEqual(expectedOutput);
|
||||
expect(deserializeObject(await makeObjectSerializable(map))).toEqual(map);
|
||||
});
|
||||
|
||||
test('test makeObjectSerializable and deserializeObject function for Map, Dates and Set with complex nesting', async () => {
|
||||
const date1 = new Date('2019-02-15');
|
||||
const date2 = new Date('2019-02-16');
|
||||
const map = new Map([
|
||||
['k1', date1],
|
||||
['k2', new Set([date2])],
|
||||
]);
|
||||
const expectedOutput = {
|
||||
__flipper_object_type__: 'Map',
|
||||
data: [
|
||||
['k1', {__flipper_object_type__: 'Date', data: date1.toString()}],
|
||||
[
|
||||
'k2',
|
||||
{
|
||||
__flipper_object_type__: 'Set',
|
||||
data: [{__flipper_object_type__: 'Date', data: date2.toString()}],
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
expect(await makeObjectSerializable(map)).toEqual(expectedOutput);
|
||||
expect(deserializeObject(await makeObjectSerializable(map))).toEqual(map);
|
||||
});
|
||||
Reference in New Issue
Block a user