Enable search on layout2 for archived devices
Summary: Enables search on the imported layout data. The way search is implemented is that the Flipper app asks for the search results from the mobile clients. Since mobile client will not exist in the archived case, the search won't work. To solve this problem I added a proxy client which will get all the messages fired by the Layout Inspector and it will accordingly revert back with the responses. In the case of search, it will give back the search result tree for a particular query. Also added extensive tests for the proxy client Reviewed By: danielbuechele Differential Revision: D14281856 fbshipit-source-id: 651436084ebacd57f86e4fe9bb2036e7f666880c
This commit is contained in:
committed by
Facebook Github Bot
parent
44b7d4c6c3
commit
b65581262a
@@ -17,6 +17,7 @@ import {
|
||||
FlexRow,
|
||||
colors,
|
||||
styled,
|
||||
ArchivedDevice,
|
||||
} from 'flipper';
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
@@ -66,6 +67,7 @@ type Props = {|
|
||||
pluginKey: string,
|
||||
state: Object,
|
||||
}) => void,
|
||||
isArchivedDevice: boolean,
|
||||
|};
|
||||
|
||||
class PluginContainer extends PureComponent<Props> {
|
||||
@@ -91,20 +93,21 @@ class PluginContainer extends PureComponent<Props> {
|
||||
activePlugin,
|
||||
pluginKey,
|
||||
target,
|
||||
isArchivedDevice,
|
||||
} = this.props;
|
||||
|
||||
if (!activePlugin || !target) {
|
||||
return null;
|
||||
}
|
||||
const props: PluginProps<Object> = {
|
||||
key: pluginKey,
|
||||
logger: this.props.logger,
|
||||
persistedState: activePlugin.defaultPersistedState
|
||||
? {
|
||||
...activePlugin.defaultPersistedState,
|
||||
...pluginState,
|
||||
}
|
||||
: pluginState,
|
||||
persistedState:
|
||||
!isArchivedDevice && activePlugin.defaultPersistedState
|
||||
? {
|
||||
...activePlugin.defaultPersistedState,
|
||||
...pluginState,
|
||||
}
|
||||
: pluginState,
|
||||
setPersistedState: state => setPluginState({pluginKey, state}),
|
||||
target,
|
||||
deepLinkPayload: this.props.deepLinkPayload,
|
||||
@@ -125,8 +128,8 @@ class PluginContainer extends PureComponent<Props> {
|
||||
}
|
||||
},
|
||||
ref: this.refChanged,
|
||||
isArchivedDevice,
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Container key="plugin">
|
||||
@@ -180,6 +183,7 @@ export default connect<Props, OwnProps, _, _, _, _>(
|
||||
pluginKey = getPluginKey(target.id, activePlugin.id);
|
||||
}
|
||||
}
|
||||
const isArchivedDevice = selectedDevice instanceof ArchivedDevice;
|
||||
|
||||
return {
|
||||
pluginState: pluginStates[pluginKey],
|
||||
@@ -187,6 +191,7 @@ export default connect<Props, OwnProps, _, _, _, _>(
|
||||
target,
|
||||
deepLinkPayload,
|
||||
pluginKey,
|
||||
isArchivedDevice,
|
||||
};
|
||||
},
|
||||
// $FlowFixMe
|
||||
|
||||
@@ -40,6 +40,7 @@ export {createTablePlugin} from './createTablePlugin.js';
|
||||
export {default as DetailSidebar} from './chrome/DetailSidebar.js';
|
||||
|
||||
export {default as AndroidDevice} from './devices/AndroidDevice.js';
|
||||
export {default as ArchivedDevice} from './devices/ArchivedDevice.js';
|
||||
export {default as Device} from './devices/BaseDevice.js';
|
||||
export {default as IOSDevice} from './devices/IOSDevice.js';
|
||||
export type {OS} from './devices/BaseDevice.js';
|
||||
|
||||
@@ -28,12 +28,16 @@ export function callClient(
|
||||
return (method, params) => client.call(id, method, false, params);
|
||||
}
|
||||
|
||||
export type PluginClient = {|
|
||||
send: (method: string, params?: Object) => void,
|
||||
call: (method: string, params?: Object) => Promise<any>,
|
||||
subscribe: (method: string, callback: (params: any) => void) => void,
|
||||
supportsMethod: (method: string) => Promise<boolean>,
|
||||
|};
|
||||
export interface PluginClient {
|
||||
// eslint-disable-next-line
|
||||
send(method: string, params?: Object): void;
|
||||
// eslint-disable-next-line
|
||||
call(method: string, params?: Object): Promise<any>;
|
||||
// eslint-disable-next-line
|
||||
subscribe(method: string, callback: (params: any) => void): void;
|
||||
// eslint-disable-next-line
|
||||
supportsMethod(method: string): Promise<boolean>;
|
||||
}
|
||||
|
||||
type PluginTarget = BaseDevice | Client;
|
||||
|
||||
@@ -54,6 +58,7 @@ export type Props<T> = {
|
||||
target: PluginTarget,
|
||||
deepLinkPayload: ?string,
|
||||
selectPlugin: (pluginID: string, deepLinkPayload: ?string) => boolean,
|
||||
isArchivedDevice: boolean,
|
||||
};
|
||||
|
||||
export class FlipperBasePlugin<
|
||||
|
||||
169
src/plugins/layout/layout2/ProxyArchiveClient.js
Normal file
169
src/plugins/layout/layout2/ProxyArchiveClient.js
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {Element, ElementID} from 'flipper';
|
||||
import type {PersistedState} from './index';
|
||||
import type {SearchResultTree} from './Search';
|
||||
import {cloneDeep} from 'lodash';
|
||||
|
||||
const propsForPersistedState = (
|
||||
AXMode: boolean,
|
||||
): {ROOT: string, ELEMENTS: string, ELEMENT: string} => {
|
||||
return {
|
||||
ROOT: AXMode ? 'rootAXElement' : 'rootElement',
|
||||
ELEMENTS: AXMode ? 'AXelements' : 'elements',
|
||||
ELEMENT: AXMode ? 'axElement' : 'element',
|
||||
};
|
||||
};
|
||||
|
||||
function constructSearchResultTree(
|
||||
node: Element,
|
||||
isMatch: boolean,
|
||||
children: Array<SearchResultTree>,
|
||||
AXMode: boolean,
|
||||
): SearchResultTree {
|
||||
let searchResult = {
|
||||
id: node.id,
|
||||
isMatch,
|
||||
hasChildren: children.length > 0,
|
||||
children: children.length > 0 ? children : null,
|
||||
element: node,
|
||||
axElement: null,
|
||||
};
|
||||
searchResult[`${propsForPersistedState(AXMode).ELEMENT}`] = node;
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
function isMatch(element: Element, query: string): boolean {
|
||||
const nameMatch = element.name.toLowerCase().includes(query.toLowerCase());
|
||||
return nameMatch || element.id === query;
|
||||
}
|
||||
|
||||
export function searchNodes(
|
||||
node: Element,
|
||||
query: string,
|
||||
AXMode: boolean,
|
||||
state: PersistedState,
|
||||
): ?SearchResultTree {
|
||||
const elements = state[propsForPersistedState(AXMode).ELEMENTS];
|
||||
const children: Array<SearchResultTree> = [];
|
||||
const match = isMatch(node, query);
|
||||
|
||||
for (const childID of node.children) {
|
||||
const child = elements[childID];
|
||||
const tree = searchNodes(child, query, AXMode, state);
|
||||
if (tree) {
|
||||
children.push(tree);
|
||||
}
|
||||
}
|
||||
|
||||
if (match || children.length > 0) {
|
||||
return cloneDeep(constructSearchResultTree(node, match, children, AXMode));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class ProxyArchiveClient {
|
||||
constructor(persistedState: PersistedState) {
|
||||
this.persistedState = cloneDeep(persistedState);
|
||||
}
|
||||
persistedState: PersistedState;
|
||||
subscribe(method: string, callback: (params: any) => void): void {
|
||||
return;
|
||||
}
|
||||
|
||||
supportsMethod(method: string): Promise<boolean> {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
send(method: string, params?: Object): void {
|
||||
return;
|
||||
}
|
||||
|
||||
call(method: string, params?: Object): Promise<any> {
|
||||
const paramaters = params;
|
||||
switch (method) {
|
||||
case 'getRoot': {
|
||||
const {rootElement} = this.persistedState;
|
||||
if (!rootElement) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return Promise.resolve(this.persistedState.elements[rootElement]);
|
||||
}
|
||||
case 'getAXRoot': {
|
||||
const {rootAXElement} = this.persistedState;
|
||||
if (!rootAXElement) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return Promise.resolve(this.persistedState.AXelements[rootAXElement]);
|
||||
}
|
||||
case 'getNodes': {
|
||||
if (!paramaters) {
|
||||
return Promise.reject(new Error('Called getNodes with no params'));
|
||||
}
|
||||
const {ids} = paramaters;
|
||||
const arr: Array<Element> = [];
|
||||
for (let id: ElementID of ids) {
|
||||
arr.push(this.persistedState.elements[id]);
|
||||
}
|
||||
return Promise.resolve({elements: arr});
|
||||
}
|
||||
case 'getAXNodes': {
|
||||
if (!paramaters) {
|
||||
return Promise.reject(new Error('Called getAXNodes with no params'));
|
||||
}
|
||||
const {ids} = paramaters;
|
||||
const arr: Array<Element> = [];
|
||||
for (let id: ElementID of ids) {
|
||||
arr.push(this.persistedState.AXelements[id]);
|
||||
}
|
||||
return Promise.resolve({elements: arr});
|
||||
}
|
||||
case 'getSearchResults': {
|
||||
const {rootElement, rootAXElement} = this.persistedState;
|
||||
|
||||
if (!paramaters) {
|
||||
return Promise.reject(
|
||||
new Error('Called getSearchResults with no params'),
|
||||
);
|
||||
}
|
||||
const {query, axEnabled} = paramaters;
|
||||
if (!query) {
|
||||
return Promise.reject(
|
||||
new Error('query is not passed as a params to getSearchResults'),
|
||||
);
|
||||
}
|
||||
let element = {};
|
||||
if (axEnabled) {
|
||||
if (!rootAXElement) {
|
||||
return Promise.reject(new Error('rootAXElement is undefined'));
|
||||
}
|
||||
element = this.persistedState.AXelements[rootAXElement];
|
||||
} else {
|
||||
if (!rootElement) {
|
||||
return Promise.reject(new Error('rootElement is undefined'));
|
||||
}
|
||||
element = this.persistedState.elements[rootElement];
|
||||
}
|
||||
const output = searchNodes(
|
||||
element,
|
||||
query,
|
||||
axEnabled,
|
||||
this.persistedState,
|
||||
);
|
||||
return Promise.resolve({results: output, query});
|
||||
}
|
||||
case 'isConsoleEnabled': {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
default: {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default ProxyArchiveClient;
|
||||
@@ -18,13 +18,13 @@ import {
|
||||
} from 'flipper';
|
||||
import {Component} from 'react';
|
||||
|
||||
type SearchResultTree = {|
|
||||
export type SearchResultTree = {|
|
||||
id: string,
|
||||
isMatch: Boolean,
|
||||
isMatch: boolean,
|
||||
hasChildren: boolean,
|
||||
children: ?Array<SearchResultTree>,
|
||||
element: Element,
|
||||
axElement: Element,
|
||||
axElement: ?Element, // Not supported in iOS
|
||||
|};
|
||||
|
||||
type Props = {
|
||||
|
||||
414
src/plugins/layout/layout2/__tests__/ProxyArchiveClient.node.js
Normal file
414
src/plugins/layout/layout2/__tests__/ProxyArchiveClient.node.js
Normal file
@@ -0,0 +1,414 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* 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 ProxyArchiveClient,
|
||||
searchNodes,
|
||||
} from '../ProxyArchiveClient';
|
||||
import type {PersistedState} from '../index';
|
||||
import type {ElementID, Element} from 'flipper';
|
||||
import type {SearchResultTree} from '../Search';
|
||||
|
||||
function constructElement(
|
||||
id: string,
|
||||
name: string,
|
||||
children: Array<ElementID>,
|
||||
): Element {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
expanded: false,
|
||||
children,
|
||||
attributes: [],
|
||||
data: {},
|
||||
decoration: 'decoration',
|
||||
extraInfo: {},
|
||||
};
|
||||
}
|
||||
|
||||
function constructPersistedState(axMode: boolean): PersistedState {
|
||||
if (!axMode) {
|
||||
return {
|
||||
rootElement: 'root',
|
||||
rootAXElement: null,
|
||||
elements: {},
|
||||
AXelements: {},
|
||||
};
|
||||
}
|
||||
return {
|
||||
rootElement: null,
|
||||
rootAXElement: 'root',
|
||||
elements: {},
|
||||
AXelements: {},
|
||||
};
|
||||
}
|
||||
let state = constructPersistedState(false);
|
||||
|
||||
function populateChildren(state: PersistedState, axMode: boolean) {
|
||||
let elements = {};
|
||||
elements['root'] = constructElement('root', 'root view', [
|
||||
'child0',
|
||||
'child1',
|
||||
]);
|
||||
|
||||
elements['child0'] = constructElement('child0', 'child0 view', [
|
||||
'child0_child0',
|
||||
'child0_child1',
|
||||
]);
|
||||
elements['child1'] = constructElement('child1', 'child1 view', [
|
||||
'child1_child0',
|
||||
'child1_child1',
|
||||
]);
|
||||
elements['child0_child0'] = constructElement(
|
||||
'child0_child0',
|
||||
'child0_child0 view',
|
||||
[],
|
||||
);
|
||||
elements['child0_child1'] = constructElement(
|
||||
'child0_child1',
|
||||
'child0_child1 view',
|
||||
[],
|
||||
);
|
||||
elements['child1_child0'] = constructElement(
|
||||
'child1_child0',
|
||||
'child1_child0 view',
|
||||
[],
|
||||
);
|
||||
elements['child1_child1'] = constructElement(
|
||||
'child1_child1',
|
||||
'child1_child1 view',
|
||||
[],
|
||||
);
|
||||
if (axMode) {
|
||||
state.AXelements = elements;
|
||||
} else {
|
||||
state.elements = elements;
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
state = constructPersistedState(false);
|
||||
populateChildren(state, false);
|
||||
});
|
||||
|
||||
test('test the searchNode for root in axMode false', async () => {
|
||||
let searchResult: ?SearchResultTree = await searchNodes(
|
||||
state.elements['root'],
|
||||
'root',
|
||||
false,
|
||||
state,
|
||||
);
|
||||
expect(searchResult).toBeDefined();
|
||||
expect(searchResult).toEqual({
|
||||
id: 'root',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['root'],
|
||||
axElement: null,
|
||||
});
|
||||
});
|
||||
|
||||
test('test the searchNode for root in axMode true', async () => {
|
||||
state = constructPersistedState(true);
|
||||
populateChildren(state, true);
|
||||
let searchResult: ?SearchResultTree = await searchNodes(
|
||||
state.AXelements['root'],
|
||||
'RoOT',
|
||||
true,
|
||||
state,
|
||||
);
|
||||
expect(searchResult).toBeDefined();
|
||||
expect(searchResult).toEqual({
|
||||
id: 'root',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.AXelements['root'], // Even though AXElement exists, normal element will exist too
|
||||
axElement: state.AXelements['root'],
|
||||
});
|
||||
});
|
||||
|
||||
test('test the searchNode which matches just one child', async () => {
|
||||
let searchResult: ?SearchResultTree = await searchNodes(
|
||||
state.elements['root'],
|
||||
'child0_child0',
|
||||
false,
|
||||
state,
|
||||
);
|
||||
expect(searchResult).toBeDefined();
|
||||
expect(searchResult).toEqual({
|
||||
id: 'root',
|
||||
isMatch: false,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child0',
|
||||
isMatch: false,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child0_child0',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child0_child0'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['child0'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['root'],
|
||||
axElement: null,
|
||||
});
|
||||
});
|
||||
|
||||
test('test the searchNode for which matches multiple child', async () => {
|
||||
let searchResult: ?SearchResultTree = await searchNodes(
|
||||
state.elements['root'],
|
||||
'child0',
|
||||
false,
|
||||
state,
|
||||
);
|
||||
expect(searchResult).toBeDefined();
|
||||
let expectedSearchResult = {
|
||||
id: 'root',
|
||||
isMatch: false,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child0',
|
||||
isMatch: true,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child0_child0',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child0_child0'],
|
||||
axElement: null,
|
||||
},
|
||||
{
|
||||
id: 'child0_child1',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child0_child1'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['child0'],
|
||||
axElement: null,
|
||||
},
|
||||
{
|
||||
id: 'child1',
|
||||
isMatch: false,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child1_child0',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child1_child0'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['child1'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['root'],
|
||||
axElement: null,
|
||||
};
|
||||
expect(searchResult).toEqual(expectedSearchResult);
|
||||
});
|
||||
|
||||
test('test the searchNode, it should not be case sensitive', async () => {
|
||||
let searchResult: ?SearchResultTree = await searchNodes(
|
||||
state.elements['root'],
|
||||
'ChIlD0',
|
||||
false,
|
||||
state,
|
||||
);
|
||||
expect(searchResult).toBeDefined();
|
||||
let expectedSearchResult = {
|
||||
id: 'root',
|
||||
isMatch: false,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child0',
|
||||
isMatch: true,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child0_child0',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child0_child0'],
|
||||
axElement: null,
|
||||
},
|
||||
{
|
||||
id: 'child0_child1',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child0_child1'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['child0'],
|
||||
axElement: null,
|
||||
},
|
||||
{
|
||||
id: 'child1',
|
||||
isMatch: false,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{
|
||||
id: 'child1_child0',
|
||||
isMatch: true,
|
||||
hasChildren: false,
|
||||
children: null,
|
||||
element: state.elements['child1_child0'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['child1'],
|
||||
axElement: null,
|
||||
},
|
||||
],
|
||||
element: state.elements['root'],
|
||||
axElement: null,
|
||||
};
|
||||
expect(searchResult).toEqual(expectedSearchResult);
|
||||
});
|
||||
|
||||
test('test the searchNode for non existent query', async () => {
|
||||
let searchResult: ?SearchResultTree = await searchNodes(
|
||||
state.elements['root'],
|
||||
'Unknown query',
|
||||
false,
|
||||
state,
|
||||
);
|
||||
expect(searchResult).toBeNull();
|
||||
});
|
||||
|
||||
test('test the call method with getRoot', async () => {
|
||||
let proxyClient = new ProxyArchiveClient(state);
|
||||
let root: Element = await proxyClient.call('getRoot');
|
||||
expect(root).toEqual(state.elements['root']);
|
||||
});
|
||||
|
||||
test('test the call method with getAXRoot', async () => {
|
||||
state = constructPersistedState(true);
|
||||
populateChildren(state, true);
|
||||
let proxyClient = new ProxyArchiveClient(state);
|
||||
let root: Element = await proxyClient.call('getAXRoot');
|
||||
expect(root).toEqual(state.AXelements['root']);
|
||||
});
|
||||
|
||||
test('test the call method with getNodes', async () => {
|
||||
let proxyClient = new ProxyArchiveClient(state);
|
||||
let nodes: Array<Element> = await proxyClient.call('getNodes', {
|
||||
ids: ['child0_child1', 'child1_child0'],
|
||||
});
|
||||
expect(nodes).toEqual({
|
||||
elements: [
|
||||
{
|
||||
id: 'child0_child1',
|
||||
name: 'child0_child1 view',
|
||||
expanded: false,
|
||||
children: [],
|
||||
attributes: [],
|
||||
data: {},
|
||||
decoration: 'decoration',
|
||||
extraInfo: {},
|
||||
},
|
||||
{
|
||||
id: 'child1_child0',
|
||||
name: 'child1_child0 view',
|
||||
expanded: false,
|
||||
children: [],
|
||||
attributes: [],
|
||||
data: {},
|
||||
decoration: 'decoration',
|
||||
extraInfo: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('test the call method with getAXNodes', async () => {
|
||||
state = constructPersistedState(true);
|
||||
populateChildren(state, true);
|
||||
let proxyClient = new ProxyArchiveClient(state);
|
||||
let nodes: Array<Element> = await proxyClient.call('getAXNodes', {
|
||||
ids: ['child0_child1', 'child1_child0'],
|
||||
});
|
||||
expect(nodes).toEqual({
|
||||
elements: [
|
||||
{
|
||||
id: 'child0_child1',
|
||||
name: 'child0_child1 view',
|
||||
expanded: false,
|
||||
children: [],
|
||||
attributes: [],
|
||||
data: {},
|
||||
decoration: 'decoration',
|
||||
extraInfo: {},
|
||||
},
|
||||
{
|
||||
id: 'child1_child0',
|
||||
name: 'child1_child0 view',
|
||||
expanded: false,
|
||||
children: [],
|
||||
attributes: [],
|
||||
data: {},
|
||||
decoration: 'decoration',
|
||||
extraInfo: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('test different methods of calls with no params', async () => {
|
||||
let proxyClient = new ProxyArchiveClient(state);
|
||||
await expect(proxyClient.call('getNodes')).rejects.toThrow(
|
||||
new Error('Called getNodes with no params'),
|
||||
);
|
||||
await expect(proxyClient.call('getAXNodes')).rejects.toThrow(
|
||||
new Error('Called getAXNodes with no params'),
|
||||
);
|
||||
// let result: Error = await proxyClient.call('getSearchResults');
|
||||
await expect(proxyClient.call('getSearchResults')).rejects.toThrow(
|
||||
new Error('Called getSearchResults with no params'),
|
||||
);
|
||||
await expect(
|
||||
proxyClient.call('getSearchResults', {
|
||||
query: 'random',
|
||||
axEnabled: true,
|
||||
}),
|
||||
).rejects.toThrow(new Error('rootAXElement is undefined'));
|
||||
await expect(
|
||||
proxyClient.call('getSearchResults', {
|
||||
axEnabled: false,
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
new Error('query is not passed as a params to getSearchResults'),
|
||||
);
|
||||
});
|
||||
|
||||
test('test call method isConsoleEnabled', () => {
|
||||
let proxyClient = new ProxyArchiveClient(state);
|
||||
return expect(proxyClient.call('isConsoleEnabled')).resolves.toBe(false);
|
||||
});
|
||||
@@ -5,7 +5,13 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {ElementID, Element, ElementSearchResultSet, Store} from 'flipper';
|
||||
import type {
|
||||
ElementID,
|
||||
Element,
|
||||
ElementSearchResultSet,
|
||||
Store,
|
||||
PluginClient,
|
||||
} from 'flipper';
|
||||
|
||||
import {
|
||||
FlexColumn,
|
||||
@@ -22,6 +28,7 @@ import Inspector from './Inspector';
|
||||
import ToolbarIcon from './ToolbarIcon';
|
||||
import InspectorSidebar from './InspectorSidebar';
|
||||
import Search from './Search';
|
||||
import ProxyArchiveClient from './ProxyArchiveClient';
|
||||
|
||||
type State = {|
|
||||
init: boolean,
|
||||
@@ -115,6 +122,11 @@ export default class Layout extends FlipperPlugin<State, void, PersistedState> {
|
||||
this.setState({inAXMode: !this.state.inAXMode});
|
||||
};
|
||||
|
||||
getClient(): PluginClient {
|
||||
return this.props.isArchivedDevice
|
||||
? new ProxyArchiveClient(this.props.persistedState)
|
||||
: this.client;
|
||||
}
|
||||
onToggleAlignmentMode = () => {
|
||||
if (this.state.selectedElement) {
|
||||
this.client.send('setHighlighted', {
|
||||
@@ -139,7 +151,7 @@ export default class Layout extends FlipperPlugin<State, void, PersistedState> {
|
||||
|
||||
render() {
|
||||
const inspectorProps = {
|
||||
client: this.client,
|
||||
client: this.getClient(),
|
||||
inAlignmentMode: this.state.inAlignmentMode,
|
||||
selectedElement: this.state.selectedElement,
|
||||
selectedAXElement: this.state.selectedAXElement,
|
||||
@@ -192,7 +204,7 @@ export default class Layout extends FlipperPlugin<State, void, PersistedState> {
|
||||
active={this.state.inAlignmentMode}
|
||||
/>
|
||||
<Search
|
||||
client={this.client}
|
||||
client={this.getClient()}
|
||||
setPersistedState={this.props.setPersistedState}
|
||||
persistedState={this.props.persistedState}
|
||||
onSearchResults={searchResults =>
|
||||
@@ -223,7 +235,7 @@ export default class Layout extends FlipperPlugin<State, void, PersistedState> {
|
||||
</FlexRow>
|
||||
<DetailSidebar>
|
||||
<InspectorSidebar
|
||||
client={this.client}
|
||||
client={this.getClient()}
|
||||
realClient={this.realClient}
|
||||
element={element}
|
||||
onValueChanged={this.onDataValueChanged}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash.debounce": "^4.0.8"
|
||||
},
|
||||
"title": "Layout",
|
||||
|
||||
@@ -10,3 +10,8 @@ deep-equal@^1.0.1:
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
|
||||
lodash@^4.17.11:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
|
||||
Reference in New Issue
Block a user