aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2017-05-29 13:42:18 +0200
committerGitHub <noreply@github.com>2017-05-29 13:42:18 +0200
commitec7d7c995c0d8e93332b43699ad372f9555c9b75 (patch)
tree64bcd3790802e537da7d886ebae25e8ff5453d1a
parente7f7a608c6dda7cc22d2eda1129da99fd2830767 (diff)
parenta0ec6f58e960ba8f41929da971b3603af1c7e629 (diff)
downloadmitmproxy-ec7d7c995c0d8e93332b43699ad372f9555c9b75.tar.gz
mitmproxy-ec7d7c995c0d8e93332b43699ad372f9555c9b75.tar.bz2
mitmproxy-ec7d7c995c0d8e93332b43699ad372f9555c9b75.zip
Merge pull request #2348 from MatthewShao/jest-dev
[WIP][web] Add tests for js/components/Header
-rw-r--r--web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js5
-rw-r--r--web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.js55
-rw-r--r--web/src/js/__tests__/components/Header/FileMenuSpec.js45
-rw-r--r--web/src/js/__tests__/components/Header/FilterDocsSpec.js18
-rw-r--r--web/src/js/__tests__/components/Header/FilterInputSpec.js93
-rw-r--r--web/src/js/__tests__/components/Header/FlowMenuSpec.js102
-rw-r--r--web/src/js/__tests__/components/Header/MainMenuSpec.js26
-rw-r--r--web/src/js/__tests__/components/Header/MenuToggleSpec.js55
-rw-r--r--web/src/js/__tests__/components/Header/OptionMenuSpec.js19
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/ConnectionIndicatorSpec.js.snap50
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap86
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.js.snap7
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/FilterInputSpec.js.snap30
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap245
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/MainMenuSpec.js.snap86
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/MenuToggleSpec.js.snap50
-rw-r--r--web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap145
-rw-r--r--web/src/js/__tests__/ducks/tutils.js62
-rw-r--r--web/src/js/components/Header/ConnectionIndicator.jsx2
-rw-r--r--web/src/js/components/Header/FileMenu.jsx2
-rw-r--r--web/src/js/components/Header/FlowMenu.jsx2
-rw-r--r--web/src/js/components/Header/MainMenu.jsx6
22 files changed, 1183 insertions, 8 deletions
diff --git a/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js b/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js
index 51ff4ceb..3b7302f2 100644
--- a/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js
+++ b/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js
@@ -2,9 +2,8 @@ import React from 'react'
import renderer from 'react-test-renderer'
import ConnectedHead, { FlowTableHead } from '../../../components/FlowTable/FlowTableHead'
import { Provider } from 'react-redux'
-import configureStore from 'redux-mock-store'
+import { TStore } from '../../ducks/tutils'
-const mockStore = configureStore()
describe('FlowTableHead Component', () => {
let sortFn = jest.fn(),
@@ -21,7 +20,7 @@ describe('FlowTableHead Component', () => {
})
it('should connect to state', () => {
- let store = mockStore({ flows: {sort: {desc: true, column: 'PathColumn'}} }),
+ let store = TStore(),
provider = renderer.create(
<Provider store={store}>
<ConnectedHead/>
diff --git a/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.js b/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.js
new file mode 100644
index 00000000..45fcb5e4
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.js
@@ -0,0 +1,55 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import ConnectedIndicator, { ConnectionIndicator } from '../../../components/Header/ConnectionIndicator'
+import { ConnectionState } from '../../../ducks/connection'
+import { Provider } from 'react-redux'
+import { TStore } from '../../ducks/tutils'
+
+describe('ConnectionIndicator Component', () => {
+
+ it('should render INIT', () => {
+ let connectionIndicator = renderer.create(
+ <ConnectionIndicator state={ConnectionState.INIT}/>),
+ tree = connectionIndicator.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render FETCHING', () => {
+ let connectionIndicator = renderer.create(
+ <ConnectionIndicator state={ConnectionState.FETCHING}/>),
+ tree = connectionIndicator.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render ESTABLISHED', () => {
+ let connectionIndicator = renderer.create(
+ <ConnectionIndicator state={ConnectionState.ESTABLISHED}/>),
+ tree = connectionIndicator.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render ERROR', () => {
+ let connectionIndicator = renderer.create(
+ <ConnectionIndicator state={ConnectionState.ERROR} message="foo"/>),
+ tree = connectionIndicator.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render OFFLINE', () => {
+ let connectionIndicator = renderer.create(
+ <ConnectionIndicator state={ConnectionState.OFFLINE} />),
+ tree = connectionIndicator.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should connect to state', () => {
+ let store = TStore(),
+ provider = renderer.create(
+ <Provider store={store}>
+ <ConnectedIndicator/>
+ </Provider>),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
+
diff --git a/web/src/js/__tests__/components/Header/FileMenuSpec.js b/web/src/js/__tests__/components/Header/FileMenuSpec.js
new file mode 100644
index 00000000..65b4647a
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/FileMenuSpec.js
@@ -0,0 +1,45 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import { FileMenu } from '../../../components/Header/FileMenu'
+
+global.confirm = jest.fn( s => true )
+
+describe('FileMenu Component', () => {
+ let clearFn = jest.fn(),
+ loadFn = jest.fn(),
+ saveFn = jest.fn(),
+ mockEvent = {
+ preventDefault: jest.fn(),
+ target: { files: ["foo", "bar "] }
+ },
+ createNodeMock = () => { return { click: jest.fn() }},
+ fileMenu = renderer.create(
+ <FileMenu clearFlows={clearFn} loadFlows={loadFn} saveFlows={saveFn}/>, { createNodeMock }),
+ tree = fileMenu.toJSON()
+
+ it('should render correctly', () => {
+ expect(tree).toMatchSnapshot()
+ })
+
+ let ul = tree.children[1]
+
+ it('should clear flows', () => {
+ let a = ul.children[0].children[1]
+ a.props.onClick(mockEvent)
+ expect(mockEvent.preventDefault).toBeCalled()
+ expect(clearFn).toBeCalled()
+ })
+
+ it('should load flows', () => {
+ let fileChooser = ul.children[1].children[1],
+ input = fileChooser.children[2]
+ input.props.onChange(mockEvent)
+ expect(loadFn).toBeCalledWith("foo")
+ })
+
+ it('should save flows', () => {
+ let a = ul.children[2].children[1]
+ a.props.onClick(mockEvent)
+ expect(saveFn).toBeCalled()
+ })
+})
diff --git a/web/src/js/__tests__/components/Header/FilterDocsSpec.js b/web/src/js/__tests__/components/Header/FilterDocsSpec.js
new file mode 100644
index 00000000..321f9483
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/FilterDocsSpec.js
@@ -0,0 +1,18 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import FilterDocs from '../../../components/Header/FilterDocs'
+
+describe('FilterDocs Component', () => {
+ let mockResponse = { json:
+ () => { return { commands: [['cmd1', 'foo'], ['cmd2', 'bar']]}}
+ },
+ promise = Promise.resolve(mockResponse)
+ global.fetch = r => { return promise }
+
+ let filterDocs = renderer.create(<FilterDocs/>),
+ tree = filterDocs.toJSON()
+
+ it('should render correctly when fetch success', () => {
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/Header/FilterInputSpec.js b/web/src/js/__tests__/components/Header/FilterInputSpec.js
new file mode 100644
index 00000000..86193456
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/FilterInputSpec.js
@@ -0,0 +1,93 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import FilterInput from '../../../components/Header/FilterInput'
+import FilterDocs from '../../../components/Header/FilterDocs'
+import TestUtil from 'react-dom/test-utils'
+import ReactDOM from 'react-dom'
+import { Key } from '../../../utils'
+
+describe('FilterInput Component', () => {
+ it('should render correctly', () => {
+ let filterInput = renderer.create(<FilterInput type='foo' color='red' placeholder='bar'/>),
+ tree = filterInput.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ let filterInput = TestUtil.renderIntoDocument(
+ <FilterInput type='foo' color='red' placeholder='bar' value='' onChange={jest.fn()}/>)
+ it('should handle componentWillReceiveProps', () => {
+ filterInput.componentWillReceiveProps({value: 'foo'})
+ expect(filterInput.state.value).toEqual('foo')
+ })
+
+ it('should handle isValid', () => {
+ // valid
+ expect(filterInput.isValid("~u foo")).toBeTruthy()
+ expect(filterInput.isValid("~foo bar")).toBeFalsy()
+ })
+
+ it('should handle getDesc', () => {
+ filterInput.state.value = ''
+ expect(filterInput.getDesc().type).toEqual(FilterDocs)
+
+ filterInput.state.value = '~u foo'
+ expect(filterInput.getDesc()).toEqual('url matches /foo/i')
+
+ filterInput.state.value = '~foo bar'
+ expect(filterInput.getDesc()).toEqual('SyntaxError: Expected filter expression but \"~\" found.')
+ })
+
+ it('should handle change', () => {
+ let mockEvent = { target: { value: '~a bar'} }
+ filterInput.onChange(mockEvent)
+ expect(filterInput.state.value).toEqual('~a bar')
+ expect(filterInput.props.onChange).toBeCalledWith('~a bar')
+ })
+
+ it('should handle focus', () => {
+ filterInput.onFocus()
+ expect(filterInput.state.focus).toBeTruthy()
+ })
+
+ it('should handle blur', () => {
+ filterInput.onBlur()
+ expect(filterInput.state.focus).toBeFalsy()
+ })
+
+ it('should handle mouseEnter', () => {
+ filterInput.onMouseEnter()
+ expect(filterInput.state.mousefocus).toBeTruthy()
+ })
+
+ it('should handle mouseLeave', () => {
+ filterInput.onMouseLeave()
+ expect(filterInput.state.mousefocus).toBeFalsy()
+ })
+
+ let input = ReactDOM.findDOMNode(filterInput.refs.input)
+
+ it('should handle keyDown', () => {
+ input.blur = jest.fn()
+ let mockEvent = {
+ keyCode: Key.ESC,
+ stopPropagation: jest.fn()
+ }
+ filterInput.onKeyDown(mockEvent)
+ expect(input.blur).toBeCalled()
+ expect(filterInput.state.mousefocus).toBeFalsy()
+ expect(mockEvent.stopPropagation).toBeCalled()
+ })
+
+ it('should handle selectFilter', () => {
+ input.focus = jest.fn()
+ filterInput.selectFilter('bar')
+ expect(filterInput.state.value).toEqual('bar')
+ expect(input.focus).toBeCalled()
+ })
+
+ it('should handle select', () => {
+ input.select = jest.fn()
+ filterInput.select()
+ expect(input.select).toBeCalled()
+ })
+})
diff --git a/web/src/js/__tests__/components/Header/FlowMenuSpec.js b/web/src/js/__tests__/components/Header/FlowMenuSpec.js
new file mode 100644
index 00000000..1278d8ee
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/FlowMenuSpec.js
@@ -0,0 +1,102 @@
+jest.mock('../../../flow/utils')
+
+import React from 'react'
+import renderer from 'react-test-renderer'
+import ConnectedFlowMenu, { FlowMenu } from '../../../components/Header/FlowMenu'
+import { TFlow, TStore }from '../../ducks/tutils'
+import { MessageUtils } from "../../../flow/utils"
+import { Provider } from 'react-redux'
+
+
+describe('FlowMenu Component', () => {
+ let actions = {
+ resumeFlow: jest.fn(),
+ killFlow: jest.fn(),
+ replayFlow: jest.fn(),
+ duplicateFlow: jest.fn(),
+ removeFlow: jest.fn(),
+ revertFlow: jest.fn()
+ },
+ tflow = new TFlow()
+ tflow.modified = true
+ tflow.intercepted = true
+
+ it('should render correctly without flow', () => {
+ let flowMenu = renderer.create(
+ <FlowMenu removeFlow={actions.removeFlow}
+ killFlow={actions.killFlow}
+ replayFlow={actions.replayFlow}
+ duplicateFlow={actions.duplicateFlow}
+ resumeFlow={actions.resumeFlow}
+ revertFlow={actions.revertFlow}/>),
+ tree = flowMenu.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ let flowMenu = renderer.create(<FlowMenu
+ flow={tflow}
+ removeFlow={actions.removeFlow}
+ killFlow={actions.killFlow}
+ replayFlow={actions.replayFlow}
+ duplicateFlow={actions.duplicateFlow}
+ resumeFlow={actions.resumeFlow}
+ revertFlow={actions.revertFlow}/>),
+ tree = flowMenu.toJSON()
+
+ it('should render correctly with flow', () => {
+ expect(tree).toMatchSnapshot()
+ })
+
+ let menu_content_1 = tree.children[0].children[0]
+ it('should handle replayFlow', () => {
+ let button = menu_content_1.children[0]
+ button.props.onClick()
+ expect(actions.replayFlow).toBeCalledWith(tflow)
+ })
+
+ it('should handle duplicateFlow', () => {
+ let button = menu_content_1.children[1]
+ button.props.onClick()
+ expect(actions.duplicateFlow).toBeCalledWith(tflow)
+ })
+
+ it('should handle revertFlow', () => {
+ let button = menu_content_1.children[2]
+ button.props.onClick()
+ expect(actions.revertFlow).toBeCalledWith(tflow)
+ })
+
+ it('should handle removeFlow', () => {
+ let button = menu_content_1.children[3]
+ button.props.onClick()
+ expect(actions.removeFlow).toBeCalledWith(tflow)
+ })
+
+ let menu_content_2 = tree.children[1].children[0]
+ it('should handle download', () => {
+ let button = menu_content_2.children[0]
+ button.props.onClick()
+ expect(MessageUtils.getContentURL).toBeCalledWith(tflow, tflow.response)
+ })
+
+ let menu_content_3 = tree.children[2].children[0]
+ it('should handle resumeFlow', () => {
+ let button = menu_content_3.children[0]
+ button.props.onClick()
+ expect(actions.resumeFlow).toBeCalledWith(tflow)
+ })
+
+ it('should handle killFlow', () => {
+ let button = menu_content_3.children[1]
+ button.props.onClick()
+ expect(actions.killFlow).toBeCalledWith(tflow)
+ })
+
+ it('should connect to state', () => {
+ let store = TStore(),
+ provider = renderer.create(<Provider store={store}><ConnectedFlowMenu/></Provider>),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+})
diff --git a/web/src/js/__tests__/components/Header/MainMenuSpec.js b/web/src/js/__tests__/components/Header/MainMenuSpec.js
new file mode 100644
index 00000000..927166fd
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/MainMenuSpec.js
@@ -0,0 +1,26 @@
+jest.mock('../../../ducks/settings')
+
+import React from 'react'
+import renderer from 'react-test-renderer'
+import MainMenu, { setIntercept } from '../../../components/Header/MainMenu'
+import { Provider } from 'react-redux'
+import { update as updateSettings } from '../../../ducks/settings'
+import { TStore } from '../../ducks/tutils'
+
+describe('MainMenu Component', () => {
+ let store = TStore()
+
+ it('should render and connect to state', () => {
+ let provider = renderer.create(
+ <Provider store={store}>
+ <MainMenu/>
+ </Provider>),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle change on interceptInput', () => {
+ setIntercept('foo')
+ expect(updateSettings).toBeCalledWith({ intercept: 'foo' })
+ })
+})
diff --git a/web/src/js/__tests__/components/Header/MenuToggleSpec.js b/web/src/js/__tests__/components/Header/MenuToggleSpec.js
new file mode 100644
index 00000000..dabaaa4e
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/MenuToggleSpec.js
@@ -0,0 +1,55 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import { MenuToggle, SettingsToggle, EventlogToggle } from '../../../components/Header/MenuToggle'
+import { Provider } from 'react-redux'
+import { REQUEST_UPDATE } from '../../../ducks/settings'
+import { TStore } from '../../ducks/tutils'
+
+global.fetch = jest.fn()
+
+describe('MenuToggle Component', () => {
+ it('should render correctly', () => {
+ let changeFn = jest.fn(),
+ menuToggle = renderer.create(
+ <MenuToggle onChange={changeFn} value={true}>
+ <p>foo children</p>
+ </MenuToggle>),
+ tree = menuToggle.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
+
+describe('SettingToggle Component', () => {
+ let store = TStore(),
+ provider = renderer.create(
+ <Provider store={store}>
+ <SettingsToggle setting='anticache'>
+ <p>foo children</p>
+ </SettingsToggle>
+ </Provider>),
+ tree = provider.toJSON()
+
+ it('should render and connect to state', () => {
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle change', () => {
+ let menuToggle = tree.children[0].children[0]
+ menuToggle.props.onChange()
+ expect(store.getActions()).toEqual([{ type: REQUEST_UPDATE }])
+ })
+})
+
+describe('EventlogToggle Component', () => {
+ let store = TStore(),
+ changFn = jest.fn(),
+ provider = renderer.create(
+ <Provider store={store}>
+ <EventlogToggle value={false} onChange={changFn}/>
+ </Provider>
+ ),
+ tree = provider.toJSON()
+ it('should render and connect to state', () => {
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/Header/OptionMenuSpec.js b/web/src/js/__tests__/components/Header/OptionMenuSpec.js
new file mode 100644
index 00000000..b84fce6e
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/OptionMenuSpec.js
@@ -0,0 +1,19 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import { Provider } from 'react-redux'
+import OptionMenu from '../../../components/Header/OptionMenu'
+import { TStore } from '../../ducks/tutils'
+
+
+describe('OptionMenu Component', () => {
+ it('should render correctly', () => {
+ let store = TStore(),
+ provider = renderer.create(
+ <Provider store={store}>
+ <OptionMenu/>
+ </Provider>
+ ),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/ConnectionIndicatorSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/ConnectionIndicatorSpec.js.snap
new file mode 100644
index 00000000..817ba395
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/ConnectionIndicatorSpec.js.snap
@@ -0,0 +1,50 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ConnectionIndicator Component should connect to state 1`] = `
+<span
+ className="connection-indicator established"
+>
+ connected
+</span>
+`;
+
+exports[`ConnectionIndicator Component should render ERROR 1`] = `
+<span
+ className="connection-indicator error"
+ title="foo"
+>
+ connection lost
+</span>
+`;
+
+exports[`ConnectionIndicator Component should render ESTABLISHED 1`] = `
+<span
+ className="connection-indicator established"
+>
+ connected
+</span>
+`;
+
+exports[`ConnectionIndicator Component should render FETCHING 1`] = `
+<span
+ className="connection-indicator fetching"
+>
+ fetching data…
+</span>
+`;
+
+exports[`ConnectionIndicator Component should render INIT 1`] = `
+<span
+ className="connection-indicator init"
+>
+ connecting…
+</span>
+`;
+
+exports[`ConnectionIndicator Component should render OFFLINE 1`] = `
+<span
+ className="connection-indicator offline"
+>
+ offline
+</span>
+`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap
new file mode 100644
index 00000000..13ecf3f5
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/FileMenuSpec.js.snap
@@ -0,0 +1,86 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FileMenu Component should render correctly 1`] = `
+<div
+ className="dropdown pull-left"
+>
+ <a
+ className="special"
+ href="#"
+ onClick={[Function]}
+ >
+ mitmproxy
+ </a>
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="fa fa-fw fa-file"
+ />
+  New
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ className={undefined}
+ href="#"
+ onClick={[Function]}
+ title={undefined}
+ >
+ <i
+ className="fa fa-fw fa-folder-open"
+ />
+  Open...
+ <input
+ className="hidden"
+ onChange={[Function]}
+ type="file"
+ />
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="fa fa-fw fa-floppy-o"
+ />
+  Save...
+ </a>
+
+ </li>
+ <li>
+
+ <hr
+ className="divider"
+ />
+
+ </li>
+ <li>
+
+ <a
+ href="http://mitm.it/"
+ target="_blank"
+ >
+ <i
+ className="fa fa-fw fa-external-link"
+ />
+  Install Certificates...
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.js.snap
new file mode 100644
index 00000000..cd0c9dda
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.js.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FilterDocs Component should render correctly when fetch success 1`] = `
+<i
+ className="fa fa-spinner fa-spin"
+/>
+`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FilterInputSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/FilterInputSpec.js.snap
new file mode 100644
index 00000000..5afa8d7a
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/FilterInputSpec.js.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FilterInput Component should render correctly 1`] = `
+<div
+ className="filter-input input-group"
+>
+ <span
+ className="input-group-addon"
+ >
+ <i
+ className="fa fa-fw fa-foo"
+ style={
+ Object {
+ "color": "red",
+ }
+ }
+ />
+ </span>
+ <input
+ className="form-control"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ onKeyDown={[Function]}
+ placeholder="bar"
+ type="text"
+ value={undefined}
+ />
+</div>
+`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap
new file mode 100644
index 00000000..b0b28f1b
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/FlowMenuSpec.js.snap
@@ -0,0 +1,245 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FlowMenu Component should connect to state 1`] = `
+<div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="[r]eplay flow"
+ >
+ <i
+ className="fa fa-fw fa-repeat text-primary"
+ />
+ Replay
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="[D]uplicate flow"
+ >
+ <i
+ className="fa fa-fw fa-copy text-info"
+ />
+ Duplicate
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={true}
+ onClick={false}
+ title="revert changes to flow [V]"
+ >
+ <i
+ className="fa fa-fw fa-history text-warning"
+ />
+ Revert
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="[d]elete flow"
+ >
+ <i
+ className="fa fa-fw fa-trash text-danger"
+ />
+ Delete
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Flow Modification
+ </div>
+ </div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="download"
+ >
+ <i
+ className="fa fa-fw fa-download"
+ />
+ Download
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Export
+ </div>
+ </div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="btn btn-default"
+ disabled={true}
+ onClick={false}
+ title="[a]ccept intercepted flow"
+ >
+ <i
+ className="fa fa-fw fa-play text-success"
+ />
+ Resume
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={true}
+ onClick={false}
+ title="kill intercepted flow [x]"
+ >
+ <i
+ className="fa fa-fw fa-times text-danger"
+ />
+ Abort
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Interception
+ </div>
+ </div>
+</div>
+`;
+
+exports[`FlowMenu Component should render correctly with flow 1`] = `
+<div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="[r]eplay flow"
+ >
+ <i
+ className="fa fa-fw fa-repeat text-primary"
+ />
+ Replay
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="[D]uplicate flow"
+ >
+ <i
+ className="fa fa-fw fa-copy text-info"
+ />
+ Duplicate
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={false}
+ onClick={[Function]}
+ title="revert changes to flow [V]"
+ >
+ <i
+ className="fa fa-fw fa-history text-warning"
+ />
+ Revert
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="[d]elete flow"
+ >
+ <i
+ className="fa fa-fw fa-trash text-danger"
+ />
+ Delete
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Flow Modification
+ </div>
+ </div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="download"
+ >
+ <i
+ className="fa fa-fw fa-download"
+ />
+ Download
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Export
+ </div>
+ </div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="btn btn-default"
+ disabled={false}
+ onClick={[Function]}
+ title="[a]ccept intercepted flow"
+ >
+ <i
+ className="fa fa-fw fa-play text-success"
+ />
+ Resume
+ </div>
+ <div
+ className="btn btn-default"
+ disabled={false}
+ onClick={[Function]}
+ title="kill intercepted flow [x]"
+ >
+ <i
+ className="fa fa-fw fa-times text-danger"
+ />
+ Abort
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Interception
+ </div>
+ </div>
+</div>
+`;
+
+exports[`FlowMenu Component should render correctly without flow 1`] = `<div />`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/MainMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/MainMenuSpec.js.snap
new file mode 100644
index 00000000..b9735aa5
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/MainMenuSpec.js.snap
@@ -0,0 +1,86 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MainMenu Component should render and connect to state 1`] = `
+<div
+ className="menu-main"
+>
+ <div
+ className="filter-input input-group"
+ >
+ <span
+ className="input-group-addon"
+ >
+ <i
+ className="fa fa-fw fa-search"
+ style={
+ Object {
+ "color": "black",
+ }
+ }
+ />
+ </span>
+ <input
+ className="form-control"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ onKeyDown={[Function]}
+ placeholder="Search"
+ type="text"
+ value="~u foo"
+ />
+ </div>
+ <div
+ className="filter-input input-group"
+ >
+ <span
+ className="input-group-addon"
+ >
+ <i
+ className="fa fa-fw fa-tag"
+ style={
+ Object {
+ "color": "hsl(48, 100%, 50%)",
+ }
+ }
+ />
+ </span>
+ <input
+ className="form-control"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ onKeyDown={[Function]}
+ placeholder="Highlight"
+ type="text"
+ value="~a bar"
+ />
+ </div>
+ <div
+ className="filter-input input-group"
+ >
+ <span
+ className="input-group-addon"
+ >
+ <i
+ className="fa fa-fw fa-pause"
+ style={
+ Object {
+ "color": "hsl(208, 56%, 53%)",
+ }
+ }
+ />
+ </span>
+ <input
+ className="form-control"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ onKeyDown={[Function]}
+ placeholder="Intercept"
+ type="text"
+ value=""
+ />
+ </div>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/MenuToggleSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/MenuToggleSpec.js.snap
new file mode 100644
index 00000000..a0859081
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/MenuToggleSpec.js.snap
@@ -0,0 +1,50 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EventlogToggle Component should render and connect to state 1`] = `
+<div
+ className="menu-entry"
+>
+ <label>
+ <input
+ checked={true}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ Display Event Log
+ </label>
+</div>
+`;
+
+exports[`MenuToggle Component should render correctly 1`] = `
+<div
+ className="menu-entry"
+>
+ <label>
+ <input
+ checked={true}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ <p>
+ foo children
+ </p>
+ </label>
+</div>
+`;
+
+exports[`SettingToggle Component should render and connect to state 1`] = `
+<div
+ className="menu-entry"
+>
+ <label>
+ <input
+ checked={true}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ <p>
+ foo children
+ </p>
+ </label>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap b/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap
new file mode 100644
index 00000000..9299e69f
--- /dev/null
+++ b/web/src/js/__tests__/components/Header/__snapshots__/OptionMenuSpec.js.snap
@@ -0,0 +1,145 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`OptionMenu Component should render correctly 1`] = `
+<div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={false}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ HTTP/2.0
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={false}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ WebSockets
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={false}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ Raw TCP
+ </label>
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ Protocol Support
+ </div>
+ </div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={true}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ Disable Caching
+ <a
+ href="http://docs.mitmproxy.org/en/stable/features/anticache.html"
+ target="_blank"
+ >
+ <i
+ className="fa fa-question-circle"
+ />
+ </a>
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={false}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ Disable Compression
+ <i
+ className="fa fa-question-circle"
+ title="Do not forward Accept-Encoding headers to the server to force an uncompressed response."
+ />
+ </label>
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ HTTP Options
+ </div>
+ </div>
+ <div
+ className="menu-group"
+ >
+ <div
+ className="menu-content"
+ >
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={false}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ Use Host Header
+ <i
+ className="fa fa-question-circle"
+ title="Use the Host header to construct URLs for display."
+ />
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ <input
+ checked={true}
+ onChange={[Function]}
+ type="checkbox"
+ />
+ Display Event Log
+ </label>
+ </div>
+ </div>
+ <div
+ className="menu-legend"
+ >
+ View Options
+ </div>
+ </div>
+</div>
+`;
diff --git a/web/src/js/__tests__/ducks/tutils.js b/web/src/js/__tests__/ducks/tutils.js
index 211b61e3..2a79ede0 100644
--- a/web/src/js/__tests__/ducks/tutils.js
+++ b/web/src/js/__tests__/ducks/tutils.js
@@ -1,5 +1,11 @@
+import React from 'react'
import { combineReducers, applyMiddleware, createStore as createReduxStore } from 'redux'
import thunk from 'redux-thunk'
+import configureStore from 'redux-mock-store'
+import { ConnectionState } from '../../ducks/connection'
+import TFlow from './_tflow'
+
+const mockStore = configureStore([thunk])
export function createStore(parts) {
return createReduxStore(
@@ -8,4 +14,58 @@ export function createStore(parts) {
)
}
-export { default as TFlow } from './_tflow'
+export { TFlow }
+
+export function TStore(){
+ let tflow = new TFlow()
+ return mockStore({
+ ui: {
+ flow: {
+ contentView: 'Auto',
+ displayLarge: false,
+ showFullContent: true,
+ maxContentLines: 10,
+ content: ['foo', 'bar'],
+ viewDescription: 'foo',
+ modifiedFlow: true,
+ tab: 'request'
+ },
+ header: {
+ tab: 'Start'
+ }
+ },
+ settings: {
+ contentViews: ['Auto', 'Raw', 'Text'],
+ anticache: true,
+ anticomp: false
+ },
+ flows: {
+ selected: ["d91165be-ca1f-4612-88a9-c0f8696f3e29"],
+ byId: {"d91165be-ca1f-4612-88a9-c0f8696f3e29": tflow},
+ filter: '~u foo',
+ highlight: '~a bar',
+ sort: {
+ desc: true,
+ column: 'PathColumn'
+ }
+ },
+ connection: {
+ state: ConnectionState.ESTABLISHED
+
+ },
+ eventLog: {
+ visible: true,
+ filters: {
+ debug: true,
+ info: true,
+ web: false,
+ warn: true,
+ error: true
+ },
+ view: [
+ { id: 1, level: 'info', message: 'foo' },
+ { id: 2, level: 'error', message: 'bar' }
+ ]
+ }
+ })
+}
diff --git a/web/src/js/components/Header/ConnectionIndicator.jsx b/web/src/js/components/Header/ConnectionIndicator.jsx
index 1ee42e25..bbf0dd81 100644
--- a/web/src/js/components/Header/ConnectionIndicator.jsx
+++ b/web/src/js/components/Header/ConnectionIndicator.jsx
@@ -9,7 +9,7 @@ ConnectionIndicator.propTypes = {
message: PropTypes.string,
}
-function ConnectionIndicator({ state, message }) {
+export function ConnectionIndicator({ state, message }) {
switch (state) {
case ConnectionState.INIT:
return <span className="connection-indicator init">connecting…</span>;
diff --git a/web/src/js/components/Header/FileMenu.jsx b/web/src/js/components/Header/FileMenu.jsx
index 1975d1cb..70fbb2c3 100644
--- a/web/src/js/components/Header/FileMenu.jsx
+++ b/web/src/js/components/Header/FileMenu.jsx
@@ -17,7 +17,7 @@ FileMenu.onNewClick = (e, clearFlows) => {
clearFlows()
}
-function FileMenu ({clearFlows, loadFlows, saveFlows}) {
+export function FileMenu ({clearFlows, loadFlows, saveFlows}) {
return (
<Dropdown className="pull-left" btnClass="special" text="mitmproxy">
<a href="#" onClick={e => FileMenu.onNewClick(e, clearFlows)}>
diff --git a/web/src/js/components/Header/FlowMenu.jsx b/web/src/js/components/Header/FlowMenu.jsx
index fb61baf1..8f104213 100644
--- a/web/src/js/components/Header/FlowMenu.jsx
+++ b/web/src/js/components/Header/FlowMenu.jsx
@@ -17,7 +17,7 @@ FlowMenu.propTypes = {
revertFlow: PropTypes.func.isRequired
}
-function FlowMenu({ flow, resumeFlow, killFlow, replayFlow, duplicateFlow, removeFlow, revertFlow }) {
+export function FlowMenu({ flow, resumeFlow, killFlow, replayFlow, duplicateFlow, removeFlow, revertFlow }) {
if (!flow)
return <div/>
return (
diff --git a/web/src/js/components/Header/MainMenu.jsx b/web/src/js/components/Header/MainMenu.jsx
index 465649d7..162ed0f5 100644
--- a/web/src/js/components/Header/MainMenu.jsx
+++ b/web/src/js/components/Header/MainMenu.jsx
@@ -17,6 +17,10 @@ export default function MainMenu() {
)
}
+export function setIntercept(intercept) {
+ updateSettings({ intercept })
+}
+
const InterceptInput = connect(
state => ({
value: state.settings.intercept || '',
@@ -24,7 +28,7 @@ const InterceptInput = connect(
type: 'pause',
color: 'hsl(208, 56%, 53%)'
}),
- { onChange: intercept => updateSettings({ intercept }) }
+ { onChange: setIntercept }
)(FilterInput);
const FlowFilterInput = connect(