aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/__tests__/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/js/__tests__/components')
-rw-r--r--web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js108
-rw-r--r--web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap160
-rw-r--r--web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js47
-rw-r--r--web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js155
-rw-r--r--web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap21
-rw-r--r--web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap21
-rw-r--r--web/src/js/__tests__/components/common/ButtonSpec.js26
-rw-r--r--web/src/js/__tests__/components/common/DocsLinkSpec.js17
-rw-r--r--web/src/js/__tests__/components/common/DropdownSpec.js38
-rw-r--r--web/src/js/__tests__/components/common/FileChooserSpec.js38
-rw-r--r--web/src/js/__tests__/components/common/SplitterSpec.js84
-rw-r--r--web/src/js/__tests__/components/common/ToggleButtonSpec.js26
-rw-r--r--web/src/js/__tests__/components/common/ToggleInputButtonSpec.js43
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap30
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.js.snap21
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/DropdownSpec.js.snap162
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/FileChooserSpec.js.snap19
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/SplitterSpec.js.snap12
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/ToggleButtonSpec.js.snap14
-rw-r--r--web/src/js/__tests__/components/common/__snapshots__/ToggleInputButtonSpec.js.snap31
-rw-r--r--web/src/js/__tests__/components/helpers/AutoScrollSpec.js41
-rw-r--r--web/src/js/__tests__/components/helpers/VirtualScrollSpec.js21
22 files changed, 1135 insertions, 0 deletions
diff --git a/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js
new file mode 100644
index 00000000..f3373c02
--- /dev/null
+++ b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js
@@ -0,0 +1,108 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import * as Columns from '../../../components/FlowTable/FlowColumns'
+import { TFlow } from '../../ducks/tutils'
+
+describe('FlowColumns Components', () => {
+
+ let tflow = TFlow()
+ it('should render TLSColumn', () => {
+ let tlsColumn = renderer.create(<Columns.TLSColumn flow={tflow}/>),
+ tree = tlsColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render IconColumn', () => {
+ let iconColumn = renderer.create(<Columns.IconColumn flow={tflow}/>),
+ tree = iconColumn.toJSON()
+ // plain
+ expect(tree).toMatchSnapshot()
+ // not modified
+ tflow.response.status_code = 304
+ iconColumn = renderer.create(<Columns.IconColumn flow={tflow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // redirect
+ tflow.response.status_code = 302
+ iconColumn = renderer.create(<Columns.IconColumn flow={tflow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // image
+ let imageFlow = TFlow()
+ imageFlow.response.headers = [['Content-Type', 'image/jpeg']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={imageFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // javascript
+ let jsFlow = TFlow()
+ jsFlow.response.headers = [['Content-Type', 'application/x-javascript']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={jsFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // css
+ let cssFlow = TFlow()
+ cssFlow.response.headers = [['Content-Type', 'text/css']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={cssFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // html
+ let htmlFlow = TFlow()
+ htmlFlow.response.headers = [['Content-Type', 'text/html']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={htmlFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // default
+ let fooFlow = TFlow()
+ fooFlow.response.headers = [['Content-Type', 'foo']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={fooFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // no response
+ tflow.response = null
+ iconColumn = renderer.create(<Columns.IconColumn flow={tflow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render pathColumn', () => {
+ let pathColumn = renderer.create(<Columns.PathColumn flow={tflow}/>),
+ tree = pathColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+
+ tflow.error.msg = 'Connection killed'
+ tflow.intercepted = true
+ pathColumn = renderer.create(<Columns.PathColumn flow={tflow}/>)
+ tree = pathColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render MethodColumn', () => {
+ let methodColumn =renderer.create(<Columns.MethodColumn flow={tflow}/>),
+ tree = methodColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render StatusColumn', () => {
+ let statusColumn = renderer.create(<Columns.StatusColumn flow={tflow}/>),
+ tree = statusColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render SizeColumn', () => {
+ tflow = TFlow()
+ let sizeColumn = renderer.create(<Columns.SizeColumn flow={tflow}/>),
+ tree = sizeColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should render TimeColumn', () => {
+ let timeColumn = renderer.create(<Columns.TimeColumn flow={tflow}/>),
+ tree = timeColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+
+ tflow.response = null
+ timeColumn = renderer.create(<Columns.TimeColumn flow={tflow}/>),
+ tree = timeColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap
new file mode 100644
index 00000000..d6946507
--- /dev/null
+++ b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap
@@ -0,0 +1,160 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FlowColumns Components should render IconColumn 1`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-plain"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 2`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-not-modified"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 3`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-redirect"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 4`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-image"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 5`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-js"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 6`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-css"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 7`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-document"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 8`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-plain"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render IconColumn 9`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-plain"
+ />
+</td>
+`;
+
+exports[`FlowColumns Components should render MethodColumn 1`] = `
+<td
+ className="col-method"
+>
+ GET
+</td>
+`;
+
+exports[`FlowColumns Components should render SizeColumn 1`] = `
+<td
+ className="col-size"
+>
+ 14b
+</td>
+`;
+
+exports[`FlowColumns Components should render StatusColumn 1`] = `
+<td
+ className="col-status"
+/>
+`;
+
+exports[`FlowColumns Components should render TLSColumn 1`] = `
+<td
+ className="col-tls col-tls-http"
+/>
+`;
+
+exports[`FlowColumns Components should render TimeColumn 1`] = `
+<td
+ className="col-time"
+>
+ 415381h
+</td>
+`;
+
+exports[`FlowColumns Components should render TimeColumn 2`] = `
+<td
+ className="col-time"
+>
+ ...
+</td>
+`;
+
+exports[`FlowColumns Components should render pathColumn 1`] = `
+<td
+ className="col-path"
+>
+ <i
+ className="fa fa-fw fa-exclamation pull-right"
+ />
+ http://address:22/path
+</td>
+`;
+
+exports[`FlowColumns Components should render pathColumn 2`] = `
+<td
+ className="col-path"
+>
+ <i
+ className="fa fa-fw fa-pause pull-right"
+ />
+ <i
+ className="fa fa-fw fa-times pull-right"
+ />
+ http://address:22/path
+</td>
+`;
diff --git a/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js b/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js
new file mode 100644
index 00000000..32dabe59
--- /dev/null
+++ b/web/src/js/__tests__/components/ValueEditor/ValidateEditorSpec.js
@@ -0,0 +1,47 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import TestUtils from 'react-dom/test-utils'
+import ValidateEditor from '../../../components/ValueEditor/ValidateEditor'
+
+describe('ValidateEditor Component', () => {
+ let validateFn = jest.fn( content => content.length == 3),
+ doneFn = jest.fn()
+
+ it('should render correctly', () => {
+ let validateEditor = renderer.create(
+ <ValidateEditor content="foo" onDone={doneFn} isValid={validateFn}/>
+ ),
+ tree = validateEditor.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ let validateEditor = TestUtils.renderIntoDocument(
+ <ValidateEditor content="foo" onDone={doneFn} isValid={validateFn}/>
+ )
+ it('should handle componentWillReceiveProps', () => {
+ let mockProps = {
+ isValid: s => s.length == 3,
+ content: "bar"
+ }
+ validateEditor.componentWillReceiveProps(mockProps)
+ expect(validateEditor.state.valid).toBeTruthy()
+ validateEditor.componentWillReceiveProps({...mockProps, content: "bars"})
+ expect(validateEditor.state.valid).toBeFalsy()
+
+ })
+
+ it('should handle input', () => {
+ validateEditor.onInput("foo bar")
+ expect(validateFn).toBeCalledWith("foo bar")
+ })
+
+ it('should handle done', () => {
+ // invalid
+ validateEditor.editor.reset = jest.fn()
+ validateEditor.onDone("foo bar")
+ expect(validateEditor.editor.reset).toBeCalled()
+ // valid
+ validateEditor.onDone("bar")
+ expect(doneFn).toBeCalledWith("bar")
+ })
+})
diff --git a/web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js b/web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js
new file mode 100644
index 00000000..f94a6acc
--- /dev/null
+++ b/web/src/js/__tests__/components/ValueEditor/ValueEditorSpec.js
@@ -0,0 +1,155 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import TestUtils from 'react-dom/test-utils'
+import ValueEditor from '../../../components/ValueEditor/ValueEditor'
+import { Key } from '../../../utils'
+
+describe('ValueEditor Component', () => {
+
+ let mockFn = jest.fn()
+ it ('should render correctly', () => {
+ let valueEditor = renderer.create(
+ <ValueEditor content="foo" onDone={mockFn}/>
+ ),
+ tree = valueEditor.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ let valueEditor = TestUtils.renderIntoDocument(
+ <ValueEditor content="<script>foo</script>" onDone={mockFn}/>
+ )
+ it('should handle this.blur', () => {
+ valueEditor.input.blur = jest.fn()
+ valueEditor.blur()
+ expect(valueEditor.input.blur).toHaveBeenCalled()
+ })
+
+ it('should handle reset', () => {
+ valueEditor.reset()
+ expect(valueEditor.input.innerHTML).toEqual(
+ "&lt;script&gt;foo&lt;/script&gt;"
+ )
+ })
+
+ it('should handle paste', () => {
+ let mockEvent = {
+ preventDefault: jest.fn(),
+ clipboardData: { getData: (t) => "foo content"}
+ }
+ document.execCommand = jest.fn()
+ valueEditor.onPaste(mockEvent)
+ expect(document.execCommand).toBeCalledWith('insertHTML', false, "foo content")
+ })
+
+ it('should handle mouseDown', () => {
+ window.addEventListener = jest.fn()
+ valueEditor.onMouseDown({})
+ expect(valueEditor._mouseDown).toBeTruthy()
+ expect(window.addEventListener).toBeCalledWith('mouseup', valueEditor.onMouseUp)
+ })
+
+ it('should handle mouseUp', () => {
+ window.removeEventListener = jest.fn()
+ valueEditor.onMouseUp()
+ expect(window.removeEventListener).toBeCalledWith('mouseup', valueEditor.onMouseUp)
+ })
+
+ it('should handle focus', () => {
+ let mockEvent = { clientX: 1, clientY: 2 },
+ mockSelection = {
+ rangeCount: 1,
+ getRangeAt: jest.fn( (index) => {return { selectNodeContents: jest.fn() }}),
+ removeAllRanges: jest.fn(),
+ addRange: jest.fn()
+ },
+ clearState = (v) => {
+ v._mouseDown = false
+ v._ignore_events = false
+ v.state.editable = false
+ }
+ window.getSelection = () => mockSelection
+
+ // return undefined when mouse down
+ valueEditor.onMouseDown()
+ expect(valueEditor.onFocus(mockEvent)).toEqual(undefined)
+ valueEditor.onMouseUp()
+
+ // sel.rangeCount > 0
+ valueEditor.onFocus(mockEvent)
+ expect(mockSelection.getRangeAt).toBeCalledWith(0)
+ expect(valueEditor.state.editable).toBeTruthy()
+ expect(mockSelection.removeAllRanges).toBeCalled()
+ expect(mockSelection.addRange).toBeCalled()
+ clearState(valueEditor)
+
+ // document.caretPositionFromPoint
+ mockSelection.rangeCount = 0
+ let mockRange = { setStart: jest.fn(), selectNodeContents: jest.fn() }
+
+ document.caretPositionFromPoint = jest.fn((x, y) => {
+ return { offsetNode: 0, offset: x + y}
+ })
+ document.createRange = jest.fn(() => mockRange)
+ valueEditor.onFocus(mockEvent)
+ expect(mockRange.setStart).toBeCalledWith(0, 3)
+ clearState(valueEditor)
+ document.caretPositionFromPoint = null
+
+ //document.caretRangeFromPoint
+ document.caretRangeFromPoint = jest.fn(() => mockRange)
+ valueEditor.onFocus(mockEvent)
+ expect(document.caretRangeFromPoint).toBeCalledWith(1, 2)
+ clearState(valueEditor)
+ document.caretRangeFromPoint = null
+
+ //else
+ valueEditor.onFocus(mockEvent)
+ expect(mockRange.selectNodeContents).toBeCalledWith(valueEditor.input)
+ clearState(valueEditor)
+ })
+
+ it('should handle click', () => {
+ valueEditor.onMouseUp = jest.fn()
+ valueEditor.onFocus = jest.fn()
+ valueEditor.onClick('foo')
+ expect(valueEditor.onMouseUp).toBeCalled()
+ expect(valueEditor.onFocus).toBeCalledWith('foo')
+ })
+
+ it('should handle blur', () => {
+ // return undefined
+ valueEditor._ignore_events = true
+ expect(valueEditor.onBlur({})).toEqual(undefined)
+ // else
+ valueEditor._ignore_events = false
+ valueEditor.onBlur({})
+ expect(valueEditor.state.editable).toBeFalsy()
+ expect(valueEditor.props.onDone).toBeCalledWith(valueEditor.input.textContent)
+ })
+
+ it('should handle key down', () => {
+ let mockKeyEvent = (keyCode, shiftKey=false) => {
+ return {
+ keyCode: keyCode,
+ shiftKey: shiftKey,
+ stopPropagation: jest.fn(),
+ preventDefault: jest.fn()
+ }
+ }
+ valueEditor.reset = jest.fn()
+ valueEditor.blur = jest.fn()
+ valueEditor.onKeyDown(mockKeyEvent(Key.ESC))
+ expect(valueEditor.reset).toBeCalled()
+ expect(valueEditor.blur).toBeCalled()
+ valueEditor.blur.mockReset()
+
+ valueEditor.onKeyDown(mockKeyEvent(Key.ENTER))
+ expect(valueEditor.blur).toBeCalled()
+
+ valueEditor.onKeyDown(mockKeyEvent(Key.SPACE))
+ })
+
+ it('should handle input', () => {
+ valueEditor.onInput()
+ })
+})
diff --git a/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap
new file mode 100644
index 00000000..96b9ce19
--- /dev/null
+++ b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValidateEditorSpec.js.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ValidateEditor Component should render correctly 1`] = `
+<div
+ className="inline-input editable has-success"
+ contentEditable={undefined}
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "foo",
+ }
+ }
+ onBlur={[Function]}
+ onClick={[Function]}
+ onFocus={[Function]}
+ onInput={[Function]}
+ onKeyDown={[Function]}
+ onMouseDown={[Function]}
+ onPaste={[Function]}
+ tabIndex={0}
+/>
+`;
diff --git a/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap
new file mode 100644
index 00000000..91e8ee84
--- /dev/null
+++ b/web/src/js/__tests__/components/ValueEditor/__snapshots__/ValueEditorSpec.js.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ValueEditor Component should render correctly 1`] = `
+<div
+ className="inline-input editable"
+ contentEditable={undefined}
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "foo",
+ }
+ }
+ onBlur={[Function]}
+ onClick={[Function]}
+ onFocus={[Function]}
+ onInput={[Function]}
+ onKeyDown={[Function]}
+ onMouseDown={[Function]}
+ onPaste={[Function]}
+ tabIndex={0}
+/>
+`;
diff --git a/web/src/js/__tests__/components/common/ButtonSpec.js b/web/src/js/__tests__/components/common/ButtonSpec.js
new file mode 100644
index 00000000..ea05ee6e
--- /dev/null
+++ b/web/src/js/__tests__/components/common/ButtonSpec.js
@@ -0,0 +1,26 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import Button from '../../../components/common/Button'
+
+describe('Button Component', () => {
+
+ it('should render correctly', () => {
+ let button = renderer.create(
+ <Button className="classname" onClick={() => "onclick"} title="title" icon="icon">
+ <a>foo</a>
+ </Button>
+ ),
+ tree = button.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should be able to be disabled', () => {
+ let button = renderer.create(
+ <Button className="classname" onClick={() => "onclick"} disabled="true" children="children">
+ <a>foo</a>
+ </Button>
+ ),
+ tree = button.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/common/DocsLinkSpec.js b/web/src/js/__tests__/components/common/DocsLinkSpec.js
new file mode 100644
index 00000000..effed1b7
--- /dev/null
+++ b/web/src/js/__tests__/components/common/DocsLinkSpec.js
@@ -0,0 +1,17 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import DocsLink from '../../../components/common/DocsLink'
+
+describe('DocsLink Component', () => {
+ it('should be able to be rendered with children nodes', () => {
+ let docsLink = renderer.create(<DocsLink children="foo" resource="bar"></DocsLink>),
+ tree = docsLink.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should be able to be rendered without children nodes', () => {
+ let docsLink = renderer.create(<DocsLink resource="bar"></DocsLink>),
+ tree = docsLink.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/common/DropdownSpec.js b/web/src/js/__tests__/components/common/DropdownSpec.js
new file mode 100644
index 00000000..c8c57ea6
--- /dev/null
+++ b/web/src/js/__tests__/components/common/DropdownSpec.js
@@ -0,0 +1,38 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import Dropdown, { Divider } from '../../../components/common/Dropdown'
+
+describe('Dropdown Component', () => {
+ let dropup = renderer.create(<Dropdown dropup btnClass="foo">
+ <a href="#">1</a>
+ <Divider/>
+ <a href="#">2</a>
+ </Dropdown>),
+ dropdown = renderer.create(<Dropdown btnClass="foo">
+ <a href="#">1</a>
+ <a href="#">2</a>
+ </Dropdown>)
+
+ it('should render correctly', () => {
+ let tree = dropup.toJSON()
+ expect(tree).toMatchSnapshot()
+
+ tree = dropdown.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle open/close action', () => {
+ document.body.addEventListener('click', ()=>{})
+ let tree = dropup.toJSON(),
+ e = { preventDefault: jest.fn() }
+ tree.children[0].props.onClick(e)
+ expect(tree).toMatchSnapshot()
+
+ // click action when the state is open
+ tree.children[0].props.onClick(e)
+
+ // close
+ document.body.click()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/common/FileChooserSpec.js b/web/src/js/__tests__/components/common/FileChooserSpec.js
new file mode 100644
index 00000000..7d031a38
--- /dev/null
+++ b/web/src/js/__tests__/components/common/FileChooserSpec.js
@@ -0,0 +1,38 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import FileChooser from '../../../components/common/FileChooser'
+
+describe('FileChooser Component', () => {
+ let openFileFunc = jest.fn(),
+ createNodeMock = () => { return { click: jest.fn() } },
+ fileChooser = renderer.create(
+ <FileChooser className="foo" title="bar" onOpenFile={ openFileFunc }/>
+ , { createNodeMock })
+ //[test refs with react-test-renderer](https://github.com/facebook/react/issues/7371)
+
+ it('should render correctly', () => {
+ let tree = fileChooser.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle click action', () => {
+ let tree = fileChooser.toJSON(),
+ mockEvent = {
+ preventDefault: jest.fn(),
+ target: {
+ files: [ "foo", "bar" ]
+ }
+ }
+ tree.children[1].props.onChange(mockEvent)
+ expect(openFileFunc).toBeCalledWith("foo")
+ tree.props.onClick()
+ // without files
+ mockEvent = {
+ ...mockEvent,
+ target: { files: [ ]}
+ }
+ openFileFunc.mockClear()
+ tree.children[1].props.onChange(mockEvent)
+ expect(openFileFunc).not.toBeCalled()
+ })
+})
diff --git a/web/src/js/__tests__/components/common/SplitterSpec.js b/web/src/js/__tests__/components/common/SplitterSpec.js
new file mode 100644
index 00000000..9ec48350
--- /dev/null
+++ b/web/src/js/__tests__/components/common/SplitterSpec.js
@@ -0,0 +1,84 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import renderer from 'react-test-renderer'
+import Splitter from '../../../components/common/Splitter'
+import TestUtils from 'react-dom/test-utils';
+
+describe('Splitter Component', () => {
+
+ it('should render correctly', () => {
+ let splitter = renderer.create(<Splitter></Splitter>),
+ tree = splitter.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ let splitter = TestUtils.renderIntoDocument(<Splitter></Splitter>),
+ dom = ReactDOM.findDOMNode(splitter),
+ previousElementSibling = {
+ offsetHeight: 0,
+ offsetWidth: 0,
+ style: {flex: ''}
+ },
+ nextElementSibling = {
+ style: {flex: ''}
+ }
+
+ it('should handle mouseDown ', () => {
+ window.addEventListener = jest.fn()
+ splitter.onMouseDown({ pageX: 1, pageY: 2})
+ expect(splitter.state.startX).toEqual(1)
+ expect(splitter.state.startY).toEqual(2)
+ expect(window.addEventListener).toBeCalledWith('mousemove', splitter.onMouseMove)
+ expect(window.addEventListener).toBeCalledWith('mouseup', splitter.onMouseUp)
+ expect(window.addEventListener).toBeCalledWith('dragend', splitter.onDragEnd)
+ })
+
+ it('should handle dragEnd', () => {
+ window.removeEventListener = jest.fn()
+ splitter.onDragEnd()
+ expect(dom.style.transform).toEqual('')
+ expect(window.removeEventListener).toBeCalledWith('dragend', splitter.onDragEnd)
+ expect(window.removeEventListener).toBeCalledWith('mouseup', splitter.onMouseUp)
+ expect(window.removeEventListener).toBeCalledWith('mousemove', splitter.onMouseMove)
+ })
+
+ it('should handle mouseUp', () => {
+
+ Object.defineProperty(dom, 'previousElementSibling', { value: previousElementSibling })
+ Object.defineProperty(dom, 'nextElementSibling', { value: nextElementSibling })
+ splitter.onMouseUp({ pageX: 3, pageY: 4 })
+ expect(splitter.state.applied).toBeTruthy()
+ expect(nextElementSibling.style.flex).toEqual('1 1 auto')
+ expect(previousElementSibling.style.flex).toEqual('0 0 2px')
+ })
+
+ it('should handle mouseMove', () => {
+ splitter.onMouseMove({pageX: 10, pageY: 10})
+ expect(dom.style.transform).toEqual("translate(9px, 0px)")
+
+ let splitterY = TestUtils.renderIntoDocument(<Splitter axis="y"></Splitter>)
+ splitterY.onMouseMove({pageX: 10, pageY: 10})
+ expect(ReactDOM.findDOMNode(splitterY).style.transform).toEqual("translate(0px, 10px)")
+ })
+
+ it('should handle resize', () => {
+ window.setTimeout = jest.fn((event, time) => event())
+ splitter.onResize()
+ expect(window.setTimeout).toHaveBeenCalled()
+ })
+
+ it('should handle componentWillUnmount', () => {
+ splitter.componentWillUnmount()
+ expect(previousElementSibling.style.flex).toEqual('')
+ expect(nextElementSibling.style.flex).toEqual('')
+ expect(splitter.state.applied).toBeTruthy()
+ })
+
+ it('should handle reset', () => {
+ splitter.reset(false)
+ expect(splitter.state.applied).toBeFalsy()
+
+ expect(splitter.reset(true)).toEqual(undefined)
+ })
+
+})
diff --git a/web/src/js/__tests__/components/common/ToggleButtonSpec.js b/web/src/js/__tests__/components/common/ToggleButtonSpec.js
new file mode 100644
index 00000000..2188da82
--- /dev/null
+++ b/web/src/js/__tests__/components/common/ToggleButtonSpec.js
@@ -0,0 +1,26 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import ToggleButton from '../../../components/common/ToggleButton'
+
+describe('ToggleButton Component', () => {
+ let mockFunc = jest.fn()
+
+ it('should render correctly', () => {
+ let checkedButton = renderer.create(
+ <ToggleButton checked={true} onToggle={mockFunc} text="foo">
+ text
+ </ToggleButton>),
+ tree = checkedButton.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle click action', () => {
+ let uncheckButton = renderer.create(
+ <ToggleButton checked={false} onToggle={mockFunc} text="foo">
+ text
+ </ToggleButton>),
+ tree = uncheckButton.toJSON()
+ tree.props.onClick()
+ expect(mockFunc).toBeCalled()
+ })
+})
diff --git a/web/src/js/__tests__/components/common/ToggleInputButtonSpec.js b/web/src/js/__tests__/components/common/ToggleInputButtonSpec.js
new file mode 100644
index 00000000..39e555cd
--- /dev/null
+++ b/web/src/js/__tests__/components/common/ToggleInputButtonSpec.js
@@ -0,0 +1,43 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import ToggleInputButton from '../../../components/common/ToggleInputButton'
+import { Key } from '../../../utils'
+
+describe('ToggleInputButton Component', () => {
+ let mockFunc = jest.fn(),
+ toggleInputButton = undefined,
+ tree = undefined
+
+ it('should render correctly', () => {
+ toggleInputButton = renderer.create(
+ <ToggleInputButton checked={true} name="foo" onToggleChanged={mockFunc}
+ placeholder="bar">text</ToggleInputButton>)
+ tree = toggleInputButton.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle keydown and click action', () => {
+ toggleInputButton = renderer.create(
+ <ToggleInputButton checked={false} name="foo" onToggleChanged={mockFunc}
+ placeholder="bar" txt="txt">text</ToggleInputButton>)
+ tree = toggleInputButton.toJSON()
+ let mockEvent = {
+ keyCode: Key.ENTER,
+ stopPropagation: jest.fn()
+ }
+
+ tree.children[1].props.onKeyDown(mockEvent)
+ expect(mockFunc).toBeCalledWith("txt")
+
+ tree.children[0].props.onClick()
+ expect(mockFunc).toBeCalledWith("txt")
+ })
+
+ it('should update state onChange', () => {
+ // trigger onChange
+ tree.children[1].props.onChange({ target: { value: "foo" }})
+ // update the tree
+ tree = toggleInputButton.toJSON()
+ expect(tree.children[1].props.value).toEqual("foo")
+ })
+})
diff --git a/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap
new file mode 100644
index 00000000..1d403b2d
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/ButtonSpec.js.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Button Component should be able to be disabled 1`] = `
+<div
+ className="classname btn btn-default"
+ disabled="true"
+ onClick={false}
+ title={undefined}
+>
+ <a>
+ foo
+ </a>
+</div>
+`;
+
+exports[`Button Component should render correctly 1`] = `
+<div
+ className="classname btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title="title"
+>
+ <i
+ className="fa fa-fw icon"
+ />
+ <a>
+ foo
+ </a>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.js.snap
new file mode 100644
index 00000000..d91b77f7
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.js.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DocsLink Component should be able to be rendered with children nodes 1`] = `
+<a
+ href="http://docs.mitmproxy.org/en/stable/bar"
+ target="_blank"
+>
+ foo
+</a>
+`;
+
+exports[`DocsLink Component should be able to be rendered without children nodes 1`] = `
+<a
+ href="http://docs.mitmproxy.org/en/stable/bar"
+ target="_blank"
+>
+ <i
+ className="fa fa-question-circle"
+ />
+</a>
+`;
diff --git a/web/src/js/__tests__/components/common/__snapshots__/DropdownSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/DropdownSpec.js.snap
new file mode 100644
index 00000000..57d4968d
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/DropdownSpec.js.snap
@@ -0,0 +1,162 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Dropdown Component should handle open/close action 1`] = `
+<div
+ className="dropup"
+>
+ <a
+ className="foo"
+ href="#"
+ onClick={[Function]}
+ />
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ >
+ 1
+ </a>
+
+ </li>
+ <li>
+
+ <hr
+ className="divider"
+ />
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ >
+ 2
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
+
+exports[`Dropdown Component should handle open/close action 2`] = `
+<div
+ className="dropup"
+>
+ <a
+ className="foo"
+ href="#"
+ onClick={[Function]}
+ />
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ >
+ 1
+ </a>
+
+ </li>
+ <li>
+
+ <hr
+ className="divider"
+ />
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ >
+ 2
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
+
+exports[`Dropdown Component should render correctly 1`] = `
+<div
+ className="dropup"
+>
+ <a
+ className="foo"
+ href="#"
+ onClick={[Function]}
+ />
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ >
+ 1
+ </a>
+
+ </li>
+ <li>
+
+ <hr
+ className="divider"
+ />
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ >
+ 2
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
+
+exports[`Dropdown Component should render correctly 2`] = `
+<div
+ className="dropdown"
+>
+ <a
+ className="foo"
+ href="#"
+ onClick={[Function]}
+ />
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ >
+ 1
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ >
+ 2
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/common/__snapshots__/FileChooserSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/FileChooserSpec.js.snap
new file mode 100644
index 00000000..5f0b3cf3
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/FileChooserSpec.js.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FileChooser Component should render correctly 1`] = `
+<a
+ className="foo"
+ href="#"
+ onClick={[Function]}
+ title="bar"
+>
+ <i
+ className="fa fa-fw undefined"
+ />
+ <input
+ className="hidden"
+ onChange={[Function]}
+ type="file"
+ />
+</a>
+`;
diff --git a/web/src/js/__tests__/components/common/__snapshots__/SplitterSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/SplitterSpec.js.snap
new file mode 100644
index 00000000..dd70ed7a
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/SplitterSpec.js.snap
@@ -0,0 +1,12 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Splitter Component should render correctly 1`] = `
+<div
+ className="splitter splitter-x"
+>
+ <div
+ draggable="true"
+ onMouseDown={[Function]}
+ />
+</div>
+`;
diff --git a/web/src/js/__tests__/components/common/__snapshots__/ToggleButtonSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/ToggleButtonSpec.js.snap
new file mode 100644
index 00000000..f468d39f
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/ToggleButtonSpec.js.snap
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ToggleButton Component should render correctly 1`] = `
+<div
+ className="btn btn-toggle btn-primary"
+ onClick={[Function]}
+>
+ <i
+ className="fa fa-fw fa-check-square-o"
+ />
+  
+ foo
+</div>
+`;
diff --git a/web/src/js/__tests__/components/common/__snapshots__/ToggleInputButtonSpec.js.snap b/web/src/js/__tests__/components/common/__snapshots__/ToggleInputButtonSpec.js.snap
new file mode 100644
index 00000000..b8d80177
--- /dev/null
+++ b/web/src/js/__tests__/components/common/__snapshots__/ToggleInputButtonSpec.js.snap
@@ -0,0 +1,31 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ToggleInputButton Component should render correctly 1`] = `
+<div
+ className="input-group toggle-input-btn"
+>
+ <span
+ className="input-group-btn"
+ onClick={[Function]}
+ >
+ <div
+ className="btn btn-primary"
+ >
+ <span
+ className="fa fa-check-square-o"
+ />
+  
+ foo
+ </div>
+ </span>
+ <input
+ className="form-control"
+ disabled={true}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder="bar"
+ type="text"
+ value=""
+ />
+</div>
+`;
diff --git a/web/src/js/__tests__/components/helpers/AutoScrollSpec.js b/web/src/js/__tests__/components/helpers/AutoScrollSpec.js
new file mode 100644
index 00000000..18a3d669
--- /dev/null
+++ b/web/src/js/__tests__/components/helpers/AutoScrollSpec.js
@@ -0,0 +1,41 @@
+import React from "react"
+import ReactDOM from "react-dom"
+import AutoScroll from '../../../components/helpers/AutoScroll'
+import { calcVScroll } from '../../../components/helpers/VirtualScroll'
+import TestUtils from 'react-dom/test-utils'
+
+describe('Autoscroll', () => {
+ let mockFn = jest.fn()
+ class tComponent extends React.Component {
+ constructor(props, context){
+ super(props, context)
+ this.state = { vScroll: calcVScroll() }
+ }
+
+ componentWillUpdate() {
+ mockFn("foo")
+ }
+
+ componentDidUpdate() {
+ mockFn("bar")
+ }
+
+ render() {
+ return (<p>foo</p>)
+ }
+ }
+
+ it('should update component', () => {
+ let Foo = AutoScroll(tComponent),
+ autoScroll = TestUtils.renderIntoDocument(<Foo></Foo>),
+ viewport = ReactDOM.findDOMNode(autoScroll)
+ viewport.scrollTop = 10
+ Object.defineProperty(viewport, "scrollHeight", { value: 10, writable: true })
+ autoScroll.componentWillUpdate()
+ expect(mockFn).toBeCalledWith("foo")
+
+ Object.defineProperty(viewport, "scrollHeight", { value: 0, writable: true })
+ autoScroll.componentDidUpdate()
+ expect(mockFn).toBeCalledWith("bar")
+ })
+})
diff --git a/web/src/js/__tests__/components/helpers/VirtualScrollSpec.js b/web/src/js/__tests__/components/helpers/VirtualScrollSpec.js
new file mode 100644
index 00000000..8081e90d
--- /dev/null
+++ b/web/src/js/__tests__/components/helpers/VirtualScrollSpec.js
@@ -0,0 +1,21 @@
+import { calcVScroll } from '../../../components/helpers/VirtualScroll'
+
+describe('VirtualScroll', () => {
+
+ it('should return default state without options', () => {
+ expect(calcVScroll()).toEqual({start: 0, end: 0, paddingTop: 0, paddingBottom: 0})
+ })
+
+ it('should calculate position without itemHeights', () => {
+ expect(calcVScroll({itemCount: 0, rowHeight: 32, viewportHeight: 400, viewportTop: 0})).toEqual({
+ start: 0, end: 0, paddingTop: 0, paddingBottom: 0
+ })
+ })
+
+ it('should calculate position with itemHeights', () => {
+ expect(calcVScroll({itemCount: 5, itemHeights: [100, 100, 100, 100, 100],
+ viewportHeight: 300, viewportTop: 0})).toEqual({
+ start: 0, end: 4, paddingTop: 0, paddingBottom: 100
+ })
+ })
+})