aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2017-05-18 13:05:15 +0200
committerGitHub <noreply@github.com>2017-05-18 13:05:15 +0200
commita9e002af18b82a6f476507a9ff03eebcc19f867c (patch)
tree943790e81a810d4fd2fb4fc185109aff0049823b
parent4b1cd76f3ea1255620ae8db3eb8ba3bb33840166 (diff)
parent4e4be8bd6854f8e5364049fa30e51e8ab0127e9b (diff)
downloadmitmproxy-a9e002af18b82a6f476507a9ff03eebcc19f867c.tar.gz
mitmproxy-a9e002af18b82a6f476507a9ff03eebcc19f867c.tar.bz2
mitmproxy-a9e002af18b82a6f476507a9ff03eebcc19f867c.zip
Merge pull request #2337 from MatthewShao/jest-dev
[WIP][web] Add tests for UI components
-rw-r--r--web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js102
-rw-r--r--web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap156
-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__/ducks/tutils.js27
7 files changed, 529 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..576838f4
--- /dev/null
+++ b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.js
@@ -0,0 +1,102 @@
+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 = new 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 = new TFlow()
+ imageFlow.response.headers = [['Content-Type', 'image/jpeg']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={imageFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // javascript
+ let jsFlow = new 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 = new TFlow()
+ cssFlow.response.headers = [['Content-Type', 'text/css']]
+ iconColumn = renderer.create(<Columns.IconColumn flow={cssFlow}/>)
+ tree = iconColumn.toJSON()
+ expect(tree).toMatchSnapshot()
+ // default
+ let fooFlow = new 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 = new 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..ec260e1e
--- /dev/null
+++ b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.js.snap
@@ -0,0 +1,156 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FlowColumns Components should render IconColumn 1`] = `
+<td
+ className="col-icon"
+>
+ <div
+ className="resource-icon resource-icon-document"
+ />
+</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-plain"
+ />
+</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 MethodColumn 1`] = `
+<td
+ className="col-method"
+>
+ GET
+</td>
+`;
+
+exports[`FlowColumns Components should render SizeColumn 1`] = `
+<td
+ className="col-size"
+>
+ 100b
+</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"
+>
+ 2min
+</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-repeat pull-right"
+ />
+ <i
+ className="fa fa-fw fa-exclamation pull-right"
+ />
+ http://undefined:undefinedundefined
+</td>
+`;
+
+exports[`FlowColumns Components should render pathColumn 2`] = `
+<td
+ className="col-path"
+>
+ <i
+ className="fa fa-fw fa-repeat pull-right"
+ />
+ <i
+ className="fa fa-fw fa-pause pull-right"
+ />
+ <i
+ className="fa fa-fw fa-times pull-right"
+ />
+ http://undefined:undefinedundefined
+</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__/ducks/tutils.js b/web/src/js/__tests__/ducks/tutils.js
index 6ae7f080..f140222d 100644
--- a/web/src/js/__tests__/ducks/tutils.js
+++ b/web/src/js/__tests__/ducks/tutils.js
@@ -7,3 +7,30 @@ export function createStore(parts) {
applyMiddleware(...[thunk])
)
}
+
+export function TFlow(intercepted=false, marked=false, modified=false) {
+ return {
+ intercepted ,
+ marked,
+ modified,
+ id: "foo",
+ request: {
+ scheme: 'http',
+ is_replay: true,
+ method: 'GET',
+ contentLength: 100
+ },
+ response: {
+ status_code: 200,
+ headers: [["Content-Type", 'text/html']],
+ timestamp_end: 200
+ },
+ error: {
+ msg: ''
+ },
+ server_conn: {
+ timestamp_start: 100
+ },
+ type: 'http'
+ }
+}