adding jest test setup

Summary:
Adds a test runner for jest test and adds three simple test cases:
- render the app
- start a server
- client connecting to the app

Test can be run using `yarn test`.

To make the test runner work, some changes needed to be made:
- remove the export of `init()` from `'flipper'`, because it was a cyclic dependency
- updating Button.js to the new ref-API

Reviewed By: jknoxville

Differential Revision: D10027078

fbshipit-source-id: 49107b0dd4dec666b92ecd841422fe7e6b3a7756
This commit is contained in:
Daniel Büchele
2018-09-28 06:31:48 -07:00
committed by Facebook Github Bot
parent af1ff7f039
commit a455520ecb
14 changed files with 2191 additions and 511 deletions

View File

@@ -15,7 +15,6 @@ import MainSidebar from './chrome/MainSidebar.js';
import BugReporterDialog from './chrome/BugReporterDialog.js';
import ErrorBar from './chrome/ErrorBar.js';
import PluginContainer from './PluginContainer.js';
import PluginManager from './chrome/PluginManager.js';
import {ipcRenderer} from 'electron';
import type Logger from './fb-stubs/Logger.js';
@@ -30,7 +29,7 @@ type Props = {
pluginManagerVisible: boolean,
selectedDevice: ?BaseDevice,
error: ?string,
toggleBugDialogVisible: (visible?: boolean) => void,
toggleBugDialogVisible: (visible?: boolean) => any,
};
export class App extends React.Component<Props> {
@@ -55,7 +54,9 @@ export class App extends React.Component<Props> {
{this.props.bugDialogVisible && (
<BugReporterDialog
bugReporter={this.props.bugReporter}
close={() => this.props.toggleBugDialogVisible(false)}
close={() => {
this.props.toggleBugDialogVisible(false);
}}
/>
)}
<FlexRow fill={true}>

40
src/__tests__/App.js Normal file
View File

@@ -0,0 +1,40 @@
/**
* 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 React from 'react';
import {App} from '../App.js';
import {Provider} from 'react-redux';
import renderer from 'react-test-renderer';
import reducers from '../reducers/index.js';
import configureStore from 'redux-mock-store';
import Logger from '../fb-stubs/Logger.js';
import BugReporter from '../fb-stubs/BugReporter.js';
// create redux store with initial state
const mockStore = configureStore([])(reducers(undefined, {type: 'INIT'}));
beforeEach(() => {});
test('Empty app state matches snapshot', () => {
const logger = new Logger();
const bugReporter = new BugReporter(logger);
const component = renderer.create(
<Provider store={mockStore}>
<App
logger={logger}
bugReporter={bugReporter}
leftSidebarVisible={false}
bugDialogVisible={false}
pluginManagerVisible={false}
selectedDevice={null}
toggleBugDialogVisible={() => {}}
error={null}
/>
</Provider>,
);
expect(component.toJSON()).toMatchSnapshot();
});

View File

@@ -0,0 +1,242 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Empty app state matches snapshot 1`] = `
<div
className="css-1si6n3e"
fill={true}
>
<div
className="toolbar css-1u64wvw"
>
<div
className="css-7nzs1f"
disabled={false}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
>
<div
className="css-at56xe"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=minus-circle&variant=filled&size=12&set=facebook_icons&density=1x"
/>
No device selected
</div>
<div
className="css-1ayt83l"
>
<div
className="css-1telx8z"
disabled={true}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Take Screenshot"
>
<div
className="css-11ecny9"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=camera&variant=filled&size=12&set=facebook_icons&density=1x"
/>
</div>
<div
className="css-1telx8z"
disabled={true}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Make Screen Recording"
>
<div
className="css-1qxark3"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=camcorder&variant=filled&size=12&set=facebook_icons&density=1x"
/>
</div>
</div>
<div
className="css-12zzrdt"
/>
<div
className="css-1xcv92o"
/>
<div
className="css-1lljw3m"
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Report Bug"
>
<div
className="css-1u10tgp"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=bug&variant=filled&size=12&set=facebook_icons&density=1x"
/>
</div>
<div
className="css-1ayt83l"
>
<div
className="css-19m5dks"
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Toggle Plugins"
>
<div
className="css-1pfn0zl"
color="#80a6f5"
size={20}
src="icons/sidebar_left.svg"
/>
</div>
<div
className="css-1telx8z"
disabled={true}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Toggle Details"
>
<div
className="css-13cmaba"
color="#acacac"
size={20}
src="icons/sidebar_right.svg"
/>
</div>
</div>
</div>
<div
className="css-9qtipk"
fill={true}
>
<div
className="css-1atbcdi"
>
<div
className="css-1hs1k35"
>
<img
className="css-1yl4k4p"
src="./icon.png"
/>
<span
className="css-p2pwny"
>
Welcome to Flipper
</span>
<span
className="css-1xkgddx"
>
Development Mode
</span>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-1wavjrl"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=rocket&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Using Flipper
</span>
<span
className="css-bcc6f5"
>
Learn how Flipper can help you debug your App
</span>
</div>
</div>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-1bmw9ne"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=magic-wand&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Create your own plugin
</span>
<span
className="css-bcc6f5"
>
Get started with these pointers
</span>
</div>
</div>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-nk9hkx"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=tools&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Add Flipper support to your app
</span>
<span
className="css-bcc6f5"
>
Get started with these pointers
</span>
</div>
</div>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-14xjmfa"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=posts&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Contributing and Feedback
</span>
<span
className="css-bcc6f5"
>
Report issues and help us improve Flipper
</span>
</div>
</div>
</div>
</div>
</div>
</div>
`;

46
src/__tests__/server.js Normal file
View File

@@ -0,0 +1,46 @@
/**
* 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 Client from '../Client';
import Server, {SECURE_PORT, INSECURE_PORT} from '../server.js';
import LogManager from '../fb-stubs/Logger';
let server;
beforeAll(() => {
server = new Server(new LogManager());
});
test('servers starting at ports', done => {
const serversToBeStarted = new Set([SECURE_PORT, INSECURE_PORT]);
server.addListener('listening', port => {
if (!serversToBeStarted.has(port)) {
throw Error(`unknown server started at port ${port}`);
} else {
serversToBeStarted.delete(port);
}
if (serversToBeStarted.size === 0) {
done();
}
});
});
test('Layout plugin is connecting', done => {
server.addListener('new-client', (client: Client) => {
if (client.plugins.indexOf('Inspector -') === -1) {
done.fail(new Error('Layout inspector plugin not found'));
} else {
done();
}
});
});
afterAll(() => {
server.close();
});

View File

@@ -28,5 +28,3 @@ export {default as DetailSidebar} from './chrome/DetailSidebar.js';
export {default as AndroidDevice} from './devices/AndroidDevice.js';
export {default as Device} from './devices/BaseDevice.js';
export {default as IOSDevice} from './devices/IOSDevice.js';
export {default as init} from './init.js';

View File

@@ -62,7 +62,7 @@ const AppFrame = () => (
</TooltipProvider>
);
export default function init() {
function init() {
// $FlowFixMe: this element exists!
ReactDOM.render(<AppFrame />, document.getElementById('root'));
// $FlowFixMe: service workers exist!
@@ -77,3 +77,6 @@ export default function init() {
})
.catch(console.error);
}
// make init function callable from outside
window.Flipper.init = init;

View File

@@ -30,7 +30,7 @@ export type Store = ReduxStore<
connections: DevicesState,
pluginStates: PluginsState,
},
ApplicationAction | DevicesAction | PluginsAction,
ApplicationAction | DevicesAction | PluginsAction | {|type: 'INIT'|},
>;
export default combineReducers({

View File

@@ -21,8 +21,8 @@ const invariant = require('invariant');
const tls = require('tls');
const net = require('net');
const SECURE_PORT = 8088;
const INSECURE_PORT = 8089;
export const SECURE_PORT = 8088;
export const INSECURE_PORT = 8089;
type RSocket = {|
fireAndForget(payload: {data: string}): void,
@@ -57,14 +57,6 @@ export default class Server extends EventEmitter {
((event: 'clients-change', callback: () => void) => void);
init() {
if (process.env.NODE_ENV === 'test') {
console.warn(
"rsocket server has not been started as we're in test mode",
'server',
);
return;
}
this.certificateProvider
.loadSecureServerConfig()
.then(
@@ -93,6 +85,7 @@ export default class Server extends EventEmitter {
} server started on port ${port}`,
'server',
);
server.emit('listening', port);
});
return transportServer;
};

View File

@@ -258,7 +258,7 @@ class Button extends React.Component<
active: false,
};
_ref: ?Element | ?Text;
_ref = React.createRef();
onMouseDown = () => this.setState({active: true});
onMouseUp = () => this.setState({active: false});
@@ -270,10 +270,14 @@ class Button extends React.Component<
if (this.props.dropdown) {
const menu = electron.remote.Menu.buildFromTemplate(this.props.dropdown);
const position = {};
if (this._ref != null && this._ref instanceof Element) {
const {left, bottom} = this._ref.getBoundingClientRect();
position.x = parseInt(left, 10);
position.y = parseInt(bottom + 6, 10);
const {current} = this._ref;
if (current) {
const node = findDOMNode(current);
if (node instanceof Element) {
const {left, bottom} = node.getBoundingClientRect();
position.x = parseInt(left, 10);
position.y = parseInt(bottom + 6, 10);
}
}
menu.popup({
window: electron.remote.getCurrentWindow(),
@@ -289,10 +293,6 @@ class Button extends React.Component<
}
};
setRef = (ref: ?React.ElementRef<any>) => {
this._ref = findDOMNode(ref);
};
render() {
const {
icon,
@@ -336,7 +336,7 @@ class Button extends React.Component<
return (
<StyledButton
{...props}
ref={this.setRef}
ref={this._ref}
windowIsFocused={windowIsFocused}
onClick={this.onClick}
onMouseDown={this.onMouseDown}